From 84fccb72fcfbbdaf21aa7d6e556cec85b873a2b6 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Sun, 4 Nov 2018 09:38:27 +0100 Subject: [PATCH] simplify cow_shared_ptr implementation --- alib2common/src/object/AnyObjectBase.h | 2 +- alib2common/src/object/Object.h | 2 +- alib2std/src/extensions/memory.hpp | 407 +------------------ alib2std/test-src/extensions/SharedPtrTest.h | 2 +- 4 files changed, 22 insertions(+), 391 deletions(-) diff --git a/alib2common/src/object/AnyObjectBase.h b/alib2common/src/object/AnyObjectBase.h index 0bc59e4d6e..46ba0cbf6e 100644 --- a/alib2common/src/object/AnyObjectBase.h +++ b/alib2common/src/object/AnyObjectBase.h @@ -31,7 +31,7 @@ namespace object { -class AnyObjectBase : public ext::cow_shared_ptr_base { +class AnyObjectBase { public: /** * \brief diff --git a/alib2common/src/object/Object.h b/alib2common/src/object/Object.h index 14b53b5de1..d1f7dcdbf0 100644 --- a/alib2common/src/object/Object.h +++ b/alib2common/src/object/Object.h @@ -28,7 +28,7 @@ class Object { * Unifies the shared pointers. For internal use when two pointer eval equal. */ void unify ( Object & other ) { - if ( this->m_data.getUseCount ( ) > other.m_data.getUseCount ( ) ) + if ( this->m_data.use_count ( ) > other.m_data.use_count ( ) ) other.m_data = this->m_data; else this->m_data = other.m_data; diff --git a/alib2std/src/extensions/memory.hpp b/alib2std/src/extensions/memory.hpp index 0fa5458ee7..4d9e2a64c6 100644 --- a/alib2std/src/extensions/memory.hpp +++ b/alib2std/src/extensions/memory.hpp @@ -33,37 +33,6 @@ namespace ext { -/** - * \brief - * Predeclaration of copy on write shared ptr class. - */ -template < typename T, typename Enable = void > -class cow_shared_ptr; - -/** - * \brief - * Base class of classes used inside copy on write pointers. - */ -class cow_shared_ptr_base { -public: - /** - * Constructor of the copy on write shared ptr base class. The use count is initialized to zero. - */ - cow_shared_ptr_base ( ) : m_UseCount ( 0 ) { } - -private: - /** - * Caries the number of uses of this instance as a managed pointer inside copy on write pointer. - */ - unsigned m_UseCount; - - /** - * To make m_UseCount accessible from copy on write pointer class. - */ - template < typename T, typename Enable > - friend class cow_shared_ptr; -}; - /** * \brief * Specialisation of copy on write pointer for classes based with copy on write pointer base. @@ -75,24 +44,20 @@ private: * \tparam T the type of managed objects */ template < class T > -class cow_shared_ptr < T, typename std::enable_if < std::is_base_of < cow_shared_ptr_base, T >::value >::type > { +class cow_shared_ptr : std::shared_ptr < T > { public: /** * \brief * Default initialization to null. */ - explicit cow_shared_ptr ( ) { - attach ( NULL ); + explicit cow_shared_ptr ( ) : std::shared_ptr < T > ( nullptr ) { } /** * \brief * Constructor which takes ownership of the provided pointer. */ - explicit cow_shared_ptr ( T * data ) { - if ( data ) data->m_UseCount = 0; - - attach ( data ); + explicit cow_shared_ptr ( T * data ) : std::shared_ptr < T > ( data ) { } /** @@ -101,8 +66,7 @@ public: * * \param other the source instance */ - cow_shared_ptr ( const cow_shared_ptr & other ) { - attach ( other.m_Data ); + cow_shared_ptr ( const cow_shared_ptr & other ) : std::shared_ptr < T > ( other ) { } /** @@ -111,9 +75,7 @@ public: * * \param other the source instance */ - cow_shared_ptr ( cow_shared_ptr && other ) noexcept { - m_Data = other.m_Data; - other.m_Data = NULL; + cow_shared_ptr ( cow_shared_ptr && other ) noexcept : std::shared_ptr < T > ( std::move ( other ) ) { } /** @@ -121,7 +83,6 @@ public: * The destructor of the shared pointer. */ ~cow_shared_ptr ( ) noexcept { - detach ( ); } /** @@ -131,11 +92,7 @@ public: * \param other the source instance */ cow_shared_ptr & operator =( const cow_shared_ptr & other ) { - if ( this == & other ) return * this; - - detach ( ); - attach ( other.m_Data ); - + static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < const std::shared_ptr < T > & > ( other ); return * this; } @@ -146,7 +103,7 @@ public: * \param other the source instance */ cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept { - swap ( * this, other ); + static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < std::shared_ptr < T > && > ( other ); return * this; } @@ -157,8 +114,7 @@ public: * \return the managed pointer */ T * operator ->( ) { - make_unique ( ); - return m_Data; + return this->get ( ); } /** @@ -168,7 +124,7 @@ public: * \return the managed pointer */ T const * operator ->( ) const { - return m_Data; + return this->get ( ); } /** @@ -178,8 +134,7 @@ public: * \return reference to managed data */ T & operator *( ) { - make_unique ( ); - return * m_Data; + return * this->get ( ); } /** @@ -189,7 +144,7 @@ public: * \return reference to managed data */ T const & operator *( ) const { - return * m_Data; + return * this->get ( ); } /** @@ -199,7 +154,7 @@ public: */ T * get ( ) { make_unique ( ); - return m_Data; + return std::shared_ptr < T >::get ( ); } /** @@ -208,7 +163,7 @@ public: * \return the managed pointer */ T const * get ( ) const { - return m_Data; + return std::shared_ptr < T >::get ( ); } /** @@ -218,7 +173,7 @@ public: * \return bool true if the managed pointer is referenced from one location only, false otherwise */ bool unique ( ) const { - return m_Data == NULL || m_Data->m_UseCount == 1; + return std::shared_ptr < T >::unique ( ); } /** @@ -227,10 +182,8 @@ public: * * \return the use count */ - unsigned getUseCount ( ) const { - if ( m_Data == NULL ) return 0; - - return m_Data->m_UseCount; + unsigned use_count ( ) const { + return std::shared_ptr < T >::use_count ( ); } /** @@ -239,31 +192,10 @@ public: * \return true if the managed pointer is not null and the use count is nonzero, false otherwise */ explicit operator bool( ) const { - return getUseCount ( ) != 0; + return use_count ( ) != 0; } private: - /** - * \brief - * Changes the managed pointer and increases its use count - * - * \param data the new value of managed pointer - */ - void attach ( T * data ) { - m_Data = data; - - if ( m_Data ) m_Data->m_UseCount++; - } - - /** - * \brief - * Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null. - */ - void detach ( ) { - if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data; - - m_Data = NULL; - } /** * \brief @@ -272,308 +204,9 @@ private: void make_unique ( ) { if ( unique ( ) ) return; - T * tmp = m_Data; - detach ( ); - tmp = ext::clone ( * tmp ); - tmp->m_UseCount = 0; - attach ( tmp ); - } - - /** - * \brief - * The managed pointer - */ - T * m_Data; - - /** - * \brief - * Specialisation of swap method to copy on write shared pointers. - * - * \param first the first instance - * \param second the second instance - */ - friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) { - T * tmp = first.m_Data; - - first.m_Data = second.m_Data; - second.m_Data = tmp; - } - -}; - -/** - * \brief - * Specialisation of copy on write pointer for classes not based with copy on write pointer base. - * - * The class is essentially mimicking the behavior of shared_ptr. Additionaly the use of dereference (either through operator* or operator->) in non-constant context causes the managed pointer to ensure the referenced object is referenced from this class only. - * - * The class also uniques the referenced instances when they are equal. - * - * \tparam T the type of managed objects - */ -template < class T > -class cow_shared_ptr < T, typename std::enable_if < !std::is_base_of < cow_shared_ptr_base, T >::value >::type > { - /** - * \brief - * The inner structure to hold managed pointer and its use count (the number how many times it is referenced). - */ - struct cow_shared_ptr_data { - /** - * \brief - * The managed pointer. - */ - T * m_Data; - - /** - * Caries the number of uses of this instance as a managed pointer inside copy on write pointer. - */ - unsigned m_UseCount; - - /** - * \brief - * Contructs the inner shared resource based on the managed pointer. - * - * The class takes ownership of the provided pointer - */ - cow_shared_ptr_data ( T * data ) : m_Data ( data ), m_UseCount ( 0 ) { } - - /** - * \brief - * Destructor to free the managed pointer. - */ - ~cow_shared_ptr_data ( ) { - delete m_Data; - } - - /** - * Disable copy construction. - */ - cow_shared_ptr_data ( const cow_shared_ptr_data & ) = delete; - - /** - * Disable copy operator of assignment. - */ - cow_shared_ptr_data & operator = ( const cow_shared_ptr_data & ) = delete; - - /** - * Disable move construction. - */ - cow_shared_ptr_data ( cow_shared_ptr_data && ) = delete; - - /** - * Disable move operator of assignment. - */ - cow_shared_ptr_data & operator = ( cow_shared_ptr_data && ) = delete; - }; - -public: - /** - * \brief - * Default initialization to null. - */ - explicit cow_shared_ptr ( ) { - attach ( NULL ); - } - - /** - * \brief - * Constructor which takes ownership of the provided pointer. - */ - explicit cow_shared_ptr ( T * data ) { - attach ( data ? new cow_shared_ptr_data ( data ) : NULL ); - } - - /** - * \brief - * Copy constructor to create new instance of shared pointer reffering the same data. - * - * \param other the source instance - */ - cow_shared_ptr ( const cow_shared_ptr & other ) { - attach ( other.m_Data ); - } - - /** - * \brief - * Move constructor to create new instance of shared pointer reffering the same data. - * - * \param other the source instance - */ - cow_shared_ptr ( cow_shared_ptr && other ) noexcept { - m_Data = other.m_Data; - other.m_Data = NULL; - } - - /** - * \brief - * The destructor of the shared pointer. - */ - ~cow_shared_ptr ( ) noexcept { - detach ( ); - } - - /** - * \brief - * Copy assignment operator to change reffered instace to source one. - * - * \param other the source instance - */ - cow_shared_ptr & operator =( const cow_shared_ptr & other ) { - if ( this == & other ) return * this; - - detach ( ); - attach ( other.m_Data ); - - return * this; + static_cast < std::shared_ptr < T > & > ( * this ) = std::shared_ptr < T > ( ext::clone ( * std::shared_ptr < T >::get ( ) ) ); } - /** - * \brief - * Move assignment operator to change reffered instace to source one. - * - * \param other the source instance - */ - cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept { - swap ( * this, other ); - return * this; - } - - /** - * \brief - * Operator arrow to chain dereferece to inner managed pointer. - * - * \return the managed pointer - */ - T * operator ->( ) { - make_unique ( ); - return m_Data->m_Data; - } - - /** - * \brief - * Operator arrow to chain dereferece to inner managed pointer. - * - * \return the managed pointer - */ - T const * operator ->( ) const { - return m_Data->m_Data; - } - - /** - * \brief - * Operator dereference to access the inner managed pointer. - * - * \return reference to managed data - */ - T & operator *( ) { - make_unique ( ); - return * ( m_Data->m_Data ); - } - - /** - * \brief - * Operator dereference to access the inner managed pointer. - * - * \return reference to managed data - */ - T const & operator *( ) const { - return * ( m_Data->m_Data ); - } - - /** - * \brief - * Getter of the raw managed pointer. - * - * \return the managed pointer - */ - T * get ( ) { - make_unique ( ); - return m_Data->m_Data; - } - - /** - * \brief - * Getter of the raw managed pointer. - * - * \return the managed pointer - */ - T const * get ( ) const { - return m_Data->m_Data; - } - - /** - * \brief - * Tests whether the managed pointer is referenced from one location only (or the class stores null pointer). - * - * \return bool true if the managed pointer is referenced from one location only, false otherwise - */ - bool unique ( ) const { - return m_Data == NULL || m_Data->m_UseCount == 1; - } - - /** - * \brief - * Getter of the number how many times the managed pointer is referenced. - * - * \return the use count - */ - unsigned getUseCount ( ) const { - if ( m_Data == NULL ) return 0; - - return m_Data->m_UseCount; - } - - /** - * \brief - * Tests the instance whether the managed pointer is valid - * - * \return true if the managed pointer is not null and the use count is nonzero, false otherwise - */ - explicit operator bool( ) const { - return getUseCount ( ) != 0; - } - -private: - /** - * \brief - * Changes the managed pointer and increases its use count - * - * \param data the new value of managed pointer - */ - void attach ( typename cow_shared_ptr < T >::cow_shared_ptr_data * data ) { - m_Data = data; - - if ( m_Data ) m_Data->m_UseCount++; - } - - /** - * \brief - * Decreases the use count of managed pointer, if needed the pointer is freed. Managed pointer stored in this instance is set to null. - */ - void detach ( ) { - if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data; - - m_Data = NULL; - } - - /** - * \brief - * Ensures the managed pointer is unique by copy constructing the managed instance if needed. - */ - void make_unique ( ) { - if ( unique ( ) ) return; - - typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = m_Data; - detach ( ); - attach ( new cow_shared_ptr_data ( ext::clone ( * tmp->m_Data ) ) ); - } - - /** - * \brief - * The instance of sturucture containing managed pointer and its use count. - */ - cow_shared_ptr_data * m_Data; - /** * \brief * Specialisation of swap method to copy on write shared pointers. @@ -582,9 +215,7 @@ private: * \param second the second instance */ friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) { - typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = first.m_Data; - first.m_Data = second.m_Data; - second.m_Data = tmp; + std::swap ( static_cast < std::shared_ptr < T > & > ( first ), static_cast < std::shared_ptr < T > & > ( second ) ); } }; diff --git a/alib2std/test-src/extensions/SharedPtrTest.h b/alib2std/test-src/extensions/SharedPtrTest.h index 63ed1d2a3f..2ed9aa6f7f 100644 --- a/alib2std/test-src/extensions/SharedPtrTest.h +++ b/alib2std/test-src/extensions/SharedPtrTest.h @@ -36,7 +36,7 @@ public: } }; -class Moveable2 : public ext::cow_shared_ptr_base { +class Moveable2 { int& m_moves; int& m_copies; -- GitLab