Reference counting helpers - Base class, partial pointers
This commit is contained in:
parent
6cb0c45870
commit
f0e46da2f5
3 changed files with 238 additions and 0 deletions
|
@ -6,6 +6,7 @@
|
||||||
#ifndef _H_EBCL_EXTERNALS
|
#ifndef _H_EBCL_EXTERNALS
|
||||||
#define _H_EBCL_EXTERNALS
|
#define _H_EBCL_EXTERNALS
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
108
include/ebcl/RefCount.hh
Normal file
108
include/ebcl/RefCount.hh
Normal 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>
|
129
include/ebcl/inline/RefCount.hh
Normal file
129
include/ebcl/inline/RefCount.hh
Normal 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
|
Loading…
Reference in a new issue