From 36e909813588e62c80b10cee8e4530d76160fee0 Mon Sep 17 00:00:00 2001 From: Jan Travnicek <Jan.Travnicek@fit.cvut.cz> Date: Mon, 9 Jul 2018 13:41:47 +0200 Subject: [PATCH] documentation of private shared pointers --- alib2std/src/extensions/memory.hpp | 509 ++++++++++++++++++++++++++++- 1 file changed, 503 insertions(+), 6 deletions(-) diff --git a/alib2std/src/extensions/memory.hpp b/alib2std/src/extensions/memory.hpp index 51492391b3..30882639e3 100644 --- a/alib2std/src/extensions/memory.hpp +++ b/alib2std/src/extensions/memory.hpp @@ -1,6 +1,22 @@ /* * memory.hpp * + * This file is part of Algorithms library toolkit. + * Copyright (C) 2017 Jan Travnicek (jan.travnicek@fit.cvut.cz) + + * Algorithms library toolkit is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * Algorithms library toolkit is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with Algorithms library toolkit. If not, see <http://www.gnu.org/licenses/>. + * * Created on: May 1, 2015 * Author: Jan Travnicek */ @@ -17,46 +33,103 @@ 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: - int m_UseCount; - + /** + * 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. + * + * 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 > { 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 ) { if ( data ) data->m_UseCount = 0; attach ( data ); } + /** + * \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; @@ -66,65 +139,136 @@ public: return * this; } + /** + * \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; } + /** + * \brief + * Operator arrow to chain dereferece to inner managed pointer. + * + * \return the managed pointer + */ T const * operator ->( ) const { return m_Data; } + /** + * \brief + * Operator dereference to access the inner managed pointer. + * + * \return reference to managed data + */ T & operator *( ) { make_unique ( ); return * m_Data; } + /** + * \brief + * Operator dereference to access the inner managed pointer. + * + * \return reference to managed data + */ T const & operator *( ) const { return * m_Data; } + /** + * Getter of the raw managed pointer. + * + * \return the managed pointer + */ T * get ( ) { make_unique ( ); return m_Data; } + /** + * Getter of the raw managed pointer. + * + * \return the managed pointer + */ T const * get ( ) const { return 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; } - int getUseCount ( ) const { + /** + * \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; } + /** + * 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 ( 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 + * Ensures the managed pointer is unique by copy constructing the managed instance if needed. + */ void make_unique ( ) { if ( unique ( ) ) return; @@ -135,8 +279,19 @@ private: 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; @@ -146,40 +301,123 @@ private: }; +/** + * \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; - int m_UseCount; + + /** + * 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; @@ -189,65 +427,136 @@ public: return * this; } + /** + * \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 ); } + /** + * Getter of the raw managed pointer. + * + * \return the managed pointer + */ T * get ( ) { make_unique ( ); return m_Data->m_Data; } + /** + * 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; } - int getUseCount ( ) const { + /** + * \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; } + /** + * 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; @@ -256,8 +565,19 @@ private: 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. + * + * \param first the first instance + * \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; @@ -266,31 +586,81 @@ private: }; +/** + * \brief + * Managed pointer simulating value like behavior. + * + * The class is supposed to be similar to unique_ptr but allows copying of managed instance by clone method or its copy constructor. + * + * \tparam T type of managed instance + */ template < class T > class smart_ptr { + /** + * \brief + * Pointer to managed object. + */ T * m_Data; public: + /** + * \brief + * Default initialization to null. + */ explicit smart_ptr ( ) : m_Data ( NULL ) { } + /** + * \brief + * Constructor which takes ownership of the provided pointer. + */ explicit smart_ptr ( T * data ) : m_Data ( data ) { } + /** + * \brief + * Conversion constructor to simplify type casting. + * + * \tparam R the type of the managed resource of the source smart pointer + * + * \param other the source instance + */ template < class R > smart_ptr ( smart_ptr < R > other ) : m_Data ( other.release ( ) ) { } + /** + * \brief + * Copy constructor of the smart pointer. Internally uses clone (if available) or copy constructor of the managed resource. + * + * \param other the source instance + */ smart_ptr ( const smart_ptr & other ) : m_Data ( ext::clone ( * other.m_Data ) ) { } + /** + * \brief + * Move constructor of the smart pointer. Passes ownership of the managed resource from source to constructed instance + * + * \param other the source instance + */ smart_ptr ( smart_ptr && other ) noexcept : m_Data ( other.release ( ) ) { } + /** + * \brief + * The destructor of the shared pointer, responsible for freeing the managed resource. + */ ~smart_ptr ( ) noexcept { delete m_Data; } + /** + * \brief + * Copy operator of assignment. Internally uses clone (if available) or copy constructor of the managed resource. + * + * \param other the source instance + */ smart_ptr & operator =( const smart_ptr & other ) { if ( this == & other ) return * this; @@ -300,6 +670,12 @@ public: return * this; } + /** + * \brief + * Copy operator of assignment. Passes ownership of the managed resource from source to this instance. + * + * \param other the source instance + */ smart_ptr & operator =( smart_ptr && other ) noexcept { using std::swap; @@ -307,30 +683,70 @@ public: return * this; } + /** + * \brief + * Operator arrow to chain dereferece to inner managed pointer. + * + * \return the managed pointer + */ T * operator ->( ) { return m_Data; } + /** + * \brief + * Operator arrow to chain dereferece to inner managed pointer. + * + * \return the managed pointer + */ T * operator ->( ) const { return m_Data; } + /** + * \brief + * Operator dereference to access the inner managed pointer. + * + * \return reference to managed data + */ T & operator *( ) { return * m_Data; } + /** + * \brief + * Operator dereference to access the inner managed pointer. + * + * \return reference to managed data + */ T & operator *( ) const { return * m_Data; } + /** + * Getter of the raw managed pointer. + * + * \return the managed pointer + */ T * get ( ) { return m_Data; } + /** + * Getter of the raw managed pointer. + * + * \return the managed pointer + */ T * get ( ) const { return m_Data; } + /** + * \brief + * Releases the shared resource and returns it. + * + * \return the released shared resource + */ T * release ( ) { T * res = m_Data; @@ -338,26 +754,65 @@ public: return res; } + /** + * Tests the instance whether the managed pointer is valid + * + * \return true if the managed pointer is not null, false otherwise + */ explicit operator bool( ) const { - return m_Data; + return ( bool ) m_Data; } }; +/** + * Operator to print the copy on write shared pointer to the output stream. + * + * \param out the output stream + * \param map the copy on write shared pointer to print + * + * \tparam T the type of managed instances inside the copy on write shared pointer + * + * \return the output stream from the \p out + */ template < class T > std::ostream & operator <<( std::ostream & out, const ext::cow_shared_ptr < T > & ptr ) { out << * ptr; return out; } +/** + * Operator to print the smart pointer to the output stream. + * + * \param out the output stream + * \param map the smart pointer to print + * + * \tparam T the type of managed instances inside the smart pointer + * + * \return the output stream from the \p out + */ template < class T > std::ostream & operator <<( std::ostream & out, const ext::smart_ptr < T > & ptr ) { out << * ptr; return out; } +/** + * Specialisation of the compare structure implementing the three-way comparison + * + * \tparam T the type of managed resource inside the copy on write shared pointer + */ template < class T > struct compare < ext::cow_shared_ptr < T > > { + + /** + * Implementation of the three-way comparison + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ int operator ()( const ext::cow_shared_ptr < T > & first, const ext::cow_shared_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; @@ -371,8 +826,22 @@ struct compare < ext::cow_shared_ptr < T > > { }; +/** + * Specialisation of the compare structure implementing the three-way comparison + * + * \tparam T the type of managed resource inside the shared pointer + */ template < class T > struct compare < std::shared_ptr < T > > { + + /** + * Implementation of the three-way comparison + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ int operator ()( const std::shared_ptr < T > & first, const std::shared_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; @@ -386,8 +855,22 @@ struct compare < std::shared_ptr < T > > { }; +/** + * Specialisation of the compare structure implementing the three-way comparison + * + * \tparam T the type of managed resource inside the unique pointer + */ template < class T > struct compare < std::unique_ptr < T > > { + + /** + * Implementation of the three-way comparison + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ int operator ()( const std::unique_ptr < T > & first, const std::unique_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; @@ -401,8 +884,22 @@ struct compare < std::unique_ptr < T > > { }; +/** + * Specialisation of the compare structure implementing the three-way comparison + * + * \tparam T the type of managed resource inside the smart pointer + */ template < class T > struct compare < ext::smart_ptr < T > > { + + /** + * Implementation of the three-way comparison + * + * \param first the left operand of the comparison + * \param second the right operand of the comparison + * + * \return negative value of left < right, positive value if left > right, zero if left == right + */ int operator ()( const ext::smart_ptr < T > & first, const ext::smart_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; -- GitLab