Reference counting helpers - Base class, partial pointers

This commit is contained in:
Emmanuel BENOîT 2019-01-02 13:27:25 +01:00
parent 6cb0c45870
commit f0e46da2f5
3 changed files with 238 additions and 0 deletions

View file

@ -6,6 +6,7 @@
#ifndef _H_EBCL_EXTERNALS
#define _H_EBCL_EXTERNALS
#include <atomic>
#include <cstddef>
#include <cstdint>
#include <cstring>

108
include/ebcl/RefCount.hh Normal file
View file

@ -0,0 +1,108 @@
/******************************************************************************/
/* 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:
T_ReferenceCountedClass( ) noexcept;
};
// 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
>;
private:
T_Target* target_;
public:
// ---------------------------------------------------------------------
T_RcPtr( ) noexcept;
~T_RcPtr( ) noexcept;
void clear( ) noexcept;
// ---------------------------------------------------------------------
// Copy constructors
T_RcPtr( 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 );
// ---------------------------------------------------------------------
// Move constructors
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 );
};
} // namespace
#endif // _H_EBCL_REFCOUNT
#include <ebcl/inline/RefCount.hh>

View file

@ -0,0 +1,129 @@
/******************************************************************************/
/* REFERENCE-COUNTING HELPERS - INLINE CODE ***********************************/
/******************************************************************************/
#ifndef _H_EBCL_INLINE_REFCOUNT
#define _H_EBCL_INLINE_REFCOUNT
#include <ebcl/RefCount.hh>
namespace ebcl {
/*= T_ReferenceCountedClass ==================================================*/
template< bool B >
inline T_ReferenceCountedClass< B >::T_ReferenceCountedClass( ) noexcept
: referenceCounter_{ 0 }
{ }
template< bool B >
inline void T_ReferenceCountedClass< B >::increaseReferences_( ) noexcept
{
referenceCounter_ ++;
}
template< bool B >
inline bool T_ReferenceCountedClass< B >::decreaseReferences_( ) noexcept
{
return ( -- referenceCounter_ ) == 0;
}
/*= T_RcPtr ==================================================================*/
template< typename T >
inline T_RcPtr< T >::T_RcPtr( ) noexcept
: target_{ nullptr }
{ }
template< typename T >
inline T_RcPtr< T >::~T_RcPtr( ) noexcept
{
clear( );
}
template< typename T >
inline void T_RcPtr< T >::clear( ) noexcept
{
if ( target_ && target_->decreaseReferences_( ) ) {
delete target_;
}
target_ = nullptr;
}
/*----------------------------------------------------------------------------*/
template< typename T >
inline T_RcPtr< T >::T_RcPtr(
T_RcPtr< T > const& other ) noexcept
: target_{ other.target_ }
{
if ( target_ ) {
target_->increaseReferences_( );
}
}
template< typename T >
template<
typename Q ,
T_EnableForChild< T , Q >
> inline T_RcPtr< T >::T_RcPtr(
T_RcPtr< Q > const& other ) noexcept
: target_{ other.target_ }
{
if ( target_ ) {
target_->increaseReferences_( );
}
}
template< typename T >
template<
typename Q ,
T_EnableForParent< T , Q >
> inline T_RcPtr< T >::T_RcPtr(
T_RcPtr< Q > const& other )
: target_{ nullptr }
{
Q* const p{ other.target_ };
if ( p != nullptr ) {
target_ = dynamic_cast< T* >( p );
if ( target_ == nullptr ) {
throw std::bad_cast( );
}
target_->increaseReferences_( );
}
}
/*----------------------------------------------------------------------------*/
template< typename T >
template<
typename Q ,
T_EnableForChild< T , Q >
> inline T_RcPtr< T >::T_RcPtr(
T_RcPtr< Q >&& other ) noexcept
: target_{ nullptr }
{
std::swap( target_ , other.target_ );
}
template< typename T >
template<
typename Q ,
T_EnableForParent< T , Q >
> inline T_RcPtr< T >::T_RcPtr(
T_RcPtr< Q >&& other )
: target_{ nullptr }
{
Q* const p{ other.target_ };
if ( p != nullptr ) {
target_ = dynamic_cast< T* >( p );
if ( target_ == nullptr ) {
throw std::bad_cast( );
}
other.target_ = nullptr;
}
}
} // namespace ebcl
#endif // _H_EBCL_INLINE_REFCOUNT