diff options
author | Shauren <shauren.trinity@gmail.com> | 2024-03-13 17:04:26 +0100 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2024-03-13 17:04:26 +0100 |
commit | f690b693386ef44754fa4528f3c565d563ad9468 (patch) | |
tree | f36d87301c23a3dc54cc4655aa7314b74a054451 | |
parent | 6b255efb2dae561224b6ac1c02f4e6377ea39098 (diff) |
Core/Utils: unique_trackable_ptr improvements
* Added comparison operators
* Added type casting helper functions
-rw-r--r-- | src/common/Utilities/UniqueTrackablePtr.h | 252 | ||||
-rw-r--r-- | tests/common/UniqueTrackablePtr.cpp | 66 |
2 files changed, 301 insertions, 17 deletions
diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h index b315bbd6437..7b1d9c236db 100644 --- a/src/common/Utilities/UniqueTrackablePtr.h +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -18,12 +18,11 @@ #ifndef TRINITYCORE_UNIQUE_TRACKABLE_PTR_H #define TRINITYCORE_UNIQUE_TRACKABLE_PTR_H -#include "Define.h" #include <memory> namespace Trinity { -template <typename T, typename Deleter = std::default_delete<T>> +template <typename T> class unique_trackable_ptr; template <typename T> @@ -36,27 +35,32 @@ class unique_strong_ref_ptr; * \brief Specialized variant of std::shared_ptr that enforces unique ownership and/or std::unique_ptr with std::weak_ptr capabilities * Implementation has the same overhead as a std::shared_ptr, that is, a separate allocation for control block that holds use counters * \tparam T Type of held object - * \tparam Deleter Object deleter (defaults to std::default_delete<T>) */ -template <typename T, typename Deleter> +template <typename T> class unique_trackable_ptr { public: using element_type = T; using pointer = T*; - using deleter_type = Deleter; - unique_trackable_ptr() : _ptr(nullptr, deleter_type()) { } + unique_trackable_ptr() : _ptr() { } - explicit unique_trackable_ptr(pointer ptr) : _ptr(ptr, deleter_type()) { } + explicit unique_trackable_ptr(pointer ptr) + : _ptr(ptr) { } - explicit unique_trackable_ptr(pointer ptr, deleter_type deleter) : _ptr(ptr, std::move(deleter)) { } + template <typename Deleter, std::enable_if_t<std::conjunction_v<std::is_move_constructible<Deleter>, std::is_invocable<Deleter&, T*&>>, int> = 0> + explicit unique_trackable_ptr(pointer ptr, Deleter deleter) + : _ptr(ptr, std::move(deleter)) { } unique_trackable_ptr(unique_trackable_ptr const&) = delete; unique_trackable_ptr(unique_trackable_ptr&& other) noexcept : _ptr(std::move(other._ptr)) { } + template <typename T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> + unique_trackable_ptr(unique_trackable_ptr<T2>&& other) noexcept + : _ptr(std::move(other)._ptr) { } + unique_trackable_ptr& operator=(unique_trackable_ptr const&) = delete; unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept @@ -65,6 +69,13 @@ public: return *this; } + template <typename T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> + unique_trackable_ptr& operator=(unique_trackable_ptr<T2>&& other) noexcept + { + _ptr = std::move(other)._ptr; + return *this; + } + ~unique_trackable_ptr() = default; unique_trackable_ptr& operator=(std::nullptr_t) @@ -99,13 +110,27 @@ public: return static_cast<bool>(_ptr); } - void reset(pointer ptr = nullptr, deleter_type deleter = {}) + void reset() + { + _ptr.reset(); + } + + void reset(pointer ptr) + { + _ptr.reset(ptr); + } + + template <class Deleter, std::enable_if_t<std::conjunction_v<std::is_move_constructible<Deleter>, std::is_invocable<Deleter&, T*&>>, int> = 0> + void reset(pointer ptr, Deleter deleter) { _ptr.reset(ptr, std::move(deleter)); } private: template <typename T0> + friend class unique_trackable_ptr; + + template <typename T0> friend class unique_weak_ptr; template <typename T0, typename... Args> @@ -139,22 +164,36 @@ public: unique_weak_ptr() = default; - template<typename Deleter> - unique_weak_ptr(unique_trackable_ptr<T, Deleter> const& trackable) : _ptr(trackable._ptr) - { - } + unique_weak_ptr(unique_trackable_ptr<T> const& trackable) + : _ptr(trackable._ptr) { } unique_weak_ptr(unique_weak_ptr const& other) = default; + + template <typename T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> + unique_weak_ptr(unique_weak_ptr<T2> const& other) noexcept + : _ptr(other._ptr) { } + unique_weak_ptr(unique_weak_ptr&& other) noexcept = default; - template<typename Deleter> - unique_weak_ptr& operator=(unique_trackable_ptr<T, Deleter> const& trackable) + template <typename T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> + unique_weak_ptr(unique_weak_ptr<T2>&& other) noexcept + : _ptr(std::move(other)._ptr) { } + + unique_weak_ptr& operator=(unique_trackable_ptr<T> const& trackable) { _ptr = trackable._ptr; return *this; } unique_weak_ptr& operator=(unique_weak_ptr const& other) = default; + + template <typename T2, std::enable_if_t<std::is_convertible_v<T2*, T*>, int> = 0> + unique_weak_ptr& operator=(unique_weak_ptr<T2>&& other) + { + _ptr = std::move(other)._ptr; + return *this; + } + unique_weak_ptr& operator=(unique_weak_ptr&& other) noexcept = default; ~unique_weak_ptr() = default; @@ -176,6 +215,24 @@ public: } private: + template <typename T0> + friend class unique_weak_ptr; + + template <typename T0> + friend class unique_strong_ref_ptr; + + template <class To, class From> + friend unique_weak_ptr<To> static_pointer_cast(unique_weak_ptr<From> const& other); + + template <class To, class From> + friend unique_weak_ptr<To> const_pointer_cast(unique_weak_ptr<From> const& other); + + template <class To, class From> + friend unique_weak_ptr<To> reinterpret_pointer_cast(unique_weak_ptr<From> const& other); + + template <class To, class From> + friend unique_weak_ptr<To> dynamic_pointer_cast(unique_weak_ptr<From> const& other); + std::weak_ptr<element_type> _ptr; }; @@ -219,17 +276,72 @@ public: return static_cast<bool>(_ptr); } - friend std::strong_ordering operator<=>(unique_strong_ref_ptr const&, unique_strong_ref_ptr const&) = default; + operator unique_weak_ptr<T>() const + { + unique_weak_ptr<T> weak; + weak._ptr = _ptr; + return weak; + } private: template <typename T0> friend class unique_weak_ptr; + template <class To, class From> + friend unique_strong_ref_ptr<To> static_pointer_cast(unique_strong_ref_ptr<From> const& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> static_pointer_cast(unique_strong_ref_ptr<From>&& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> const_pointer_cast(unique_strong_ref_ptr<From> const& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> const_pointer_cast(unique_strong_ref_ptr<From>&& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> reinterpret_pointer_cast(unique_strong_ref_ptr<From> const& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> reinterpret_pointer_cast(unique_strong_ref_ptr<From>&& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> dynamic_pointer_cast(unique_strong_ref_ptr<From> const& other); + + template <class To, class From> + friend unique_strong_ref_ptr<To> dynamic_pointer_cast(unique_strong_ref_ptr<From>&& other); + unique_strong_ref_ptr(std::shared_ptr<element_type> ptr) : _ptr(std::move(ptr)) { } std::shared_ptr<element_type> _ptr; }; +// unique_trackable_ptr funcions + +template <typename T1, typename T2> +bool operator==(unique_trackable_ptr<T1> const& left, unique_trackable_ptr<T2> const& right) +{ + return left.get() == right.get(); +} + +template <typename T1, typename T2> +std::strong_ordering operator<=>(unique_trackable_ptr<T1> const& left, unique_trackable_ptr<T2> const& right) +{ + return left.get() <=> right.get(); +} + +template <typename T1> +bool operator==(unique_trackable_ptr<T1> const& left, std::nullptr_t) +{ + return left.get() == nullptr; +} + +template <typename T1> +std::strong_ordering operator<=>(unique_trackable_ptr<T1> const& left, std::nullptr_t) +{ + return left.get() <=> nullptr; +} + template <typename T, typename... Args> std::enable_if_t<!std::is_array_v<T>, unique_trackable_ptr<T>> make_unique_trackable(Args&&... args) { @@ -269,6 +381,114 @@ std::enable_if_t<std::is_bounded_array_v<T>, unique_trackable_ptr<T>> make_uniqu ptr._ptr = std::make_shared<T>(val); return ptr; } + +// unique_weak_ptr funcions + +template <class To, class From> +unique_weak_ptr<To> static_pointer_cast(unique_weak_ptr<From> const& other) +{ + unique_weak_ptr<To> to; + to._ptr = std::static_pointer_cast<To>(other._ptr.lock()); + return to; +} + +template <class To, class From> +unique_weak_ptr<To> const_pointer_cast(unique_weak_ptr<From> const& other) +{ + unique_weak_ptr<To> to; + to._ptr = std::const_pointer_cast<To>(other._ptr.lock()); + return to; +} + +template <class To, class From> +unique_weak_ptr<To> reinterpret_pointer_cast(unique_weak_ptr<From> const& other) +{ + unique_weak_ptr<To> to; + to._ptr = std::reinterpret_pointer_cast<To>(other._ptr.lock()); + return to; +} + +template <class To, class From> +unique_weak_ptr<To> dynamic_pointer_cast(unique_weak_ptr<From> const& other) +{ + unique_weak_ptr<To> to; + to._ptr = std::dynamic_pointer_cast<To>(other._ptr.lock()); + return to; +} + +// unique_strong_ref_ptr funcions + +template <typename T1, typename T2> +bool operator==(unique_strong_ref_ptr<T1> const& left, unique_strong_ref_ptr<T2> const& right) +{ + return left.get() == right.get(); +} + +template <typename T1, typename T2> +std::strong_ordering operator<=>(unique_strong_ref_ptr<T1> const& left, unique_strong_ref_ptr<T2> const& right) +{ + return left.get() <=> right.get(); +} + +template <typename T1> +bool operator==(unique_strong_ref_ptr<T1> const& left, std::nullptr_t) +{ + return left.get() == nullptr; +} + +template <typename T1> +std::strong_ordering operator<=>(unique_strong_ref_ptr<T1> const& left, std::nullptr_t) +{ + return left.get() <=> nullptr; +} + +template <class To, class From> +unique_strong_ref_ptr<To> static_pointer_cast(unique_strong_ref_ptr<From> const& other) +{ + return unique_strong_ref_ptr<To>(std::static_pointer_cast<To>(other._ptr)); +} + +template <class To, class From> +unique_strong_ref_ptr<To> static_pointer_cast(unique_strong_ref_ptr<From>&& other) +{ + return unique_strong_ref_ptr<To>(std::static_pointer_cast<To>(std::move(other._ptr))); +} + +template <class To, class From> +unique_strong_ref_ptr<To> const_pointer_cast(unique_strong_ref_ptr<From> const& other) +{ + return unique_strong_ref_ptr<To>(std::const_pointer_cast<To>(other._ptr)); +} + +template <class To, class From> +unique_strong_ref_ptr<To> const_pointer_cast(unique_strong_ref_ptr<From>&& other) +{ + return unique_strong_ref_ptr<To>(std::const_pointer_cast<To>(std::move(other._ptr))); +} + +template <class To, class From> +unique_strong_ref_ptr<To> reinterpret_pointer_cast(unique_strong_ref_ptr<From> const& other) +{ + return unique_strong_ref_ptr<To>(std::reinterpret_pointer_cast<To>(other._ptr)); +} + +template <class To, class From> +unique_strong_ref_ptr<To> reinterpret_pointer_cast(unique_strong_ref_ptr<From>&& other) +{ + return unique_strong_ref_ptr<To>(std::reinterpret_pointer_cast<To>(std::move(other._ptr))); +} + +template <class To, class From> +unique_strong_ref_ptr<To> dynamic_pointer_cast(unique_strong_ref_ptr<From> const& other) +{ + return unique_strong_ref_ptr<To>(std::dynamic_pointer_cast<To>(other._ptr)); +} + +template <class To, class From> +unique_strong_ref_ptr<To> dynamic_pointer_cast(unique_strong_ref_ptr<From>&& other) +{ + return unique_strong_ref_ptr<To>(std::dynamic_pointer_cast<To>(std::move(other._ptr))); +} } #endif // TRINITYCORE_UNIQUE_TRACKABLE_PTR_H diff --git a/tests/common/UniqueTrackablePtr.cpp b/tests/common/UniqueTrackablePtr.cpp index 11fdb226ba5..3ab4cee1a55 100644 --- a/tests/common/UniqueTrackablePtr.cpp +++ b/tests/common/UniqueTrackablePtr.cpp @@ -23,7 +23,7 @@ struct TestObj { TestObj(bool* deleted = nullptr) : Deleted(deleted) { } - ~TestObj() + virtual ~TestObj() { if (Deleted) *Deleted = true; @@ -32,6 +32,21 @@ struct TestObj bool* Deleted = nullptr; }; +struct TestObj2 +{ + virtual ~TestObj2() = default; + + int a = 5; +}; + +struct TestObj3 : public TestObj2, public TestObj +{ +}; + +struct TestObj4 : public TestObj +{ +}; + TEST_CASE("Trinity::unique_trackable_ptr frees memory", "[UniqueTrackablePtr]") { bool deleted = false; @@ -88,3 +103,52 @@ TEST_CASE("Trinity::unique_weak_ptr", "[UniqueTrackablePtr]") REQUIRE(!!weakRef.lock()); } } + +TEST_CASE("Trinity::unique_strong_ref_ptr type casts", "[UniqueTrackablePtr]") +{ + Trinity::unique_trackable_ptr<TestObj> ptr = Trinity::make_unique_trackable<TestObj3>(); + + Trinity::unique_weak_ptr<TestObj> weak = ptr; + + Trinity::unique_strong_ref_ptr<TestObj> temp = weak.lock(); + REQUIRE(temp != nullptr); + + SECTION("static_pointer_cast") + { + Trinity::unique_strong_ref_ptr<TestObj3> testObj2 = Trinity::static_pointer_cast<TestObj3>(temp); + + REQUIRE(testObj2.get() == static_cast<TestObj3*>(ptr.get())); + + // sanity check that we didn't accidentally setup inheritance of TestObjs incorrectly + REQUIRE(testObj2.get() != reinterpret_cast<TestObj3*>(ptr.get())); + + REQUIRE(testObj2 == Trinity::static_pointer_cast<TestObj3>(weak).lock()); + } + + SECTION("reinterpret_pointer_cast") + { + Trinity::unique_strong_ref_ptr<TestObj3> testObj2 = Trinity::reinterpret_pointer_cast<TestObj3>(temp); + + REQUIRE(testObj2.get() == reinterpret_cast<TestObj3*>(ptr.get())); + + REQUIRE(testObj2 == Trinity::reinterpret_pointer_cast<TestObj3>(weak).lock()); + } + + SECTION("succeeding dynamic_pointer_cast") + { + Trinity::unique_strong_ref_ptr<TestObj3> testObj2 = Trinity::dynamic_pointer_cast<TestObj3>(temp); + + REQUIRE(testObj2.get() == dynamic_cast<TestObj3*>(ptr.get())); + + REQUIRE(testObj2 == Trinity::dynamic_pointer_cast<TestObj3>(weak).lock()); + } + + SECTION("failing dynamic_pointer_cast") + { + Trinity::unique_strong_ref_ptr<TestObj4> testObj2 = Trinity::dynamic_pointer_cast<TestObj4>(temp); + + REQUIRE(testObj2 == nullptr); + + REQUIRE(testObj2 == Trinity::dynamic_pointer_cast<TestObj4>(weak).lock()); + } +} |