diff --git a/src/cpp/include/nola/owning_ptr.hpp b/src/cpp/include/nola/owning_ptr.hpp index 6051bf4b4c63b6272582c1824cdde0c1ab29aec9..154d488851781cd253b72a19e78ac87687703067 100644 --- a/src/cpp/include/nola/owning_ptr.hpp +++ b/src/cpp/include/nola/owning_ptr.hpp @@ -35,6 +35,14 @@ public: owning_ptr(pointer ptr, allocator_type const& alloc); + template <typename U, typename OtherAlloc> + explicit owning_ptr(owning_ptr<U, OtherAlloc>&& other) noexcept + requires std::convertible_to<U*, T*>; + + template <typename U, typename OtherAlloc> + auto operator=(owning_ptr<U, OtherAlloc>&& other) noexcept -> owning_ptr& + requires std::convertible_to<U*, T*>; + private: owning_ptr(owning_ptr const&) = default; auto operator=(owning_ptr const&) -> owning_ptr& = default; @@ -65,6 +73,8 @@ public: void reset(pointer ptr) noexcept; void reset() noexcept; + auto get_allocator() const noexcept -> allocator_type { return alloc_; } + private: pointer value_ = nullptr; internal_allocator alloc_; @@ -97,6 +107,26 @@ owning_ptr<T, Alloc>::~owning_ptr() } } +template <typename T, typename Alloc> +template <typename U, typename OtherAlloc> +owning_ptr<T, Alloc>::owning_ptr(owning_ptr<U, OtherAlloc>&& other) noexcept + requires std::convertible_to<U*, T*> +: value_(other.release()), alloc_(std::move(other.get_allocator())) +{ +} + +template <typename T, typename Alloc> +template <typename U, typename OtherAlloc> +auto owning_ptr<T, Alloc>::operator=(owning_ptr<U, OtherAlloc>&& other) noexcept -> owning_ptr& + requires std::convertible_to<U*, T*> +{ + if (*this != other) { + value_ = other.release(); + alloc_ = std::move(other.get_allocator()); + } + return *this; +} + 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 diff --git a/test/unit/cpp/nola/owning_ptr.t.cpp b/test/unit/cpp/nola/owning_ptr.t.cpp index d316c20d53ec928518a8f35c86ba5f05afb31d6b..ac60f27ff6c9b8aad9ff1ef3c35a7bade1b8402a 100644 --- a/test/unit/cpp/nola/owning_ptr.t.cpp +++ b/test/unit/cpp/nola/owning_ptr.t.cpp @@ -22,6 +22,28 @@ public: auto get() const -> int { return i; } }; +class Base { +public: + Base() = default; + virtual auto get() const -> int = 0; + virtual ~Base() = default; + Base(Base const&) = default; + Base(Base&&) = default; + auto operator=(Base const&) -> Base& = default; + auto operator=(Base&&) -> Base& = default; +}; + +class Derived : public Base { +public: + Derived() = default; + auto get() const -> int override { return 3; } + ~Derived() override = default; + Derived(Derived const&) = default; + Derived(Derived&&) = default; + auto operator=(Derived const&) -> Derived& = default; + auto operator=(Derived&&) -> Derived& = default; +}; + TEST_CASE("01. owning_ptr construction", "[all]") { auto ptr = nola::make_owning<S>(3); @@ -34,3 +56,11 @@ TEST_CASE("01. owning_ptr construction", "[all]") REQUIRE((*new_ptr).get() == 5); REQUIRE((*ptr).get() == 3); } + +TEST_CASE("02. Test Construction of Derived") +{ + auto ptr = nola::make_owning<Derived>(); + REQUIRE(ptr->get() == 3); + + auto base_ptr = nola::owning_ptr<Base>(ptr.clone()); +}