/******************************************************************************/ /* REFERENCE-COUNTING HELPERS *************************************************/ /******************************************************************************/ #ifndef _H_EBCL_REFCOUNT #define _H_EBCL_REFCOUNT #include namespace ebcl { // A base class and pointer type that can be used to implement classes which // use in-instance reference counters. /*= REFERENCE-COUNTED INSTANCES ==============================================*/ // Base class containing the reference counter. It may be an atomic, or it // may be a simple integer. template< bool UseAtomic = false > class T_ReferenceCountedClass { public: // Is it atomic ? static const bool UsingAtomic = UseAtomic; // Reference counter type using T_ReferenceCounter = std::conditional_t< UseAtomic , std::atomic< uint32_t > , uint32_t >; // Reference-counting pointers can access the counter template< typename > friend class T_RcPtr; private: T_ReferenceCounter referenceCounter_; // Add a reference to the counter void increaseReferences_( ) noexcept; // Remove a reference from the counter, returning true if the instance // is no longer referenced. bool decreaseReferences_( ) noexcept; protected: // Initialise the counter to 0 T_ReferenceCountedClass( ) noexcept; public: // Get the reference count uint32_t getReferenceCount( ) const noexcept; // Deleted copy/move constructors and assignment operators T_ReferenceCountedClass( T_ReferenceCountedClass< UseAtomic > const& ) = delete; T_ReferenceCountedClass< UseAtomic >& operator =( T_ReferenceCountedClass< UseAtomic > const& ) = delete; T_ReferenceCountedClass( T_ReferenceCountedClass< UseAtomic >&& ) = delete; T_ReferenceCountedClass< UseAtomic >& operator =( T_ReferenceCountedClass< UseAtomic >&& ) = delete; }; // Shortcuts using T_AtomicRcClass = T_ReferenceCountedClass< true >; using T_SimpleRcClass = T_ReferenceCountedClass< false >; /*= REFERENCE-COUNTING POINTERS ==============================================*/ // Pointers that use T_ReferenceCountedClass in order to track the reference // counts of the instances it manages. template< typename Type > class T_RcPtr { static_assert( MetaOr< std::is_base_of< T_AtomicRcClass , Type > , std::is_base_of< T_SimpleRcClass , Type > >::value , "type does not include a reference counter" ); public: // Target type using T_Target = Type; // Pointer type using T_Self = T_RcPtr< Type >; // Base reference counting class using T_RcClass = std::conditional_t< std::is_base_of< T_AtomicRcClass , Type >::value , T_AtomicRcClass , T_SimpleRcClass >; // All RcPtr's are friends template< typename > friend class T_RcPtr; private: T_Target* target_; void setTarget_( T_Target* t ) noexcept; public: // --------------------------------------------------------------------- T_RcPtr( ) noexcept; ~T_RcPtr( ) noexcept; // Constructor function template< typename... AT > static T_RcPtr< Type > New( AT&& ... arguments ); // Initialise from raw pointer. The instance must have a reference // count of zero, and must have been allocated using new. static T_RcPtr< Type > FromRaw( Type* ptr ) noexcept; void clear( ) noexcept; // --------------------------------------------------------------------- // Copy constructors and operators T_RcPtr( T_Self const& other ) noexcept; T_Self& operator= ( T_Self const& other ) noexcept; template< typename Q , T_EnableForChild< Type , Q > = true > T_RcPtr( T_RcPtr< Q > const& source ) noexcept; template< typename Q , T_EnableForParent< Type , Q > = false > explicit T_RcPtr( T_RcPtr< Q > const& source ); template< typename Q , T_EnableForChild< Type , Q > = true > T_Self& operator= ( T_RcPtr< Q > const& other ) noexcept; template< typename Q , T_EnableForParent< Type , Q > = false > T_Self& operator= ( T_RcPtr< Q > const& other ); // --------------------------------------------------------------------- // Move constructors and operators template< typename Q , T_EnableForChild< Type , Q > = true > T_RcPtr( T_RcPtr< Q >&& other ) noexcept; template< typename Q , T_EnableForParent< Type , Q > = false > explicit T_RcPtr( T_RcPtr< Q >&& other ); template< typename Q , T_EnableForChild< Type , Q > = true > T_Self& operator= ( T_RcPtr< Q >&& other ) noexcept; template< typename Q , T_EnableForParent< Type , Q > = false > T_Self& operator= ( T_RcPtr< Q >&& other ); // --------------------------------------------------------------------- // Swapping T_Self swap( T_Self& other ) noexcept; // --------------------------------------------------------------------- // Boolean conversion operator bool ( ) const noexcept; bool operator! ( ) const noexcept; // --------------------------------------------------------------------- // Content access // Access the actual pointer Type * get( ) const noexcept; explicit operator Type* ( ) const noexcept; // Access the object; undefined behavior if get() == nullptr. Type* operator -> ( ) const; Type& operator * ( ) const; // --------------------------------------------------------------------- // Comparison operators template< typename Q , T_EnableForHierarchy< Type , Q > = true > bool operator== ( T_RcPtr< Q > const& p ) const noexcept; template< typename Q , T_EnableForHierarchy< Type , Q > = true > bool operator!= ( T_RcPtr< Q > const& p ) const noexcept; }; template< typename T > void swap( T_RcPtr< T >& lhs , T_RcPtr< T >& rhs ) noexcept; } // namespace #endif // _H_EBCL_REFCOUNT #include