From 32e54b6bd168c196adb45360b18721851162d731 Mon Sep 17 00:00:00 2001 From: Shauren Date: Mon, 11 Mar 2024 18:16:34 +0100 Subject: Core/Utils: Added a custom smart pointer type unique_trackable_ptr - a specialized variant of std::shared_ptr that enforces unique ownership * This is intended to be used by external code unable to track object lifetime such as custom scripting engines --- src/common/Utilities/UniqueTrackablePtr.h | 274 ++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 src/common/Utilities/UniqueTrackablePtr.h (limited to 'src') diff --git a/src/common/Utilities/UniqueTrackablePtr.h b/src/common/Utilities/UniqueTrackablePtr.h new file mode 100644 index 00000000000..0a09ead1eed --- /dev/null +++ b/src/common/Utilities/UniqueTrackablePtr.h @@ -0,0 +1,274 @@ +/* + * 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_TRACKING_PTR_H +#define TRINITYCORE_UNIQUE_TRACKING_PTR_H + +#include "Define.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 + * \tparam Deleter Object deleter (defaults to std::default_delete) + */ +template +class unique_trackable_ptr +{ +public: + using element_type = T; + using pointer = T*; + using deleter_type = Deleter; + + unique_trackable_ptr() : _ptr(nullptr, deleter_type()) { } + + explicit unique_trackable_ptr(pointer ptr) : _ptr(ptr, deleter_type()) { } + + explicit unique_trackable_ptr(pointer ptr, deleter_type 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)) { } + + unique_trackable_ptr& operator=(unique_trackable_ptr const&) = delete; + + unique_trackable_ptr& operator=(unique_trackable_ptr&& other) noexcept + { + _ptr = std::move(other); + 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(pointer ptr = nullptr, deleter_type deleter = {}) + { + _ptr.reset(ptr, std::move(deleter)); + } + +private: + 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; + + template + unique_weak_ptr(unique_trackable_ptr const& trackable) : _ptr(trackable._ptr) + { + } + + unique_weak_ptr(unique_weak_ptr const& other) = default; + unique_weak_ptr(unique_weak_ptr&& other) noexcept = default; + + template + unique_weak_ptr& operator=(unique_trackable_ptr const& trackable) + { + _ptr = trackable._ptr; + return *this; + } + + unique_weak_ptr& operator=(unique_weak_ptr const& other) = default; + unique_weak_ptr& operator=(unique_weak_ptr&& other) noexcept = default; + + ~unique_weak_ptr() = default; + + 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: + 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); + } + + friend std::strong_ordering operator<=>(unique_strong_ref_ptr const&, unique_strong_ref_ptr const&) = default; + +private: + template + friend class unique_weak_ptr; + + unique_strong_ref_ptr(std::shared_ptr ptr) : _ptr(std::move(ptr)) { } + + std::shared_ptr _ptr; +}; + +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; +} +} + +#endif // TRINITYCORE_UNIQUE_TRACKING_PTR_H -- cgit v1.2.3