Skip to content
Snippets Groups Projects
Unverified Commit 717c0f97 authored by Jayesh Badwaik's avatar Jayesh Badwaik
Browse files

+ nola : add implementation of owning_ptr

parent 53bf87e4
Branches
No related tags found
No related merge requests found
Pipeline #140385 passed
// -------------------------------------------------------------------------------------------------
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: (C) 2022 Jayesh Badwaik <j.badwaik@fz-juelich.de>
// -------------------------------------------------------------------------------------------------
#ifndef NOLA_OWNING_PTR_HPP
#define NOLA_OWNING_PTR_HPP
#include <memory>
#include <type_traits>
#include <utility>
namespace nola {
template <typename T, typename Alloc = std::allocator<T>>
class owning_ptr {
private:
using internal_allocator = typename std::allocator_traits<Alloc>::template rebind_alloc<T>;
public:
using allocator_type = internal_allocator;
using element_type = T;
using pointer = typename std::allocator_traits<allocator_type>::pointer;
using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
public:
using reference = std::add_lvalue_reference_t<T>;
using const_reference = std::add_lvalue_reference_t<T const>;
public:
owning_ptr() = default;
owning_ptr(owning_ptr&&) noexcept = default;
auto operator=(owning_ptr&&) noexcept -> owning_ptr& = default;
~owning_ptr();
owning_ptr(pointer ptr, allocator_type const& alloc);
private:
owning_ptr(owning_ptr const&) = default;
auto operator=(owning_ptr const&) -> owning_ptr& = default;
public:
auto clone() const -> owning_ptr
requires std::copyable<T>;
template <typename OtherAlloc>
auto clone(OtherAlloc const& alloc) const -> owning_ptr<T, OtherAlloc>
requires std::copyable<T>;
public:
auto operator->() noexcept -> pointer { return value_; }
auto operator->() const noexcept -> const_pointer { return value_; }
auto operator*() noexcept(noexcept(*std::declval<pointer>())) -> reference { return *value_; }
auto operator*() const noexcept -> const_reference { return value_; }
auto get() noexcept -> pointer { return value_; }
auto get() const noexcept -> const_pointer { return value_; }
// NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
operator bool() const noexcept { return value_ != nullptr; }
auto release() noexcept -> pointer;
void reset(pointer ptr) noexcept;
void reset() noexcept;
private:
pointer value_ = nullptr;
internal_allocator alloc_;
};
template <typename T1, typename Alloc1, typename T2, typename Alloc>
auto operator==(owning_ptr<T1, Alloc1> const& lhs, owning_ptr<T2, Alloc> const& rhs) noexcept
-> bool;
template <typename T1, typename Alloc1, typename T2, typename Alloc>
auto operator<=>(owning_ptr<T1, Alloc1> const& lhs, owning_ptr<T2, Alloc> const& rhs) noexcept
-> std::strong_ordering;
template <typename T, typename Alloc, typename... Args>
auto allocate_owning(Alloc&& alloc, Args&&... args) -> owning_ptr<T, Alloc>;
template <typename T, typename... Args>
auto make_owning(Args&&... args) -> owning_ptr<T, std::allocator<T>>;
// -------------------------------------------------------------------------------------------------
// Implementation
// -------------------------------------------------------------------------------------------------
template <typename T, typename Alloc>
owning_ptr<T, Alloc>::~owning_ptr()
{
if (value_ != nullptr) {
std::allocator_traits<internal_allocator>::destroy(alloc_, value_);
std::allocator_traits<internal_allocator>::deallocate(alloc_, value_, 1);
}
}
template <typename T1, typename Alloc1, typename T2, typename Alloc>
auto operator==(owning_ptr<T1, Alloc1> const& lhs, owning_ptr<T2, Alloc> const& rhs) noexcept
-> bool
{
return lhs.get() == rhs.get();
}
template <typename T1, typename Alloc1, typename T2, typename Alloc>
auto operator<=>(owning_ptr<T1, Alloc1> const& lhs, owning_ptr<T2, Alloc> const& rhs) noexcept
-> std::strong_ordering
{
if (lhs.get() < rhs.get()) {
return std::strong_ordering::less;
}
if (lhs.get() > rhs.get()) {
return std::strong_ordering::greater;
}
return std::strong_ordering::equal;
}
template <typename T, typename Alloc>
auto owning_ptr<T, Alloc>::clone() const -> owning_ptr
requires std::copyable<T>
{
auto allocator = alloc_;
return clone(allocator);
}
template <typename T, typename Alloc>
template <typename OtherAlloc>
auto owning_ptr<T, Alloc>::clone(OtherAlloc const& alloc) const -> owning_ptr<T, OtherAlloc>
requires std::copyable<T>
{
using alloc_traits = std::allocator_traits<OtherAlloc>;
auto new_allocator = alloc;
auto ptr = alloc_traits::allocate(new_allocator, 1);
alloc_traits::construct(new_allocator, ptr, *value_);
return owning_ptr<T, OtherAlloc>(ptr, new_allocator);
}
template <typename T, typename Alloc>
void owning_ptr<T, Alloc>::reset(pointer ptr) noexcept
{
if (value_ != nullptr) {
std::allocator_traits<internal_allocator>::destroy(alloc_, value_);
std::allocator_traits<internal_allocator>::deallocate(alloc_, value_, 1);
}
value_ = ptr;
}
template <typename T, typename Alloc>
void owning_ptr<T, Alloc>::reset() noexcept
{
reset(nullptr);
}
template <typename T, typename Alloc>
auto owning_ptr<T, Alloc>::release() noexcept -> pointer
{
auto ptr = value_;
value_ = nullptr;
return ptr;
}
template <typename T, typename Alloc>
auto swap(owning_ptr<T, Alloc>& lhs, owning_ptr<T, Alloc>& rhs) noexcept -> void
{
using std::swap;
swap(lhs.value_, rhs.value_);
}
template <typename T, typename Alloc>
owning_ptr<T, Alloc>::owning_ptr(pointer ptr, allocator_type const& alloc)
: value_(ptr), alloc_(alloc)
{
}
template <typename T, typename Alloc, typename... Args>
auto allocate_owning(Alloc&& alloc, Args&&... args) -> owning_ptr<T, Alloc>
{
using alloc_traits = std::allocator_traits<Alloc>;
auto ptr = alloc_traits::allocate(alloc, 1);
alloc_traits::construct(alloc, ptr, std::forward<Args>(args)...);
return owning_ptr<T, Alloc>(ptr, alloc);
}
template <typename T, typename... Args>
auto make_owning(Args&&... args) -> owning_ptr<T, std::allocator<T>>
{
return allocate_owning<T, std::allocator<T>, Args...>(
std::allocator<T>(), std::forward<Args>(args)...);
}
} // namespace nola
#endif // NOLA_OWNING_PTR_HPP
// -------------------------------------------------------------------------------------------------
// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: (C) 2022 Jayesh Badwaik <j.badwaik@fz-juelich.de>
// -------------------------------------------------------------------------------------------------
#include <catch2/catch_template_test_macros.hpp>
#include <catch2/catch_test_macros.hpp>
#include <memory>
#include <nola/owning_ptr.hpp>
#include <testmol/compat/catch_main.hpp>
#include <type_traits>
TESTMOL_CATCH_MAIN("test/unit/nola/cpp/owning_ptr")
class S {
int i;
public:
S() = default;
explicit S(int a) : i(a) {}
auto get() const -> int { return i; }
};
TEST_CASE("01. owning_ptr construction", "[all]")
{
auto ptr = nola::make_owning<S>(3);
REQUIRE((*ptr).get() == 3);
auto new_ptr = ptr.clone();
REQUIRE((*new_ptr).get() == 3);
*new_ptr = S(5);
REQUIRE((*new_ptr).get() == 5);
REQUIRE((*ptr).get() == 3);
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment