#pragma once #include #include #include #include #include #include #include "FastNoise_Config.h" namespace FastNoise { class FASTNOISE_API SmartNodeManager { public: static constexpr uint64_t kInvalidReferenceId = (uint64_t)-1; SmartNodeManager() = delete; static void SetMemoryPoolSize( uint32_t size ); private: template friend struct MetadataT; template friend class SmartNode; template friend SmartNode New( FastSIMD::eLevel ); static uint64_t GetReference( const void* ptr ); static void IncReference( uint64_t id ); static void DecReference( uint64_t id, void* ptr, void ( *destructorFunc )( void* ) ); static uint32_t ReferenceCount( uint64_t id ); static void* Allocate( size_t size, size_t align ); }; template class SmartNode { public: static_assert( std::is_base_of::value, "SmartNode should only be used for FastNoise node classes" ); template static SmartNode DynamicCast( SmartNode node ) { if( T* dynamicCast = dynamic_cast( node.get() ) ) { return FastNoise::SmartNode( node, dynamicCast ); } return nullptr; } constexpr SmartNode( std::nullptr_t = nullptr ) noexcept : mReferenceId( SmartNodeManager::kInvalidReferenceId ), mPtr( nullptr ) {} SmartNode( const SmartNode& node ) { TryInc( node.mReferenceId ); mReferenceId = node.mReferenceId; mPtr = node.mPtr; } template SmartNode( const SmartNode& node ) { TryInc( node.mReferenceId ); mReferenceId = node.mReferenceId; mPtr = node.mPtr; } template SmartNode( const SmartNode& node, T* ptr ) { assert( ptr ); TryInc( node.mReferenceId ); mReferenceId = node.mReferenceId; mPtr = ptr; } SmartNode( SmartNode&& node ) noexcept { mReferenceId = node.mReferenceId; mPtr = node.mPtr; node.mReferenceId = SmartNodeManager::kInvalidReferenceId; node.mPtr = nullptr; } template SmartNode( SmartNode&& node ) noexcept { mReferenceId = node.mReferenceId; mPtr = node.mPtr; node.mReferenceId = SmartNodeManager::kInvalidReferenceId; node.mPtr = nullptr; } ~SmartNode() { Release(); } SmartNode& operator=( SmartNode&& node ) noexcept { swap( node ); return *this; } template SmartNode& operator=( SmartNode&& node ) noexcept { if( mReferenceId == node.mReferenceId ) { mPtr = node.mPtr; } else { Release(); mReferenceId = node.mReferenceId; mPtr = node.mPtr; node.mReferenceId = SmartNodeManager::kInvalidReferenceId; node.mPtr = nullptr; } return *this; } SmartNode& operator=( const SmartNode& node ) noexcept { if( mReferenceId != node.mReferenceId ) { TryInc( node.mReferenceId ); Release(); mReferenceId = node.mReferenceId; } mPtr = node.mPtr; return *this; } template SmartNode& operator=( const SmartNode& node ) noexcept { if( mReferenceId != node.mReferenceId ) { TryInc( node.mReferenceId ); Release(); mReferenceId = node.mReferenceId; } mPtr = node.mPtr; return *this; } template friend bool operator==( const SmartNode& lhs, const SmartNode& rhs ) noexcept { return lhs.get() == rhs.get(); } template friend bool operator!=( const SmartNode& lhs, const SmartNode& rhs ) noexcept { return lhs.get() != rhs.get(); } T& operator*() const noexcept { return *mPtr; } T* operator->() const noexcept { return mPtr; } explicit operator bool() const noexcept { return mPtr != nullptr; } T* get() const noexcept { return mPtr; } void reset( T* ptr = nullptr ) { *this = SmartNode( ptr ); } void swap( SmartNode& node ) noexcept { std::swap( mReferenceId, node.mReferenceId ); std::swap( mPtr, node.mPtr ); } long use_count() const noexcept { if( mReferenceId == SmartNodeManager::kInvalidReferenceId ) { return 0; } return (long)SmartNodeManager::ReferenceCount( mReferenceId ); } bool unique() const noexcept { return use_count() == 1; } private: template friend SmartNode New( FastSIMD::eLevel ); template friend struct MetadataT; template friend class SmartNode; explicit SmartNode( T* ptr ) : mReferenceId( ptr ? SmartNodeManager::GetReference( ptr ) : SmartNodeManager::kInvalidReferenceId ), mPtr( ptr ) { if( mReferenceId != SmartNodeManager::kInvalidReferenceId ) { SmartNodeManager::IncReference( mReferenceId ); } } void Release() { using U = typename std::remove_const::type; if( mReferenceId != SmartNodeManager::kInvalidReferenceId ) { SmartNodeManager::DecReference( mReferenceId, const_cast( mPtr ), []( void* ptr ) { ( (U*)ptr )->~T(); } ); } mReferenceId = SmartNodeManager::kInvalidReferenceId; mPtr = nullptr; } static void TryInc( uint64_t id ) { if( id != SmartNodeManager::kInvalidReferenceId ) { SmartNodeManager::IncReference( id ); } } uint64_t mReferenceId; T* mPtr; }; } // namespace FastNoise namespace std { template struct hash> { size_t operator()( const FastNoise::SmartNode& node ) const noexcept { return std::hash( node.get() ); } }; }