#pragma once #include "RE/B/BSCRC32.h" namespace RE { template class BSTSmartPointerIntrusiveRefCount { public: static void Acquire(T* a_ptr) { a_ptr->IncRef(); } static void Release(T* a_ptr) { if (a_ptr->DecRef() == 0) { delete a_ptr; } } }; template class BSTSmartPointerAutoPtr { public: constexpr static void Acquire(T*) { return; } static void Release(T* a_ptr) { delete a_ptr; } }; template class BSTSmartPointerGamebryoRefCount { public: constexpr static void Acquire(T* a_ptr) { a_ptr->IncRefCount(); } static void Release(T* a_ptr) { a_ptr->DecRefCount(); } }; template class RefManager = BSTSmartPointerIntrusiveRefCount> class BSTSmartPointer { public: using element_type = T; using reference_manager = RefManager; // 1 constexpr BSTSmartPointer() noexcept = default; // 2 constexpr BSTSmartPointer(std::nullptr_t) noexcept {} // 3 template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> explicit BSTSmartPointer(Y* a_rhs) : _ptr(a_rhs) { TryAttach(); } // 9a BSTSmartPointer(const BSTSmartPointer& a_rhs) : _ptr(a_rhs._ptr) { TryAttach(); } // 9b template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> BSTSmartPointer(const BSTSmartPointer& a_rhs) : _ptr(a_rhs._ptr) { TryAttach(); } // 10a BSTSmartPointer(BSTSmartPointer&& a_rhs) noexcept : _ptr(a_rhs._ptr) { a_rhs._ptr = nullptr; } // 10b template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> BSTSmartPointer(BSTSmartPointer&& a_rhs) noexcept : _ptr(a_rhs._ptr) { a_rhs._ptr = nullptr; } ~BSTSmartPointer() { TryDetach(); } // 1a BSTSmartPointer& operator=(const BSTSmartPointer& a_rhs) { if (this != std::addressof(a_rhs)) { TryDetach(); _ptr = a_rhs._ptr; TryAttach(); } return *this; } // 1b template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> BSTSmartPointer& operator=(const BSTSmartPointer& a_rhs) { TryDetach(); _ptr = a_rhs._ptr; TryAttach(); return *this; } // 2a BSTSmartPointer& operator=(BSTSmartPointer&& a_rhs) { if (this != std::addressof(a_rhs)) { TryDetach(); _ptr = a_rhs._ptr; a_rhs._ptr = nullptr; } return *this; } // 2b template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> BSTSmartPointer& operator=(BSTSmartPointer&& a_rhs) { TryDetach(); _ptr = a_rhs._ptr; a_rhs._ptr = nullptr; return *this; } void reset() { TryDetach(); } template < class Y, std::enable_if_t< std::is_convertible_v< Y*, element_type*>, int> = 0> void reset(Y* a_ptr) { if (_ptr != a_ptr) { TryDetach(); _ptr = a_ptr; TryAttach(); } } [[nodiscard]] constexpr element_type* get() const noexcept { return _ptr; } [[nodiscard]] explicit constexpr operator bool() const noexcept { return static_cast(_ptr); } [[nodiscard]] constexpr element_type& operator*() const noexcept { assert(static_cast(*this)); return *_ptr; } [[nodiscard]] constexpr element_type* operator->() const noexcept { assert(static_cast(*this)); return _ptr; } protected: template class> friend class BSTSmartPointer; void TryAttach() { if (_ptr) { reference_manager::Acquire(_ptr); } } void TryDetach() { if (_ptr) { reference_manager::Release(_ptr); _ptr = nullptr; } } // members element_type* _ptr{ nullptr }; // 0 }; static_assert(sizeof(BSTSmartPointer) == 0x8); template [[nodiscard]] BSTSmartPointer make_smart(Args&&... a_args) { return BSTSmartPointer{ new T(std::forward(a_args)...) }; } template class R> [[nodiscard]] constexpr bool operator==(const BSTSmartPointer& a_lhs, const BSTSmartPointer& a_rhs) { return a_lhs.get() == a_rhs.get(); } template class R> [[nodiscard]] constexpr bool operator==(const BSTSmartPointer& a_lhs, std::nullptr_t) noexcept { return !a_lhs; } template BSTSmartPointer(T*) -> BSTSmartPointer; template using BSTAutoPointer = BSTSmartPointer; static_assert(sizeof(BSTAutoPointer) == 0x8); template class R> struct BSCRC32> { public: [[nodiscard]] std::uint32_t operator()(const BSTSmartPointer& a_ptr) const noexcept { return BSCRC32()(a_ptr.get()); } }; }