#pragma once #include "RE/B/BSCRC32.h" namespace RE { template class NiPointer { public: using element_type = T; // 1) NiPointer() noexcept = default; // 2) NiPointer(std::nullptr_t) noexcept {} // 3) template NiPointer(Y* a_rhs) requires(std::convertible_to) : _ptr(static_cast(a_rhs)) { TryAttach(); } // 9a) NiPointer(const NiPointer& a_rhs) : _ptr(a_rhs._ptr) { TryAttach(); } // 9b) template NiPointer(const NiPointer& a_rhs) requires(std::convertible_to) : _ptr(static_cast(a_rhs._ptr)) { TryAttach(); } // 10a) NiPointer(NiPointer&& a_rhs) noexcept : _ptr(std::exchange(a_rhs._ptr, nullptr)) {} // 10b) template NiPointer(NiPointer&& a_rhs) noexcept requires(std::convertible_to) : _ptr(static_cast(std::exchange(a_rhs._ptr, nullptr))) {} ~NiPointer() noexcept { reset(); } // 1a) NiPointer& operator=(const NiPointer& a_rhs) { if (this != std::addressof(a_rhs)) { TryDetach(); _ptr = a_rhs._ptr; TryAttach(); } return *this; } // 1b) template NiPointer& operator=(const NiPointer& a_rhs) requires(std::convertible_to) { TryDetach(); _ptr = static_cast(a_rhs._ptr); TryAttach(); return *this; } // 2a) NiPointer& operator=(NiPointer&& a_rhs) noexcept { if (this != std::addressof(a_rhs)) { TryDetach(); _ptr = std::exchange(a_rhs._ptr, nullptr); } return *this; } // 2b) template NiPointer& operator=(NiPointer&& a_rhs) noexcept requires(std::convertible_to) { TryDetach(); _ptr = std::exchange(a_rhs._ptr, nullptr); return *this; } // 1) void reset() { TryDetach(); } // 2) template void reset(Y* a_ptr) requires(std::convertible_to) { if (_ptr != a_ptr) { TryDetach(); _ptr = static_cast(a_ptr); TryAttach(); } } [[nodiscard]] element_type* get() const noexcept { return _ptr; } [[nodiscard]] element_type& operator*() const noexcept { assert(static_cast(*this)); return *_ptr; } [[nodiscard]] element_type* operator->() const noexcept { assert(static_cast(*this)); return _ptr; } [[nodiscard]] explicit operator bool() const noexcept { return _ptr != nullptr; } protected: template friend class NiPointer; void TryAttach() { if (_ptr) { _ptr->IncRefCount(); } } void TryDetach() { if (_ptr) { _ptr->DecRefCount(); _ptr = nullptr; } } // members element_type* _ptr{ nullptr }; // 0 }; //static_assert(sizeof(NiPointer) == 0x8); template [[nodiscard]] NiPointer make_nismart(Args&&... a_args) { return NiPointer{ new T(std::forward(a_args)...) }; } // 1) template [[nodiscard]] bool operator==(const NiPointer& a_lhs, const NiPointer& a_rhs) noexcept { return a_lhs.get() == a_rhs.get(); } // 7) template [[nodiscard]] std::strong_ordering operator<=>(const NiPointer& a_lhs, const NiPointer& a_rhs) noexcept { return std::compare_three_way{}(a_lhs.get(), a_rhs.get()); } // 8) template [[nodiscard]] bool operator==(const NiPointer& a_lhs, std::nullptr_t) noexcept { return !a_lhs; } // 20) template [[nodiscard]] std::strong_ordering operator<=>(const NiPointer& a_lhs, std::nullptr_t) noexcept { return std::compare_three_way{}(a_lhs.get(), static_cast::element_type*>(nullptr)); } template struct BSCRC32> { public: [[nodiscard]] std::uint32_t operator()(const NiPointer& a_key) const noexcept { return BSCRC32()(a_key.get()); } }; }