/* * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program. If not, see . */ #ifndef TRINITYCORE_UNIQUE_TRACKABLE_PTR_H #define TRINITYCORE_UNIQUE_TRACKABLE_PTR_H #include namespace Trinity { template class unique_trackable_ptr; template class unique_weak_ptr; template 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 */ template class unique_trackable_ptr { public: using element_type = T; using pointer = T*; unique_trackable_ptr() : _ptr() { } explicit unique_trackable_ptr(pointer ptr) : _ptr(ptr) { } template , std::is_invocable>, 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 , int> = 0> unique_trackable_ptr(unique_trackable_ptr&& 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 { _ptr = std::move(other._ptr); return *this; } template , int> = 0> unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept { _ptr = std::move(other)._ptr; return *this; } ~unique_trackable_ptr() = default; unique_trackable_ptr& operator=(std::nullptr_t) { reset(); return *this; } void swap(unique_trackable_ptr& other) noexcept { using std::swap; swap(_ptr, other._ptr); } element_type& operator*() const { return *_ptr; } pointer operator->() const { return _ptr.operator->(); } pointer get() const { return _ptr.get(); } explicit operator bool() const { return static_cast(_ptr); } void reset() { _ptr.reset(); } void reset(pointer ptr) { _ptr.reset(ptr); } template , std::is_invocable>, int> = 0> void reset(pointer ptr, Deleter deleter) { _ptr.reset(ptr, std::move(deleter)); } private: template friend class unique_trackable_ptr; template friend class unique_weak_ptr; template friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(Args&&... args); template friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N); template friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N, std::remove_extent_t const& val); template friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(); template friend std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::remove_extent_t const& val); std::shared_ptr _ptr; }; /** * \brief Trinity::unique_trackable_ptr companion class, replicating what std::weak_ptr is to std::shared_ptr * \tparam T Type of held object */ template class unique_weak_ptr { public: using element_type = T; using pointer = T*; unique_weak_ptr() = default; unique_weak_ptr(unique_trackable_ptr const& trackable) : _ptr(trackable._ptr) { } unique_weak_ptr(unique_weak_ptr const& other) = default; template , int> = 0> unique_weak_ptr(unique_weak_ptr const& other) noexcept : _ptr(other._ptr) { } unique_weak_ptr(unique_weak_ptr&& other) noexcept = default; template , int> = 0> unique_weak_ptr(unique_weak_ptr&& other) noexcept : _ptr(std::move(other)._ptr) { } unique_weak_ptr& operator=(unique_trackable_ptr const& trackable) { _ptr = trackable._ptr; return *this; } unique_weak_ptr& operator=(unique_weak_ptr const& other) = default; template , int> = 0> unique_weak_ptr& operator=(unique_weak_ptr&& other) { _ptr = std::move(other)._ptr; return *this; } unique_weak_ptr& operator=(unique_weak_ptr&& other) noexcept = default; ~unique_weak_ptr() = default; unique_weak_ptr& operator=(std::nullptr_t) noexcept { _ptr.reset(); return *this; } void swap(unique_weak_ptr& other) noexcept { using std::swap; swap(_ptr, other._ptr); } bool expired() const { return _ptr.expired(); } unique_strong_ref_ptr lock() const { return unique_strong_ref_ptr(_ptr.lock()); } private: template friend class unique_weak_ptr; template friend class unique_strong_ref_ptr; template friend unique_weak_ptr static_pointer_cast(unique_weak_ptr const& other); template friend unique_weak_ptr const_pointer_cast(unique_weak_ptr const& other); template friend unique_weak_ptr reinterpret_pointer_cast(unique_weak_ptr const& other); template friend unique_weak_ptr dynamic_pointer_cast(unique_weak_ptr const& other); std::weak_ptr _ptr; }; /** * \brief Result of unique_weak_ptr::lock() function, this class holds a temporary strong reference to held object * to prevent it from being deallocated by another thread while it is being actively accessed. * This class is non-movable and non-copypable and is intended only for short lived local variables * \tparam T Type of held object */ template class unique_strong_ref_ptr { public: using element_type = T; using pointer = T*; unique_strong_ref_ptr(unique_strong_ref_ptr const&) = delete; unique_strong_ref_ptr(unique_strong_ref_ptr&&) = delete; unique_strong_ref_ptr& operator=(unique_strong_ref_ptr const&) = delete; unique_strong_ref_ptr& operator=(unique_strong_ref_ptr&&) = delete; ~unique_strong_ref_ptr() = default; element_type& operator*() const { return *_ptr; } pointer operator->() const { return _ptr.operator->(); } pointer get() const { return _ptr.get(); } explicit operator bool() const { return static_cast(_ptr); } operator unique_weak_ptr() const { unique_weak_ptr weak; weak._ptr = _ptr; return weak; } private: template friend class unique_weak_ptr; template friend unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr const& other); template friend unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr&& other); template friend unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr const& other); template friend unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr&& other); template friend unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr const& other); template friend unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr&& other); template friend unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr const& other); template friend unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr&& other); unique_strong_ref_ptr(std::shared_ptr ptr) : _ptr(std::move(ptr)) { } std::shared_ptr _ptr; }; // unique_trackable_ptr funcions template bool operator==(unique_trackable_ptr const& left, unique_trackable_ptr const& right) { return left.get() == right.get(); } template std::strong_ordering operator<=>(unique_trackable_ptr const& left, unique_trackable_ptr const& right) { return left.get() <=> right.get(); } template bool operator==(unique_trackable_ptr const& left, std::nullptr_t) { return left.get() == nullptr; } template std::strong_ordering operator<=>(unique_trackable_ptr const& left, std::nullptr_t) { return left.get() <=> nullptr; } template std::enable_if_t, unique_trackable_ptr> make_unique_trackable(Args&&... args) { unique_trackable_ptr ptr; ptr._ptr = std::make_shared(std::forward(args)...); return ptr; } template std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N) { unique_trackable_ptr ptr; ptr._ptr = std::make_shared(N); return ptr; } template std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::size_t N, std::remove_extent_t const& val) { unique_trackable_ptr ptr; ptr._ptr = std::make_shared(N, val); return ptr; } template std::enable_if_t, unique_trackable_ptr> make_unique_trackable() { unique_trackable_ptr ptr; ptr._ptr = std::make_shared(); return ptr; } template std::enable_if_t, unique_trackable_ptr> make_unique_trackable(std::remove_extent_t const& val) { unique_trackable_ptr ptr; ptr._ptr = std::make_shared(val); return ptr; } // unique_weak_ptr funcions template unique_weak_ptr static_pointer_cast(unique_weak_ptr const& other) { unique_weak_ptr to; to._ptr = std::static_pointer_cast(other._ptr.lock()); return to; } template unique_weak_ptr const_pointer_cast(unique_weak_ptr const& other) { unique_weak_ptr to; to._ptr = std::const_pointer_cast(other._ptr.lock()); return to; } template unique_weak_ptr reinterpret_pointer_cast(unique_weak_ptr const& other) { unique_weak_ptr to; to._ptr = std::reinterpret_pointer_cast(other._ptr.lock()); return to; } template unique_weak_ptr dynamic_pointer_cast(unique_weak_ptr const& other) { unique_weak_ptr to; to._ptr = std::dynamic_pointer_cast(other._ptr.lock()); return to; } // unique_strong_ref_ptr funcions template bool operator==(unique_strong_ref_ptr const& left, unique_strong_ref_ptr const& right) { return left.get() == right.get(); } template std::strong_ordering operator<=>(unique_strong_ref_ptr const& left, unique_strong_ref_ptr const& right) { return left.get() <=> right.get(); } template bool operator==(unique_strong_ref_ptr const& left, std::nullptr_t) { return left.get() == nullptr; } template std::strong_ordering operator<=>(unique_strong_ref_ptr const& left, std::nullptr_t) { return left.get() <=> nullptr; } template unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr const& other) { return unique_strong_ref_ptr(std::static_pointer_cast(other._ptr)); } template unique_strong_ref_ptr static_pointer_cast(unique_strong_ref_ptr&& other) { return unique_strong_ref_ptr(std::static_pointer_cast(std::move(other._ptr))); } template unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr const& other) { return unique_strong_ref_ptr(std::const_pointer_cast(other._ptr)); } template unique_strong_ref_ptr const_pointer_cast(unique_strong_ref_ptr&& other) { return unique_strong_ref_ptr(std::const_pointer_cast(std::move(other._ptr))); } template unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr const& other) { return unique_strong_ref_ptr(std::reinterpret_pointer_cast(other._ptr)); } template unique_strong_ref_ptr reinterpret_pointer_cast(unique_strong_ref_ptr&& other) { return unique_strong_ref_ptr(std::reinterpret_pointer_cast(std::move(other._ptr))); } template unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr const& other) { return unique_strong_ref_ptr(std::dynamic_pointer_cast(other._ptr)); } template unique_strong_ref_ptr dynamic_pointer_cast(unique_strong_ref_ptr&& other) { return unique_strong_ref_ptr(std::dynamic_pointer_cast(std::move(other._ptr))); } } #endif // TRINITYCORE_UNIQUE_TRACKABLE_PTR_H