/* * 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 */ #ifndef __MEMORY_HPP_ #define __MEMORY_HPP_ #include <memory> #include <utility> #include "compare.hpp" #include "type_traits.hpp" #include "clone.hpp" namespace ext { /** * \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 : std::shared_ptr < T > { public: using std::shared_ptr < T >::shared_ptr; using std::shared_ptr < T >::operator =; #ifndef __clang__ /** * \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 ) = default; /** * \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 = default; /** * \brief * The destructor of the shared pointer. */ ~cow_shared_ptr ( ) noexcept = default; /** * \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 ) = default; /** * \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 = default; #endif /** * \brief * Sets the shared pointer to nullptr. */ void reset ( ) noexcept { return std::shared_ptr < T >::reset ( ); } /** * \brief * Sets the shared pointer to value. * * \param ptr the value to store */ template < class Y > void reset( Y * ptr ) { return std::shared_ptr < T >::reset ( ptr ); } /** * \brief * Operator arrow to chain dereferece to inner managed pointer. * * \return the managed pointer */ T * operator ->( ) { return this->get ( ); } /** * \brief * Operator arrow to chain dereferece to inner managed pointer. * * \return the managed pointer */ T const * operator ->( ) const { return this->get ( ); } /** * \brief * Operator dereference to access the inner managed pointer. * * \return reference to managed data */ T & operator *( ) { return * this->get ( ); } /** * \brief * Operator dereference to access the inner managed pointer. * * \return reference to managed data */ T const & operator *( ) const { return * this->get ( ); } /** * Getter of the raw managed pointer. * * \return the managed pointer */ T * get ( ) { make_unique ( ); return std::shared_ptr < T >::get ( ); } /** * Getter of the raw managed pointer. * * \return the managed pointer */ T const * get ( ) const { return std::shared_ptr < T >::get ( ); } /** * \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 std::shared_ptr < T >::unique ( ); } /** * \brief * Getter of the number how many times the managed pointer is referenced. * * \return the use count */ unsigned use_count ( ) const { return std::shared_ptr < T >::use_count ( ); } /** * 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 use_count ( ) != 0; } private: /** * \brief * Ensures the managed pointer is unique by copy constructing the managed instance if needed. */ void make_unique ( ) { if ( unique ( ) ) return; static_cast < std::shared_ptr < T > & > ( * this ) = std::shared_ptr < T > ( ext::clone ( std::shared_ptr < T >::operator * ( ) ) ); } /** * \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 ) { std::swap ( static_cast < std::shared_ptr < T > & > ( first ), static_cast < std::shared_ptr < T > & > ( second ) ); } }; /** * \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 ( nullptr ) { } /** * \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; delete m_Data; m_Data = ext::clone ( * other.m_Data ); 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; swap ( this->m_Data, other.m_Data ); 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; } /** * \brief * Getter of the raw managed pointer. * * \return the managed pointer */ T * get ( ) { return m_Data; } /** * \brief * 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; m_Data = nullptr; return res; } /** * \brief * 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 ( bool ) m_Data; } }; /** * \brief * 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; } /** * \brief * 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; } /** * \brief * 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 > > { /** * \brief * 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; if ( !first ) return -1; if ( !second ) return 1; static compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; /** * \brief * 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 > > { /** * \brief * 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; if ( !first ) return -1; if ( !second ) return 1; static compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; /** * \brief * 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 > > { /** * \brief * 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; if ( !first ) return -1; if ( !second ) return 1; static compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; /** * \brief * 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; if ( !first ) return -1; if ( !second ) return 1; static compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; } /* namespace ext */ #endif /* __MEMORY_HPP_ */