corelib/include/ebcl/RefCount.hh
Emmanuel BENOîT a4a2a9eda4 Reference-counting helpers - Equality operators
* Added == and != operators; they can only be used if the referenced types are
from the same hierarchy
 * Tests for the above
2019-01-02 17:52:56 +01:00

183 lines
5.6 KiB
C++

/******************************************************************************/
/* REFERENCE-COUNTING HELPERS *************************************************/
/******************************************************************************/
#ifndef _H_EBCL_REFCOUNT
#define _H_EBCL_REFCOUNT
#include <ebcl/Utilities.hh>
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 <ebcl/inline/RefCount.hh>