Skip to content
Snippets Groups Projects
memory.hpp 14.8 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jan Trávníček's avatar
    Jan Trávníček committed
    /*
    
     * memory.hpp
    
    Jan Trávníček's avatar
    Jan Trávníček committed
     *
    
     * 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/>.
     *
    
    Jan Trávníček's avatar
    Jan Trávníček committed
     * 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"
    
    
    /**
     * \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
     */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    
    class cow_shared_ptr : std::shared_ptr < T > {
    
    	/**
    	 * \brief
    	 * Default initialization to 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 ) : std::shared_ptr < T > ( 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 ) : std::shared_ptr < T > ( other ) {
    
    	/**
    	 * \brief
    	 * Copy version of user conversion constructor to create new instance of shared pointer reffering the same data.
    	 *
    	 * \param other the source instance
    	 */
    	template < class Y >
    	cow_shared_ptr ( const cow_shared_ptr < Y > & other ) : std::shared_ptr < T > ( other ) {
    	}
    
    
    	/**
    	 * \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 : std::shared_ptr < T > ( std::move ( other ) ) {
    
    	/**
    	 * \brief
    	 * Move version of user conversion constructor to create new instance of shared pointer reffering the same data.
    	 *
    	 * \param other the source instance
    	 */
    	template < class Y >
    	cow_shared_ptr ( cow_shared_ptr < Y > && other ) noexcept : std::shared_ptr < T > ( std::move ( other ) ) {
    	}
    
    
    	/**
    	 * \brief
    	 * The destructor of the shared pointer.
    	 */
    
    	~cow_shared_ptr ( ) noexcept {
    	}
    
    
    	/**
    	 * \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 ) {
    
    		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < const std::shared_ptr < T > & > ( other );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * this;
    
    	/**
    	 * \brief
    	 * Copy version of user conversion assignment operator to change reffered instace to source one.
    	 *
    	 * \param other the source instance
    	 */
    	template < class Y >
    	cow_shared_ptr & operator =( const cow_shared_ptr < Y > & other ) {
    		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < const std::shared_ptr < T > & > ( other );
    		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 {
    
    		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < std::shared_ptr < T > && > ( other );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * this;
    
    	/**
    	 * \brief
    	 * Move version of user conversion assignment operator to change reffered instace to source one.
    	 *
    	 * \param other the source instance
    	 */
    	template < class Y >
    	cow_shared_ptr & operator =( cow_shared_ptr < Y > && other ) noexcept {
    		static_cast < std::shared_ptr < T > & > ( * this ) = static_cast < std::shared_ptr < T > && > ( other );
    		return * this;
    	}
    
    	/**
    	 * \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
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * operator ->( ) {
    
    		return this->get ( );
    
    	/**
    	 * \brief
    	 * Operator arrow to chain dereferece to inner managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const * operator ->( ) const {
    
    		return this->get ( );
    
    	/**
    	 * \brief
    	 * Operator dereference to access the inner managed pointer.
    	 *
    	 * \return reference to managed data
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T & operator *( ) {
    
    		return * this->get ( );
    
    	/**
    	 * \brief
    	 * Operator dereference to access the inner managed pointer.
    	 *
    	 * \return reference to managed data
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const & operator *( ) const {
    
    		return * this->get ( );
    
    	/**
    	 * Getter of the raw managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * get ( ) {
    		make_unique ( );
    
    		return std::shared_ptr < T >::get ( );
    
    	/**
    	 * Getter of the raw managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	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;
    
    	/**
    	 * \brief
    	 * Ensures the managed pointer is unique by copy constructing the managed instance if needed.
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void make_unique ( ) {
    		if ( unique ( ) ) return;
    
    		static_cast < std::shared_ptr < T > & > ( * this ) = std::shared_ptr < T > ( ext::clone ( * std::shared_ptr < T >::get ( ) ) );
    
    	/**
    	 * \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 >
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    class smart_ptr {
    
    	/**
    	 * \brief
    	 * Pointer to managed object.
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * m_Data;
    
    
    	/**
    	 * \brief
    	 * Default initialization to null.
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit smart_ptr ( ) : m_Data ( NULL ) {
    
    	/**
    	 * \brief
    	 * Constructor which takes ownership of the provided pointer.
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	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.
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	~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 ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( this == & other ) return * this;
    
    		delete m_Data;
    
    		m_Data = ext::clone ( * other.m_Data );
    
    	/**
    	 * \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 {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		swap ( this->m_Data, other.m_Data );
    		return * this;
    	}
    
    
    	/**
    	 * \brief
    	 * Operator arrow to chain dereferece to inner managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * operator ->( ) {
    		return m_Data;
    	}
    
    
    	/**
    	 * \brief
    	 * Operator arrow to chain dereferece to inner managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    	T * operator ->( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return m_Data;
    	}
    
    
    	/**
    	 * \brief
    	 * Operator dereference to access the inner managed pointer.
    	 *
    	 * \return reference to managed data
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T & operator *( ) {
    		return * m_Data;
    	}
    
    
    	/**
    	 * \brief
    	 * Operator dereference to access the inner managed pointer.
    	 *
    	 * \return reference to managed data
    	 */
    
    	T & operator *( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * m_Data;
    	}
    
    
    	 * Getter of the raw managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * get ( ) {
    		return m_Data;
    	}
    
    
    	 * Getter of the raw managed pointer.
    	 *
    	 * \return the managed pointer
    	 */
    
    	T * get ( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return m_Data;
    	}
    
    
    	/**
    	 * \brief
    	 * Releases the shared resource and returns it.
    	 *
    	 * \return the released shared resource
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * release ( ) {
    		T * res = m_Data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		m_Data = nullptr;
    		return res;
    	}
    
    
    	 * Tests the instance whether the managed pointer is valid
    	 *
    	 * \return true if the managed pointer is not null, false otherwise
    	 */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit operator bool( ) const {
    
    		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
     */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    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
     */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    
    std::ostream & operator <<( std::ostream & out, const ext::smart_ptr < T > & ptr ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	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;
    
    		if ( !first ) return -1;
    
    		if ( !second ) return 1;
    
    
    		static compare < typename std::decay < T >::type > comp;
    
    		return comp ( * first, * second );
    	}
    
    };
    
    
     * 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;
    
    		if ( !first ) return -1;
    
    		if ( !second ) return 1;
    
    
    		static compare < typename std::decay < T >::type > comp;
    
    		return comp ( * first, * second );
    	}
    
    };
    
    
     * 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;
    
    		if ( !first ) return -1;
    
    		if ( !second ) return 1;
    
    
    		static compare < typename std::decay < T >::type > comp;
    
    		return comp ( * first, * second );
    	}
    
    
     * Specialisation of the compare structure implementing the three-way comparison
     *
     * \tparam T the type of managed resource inside the smart pointer
     */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    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 {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( first.get ( ) == second.get ( ) ) return 0;
    
    		if ( !first ) return -1;
    
    		if ( !second ) return 1;
    
    
    		static compare < typename std::decay < T >::type > comp;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return comp ( * first, * second );
    	}
    
    
    } /* namespace ext */
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    #endif /* __MEMORY_HPP_ */