/* * 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/>. */ #pragma once #include <memory> #include <utility> #include <compare> #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 static_cast < 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; } } /* namespace ext */