Skip to content
Snippets Groups Projects
memory.hpp 7.89 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jan Trávníček's avatar
    Jan Trávníček committed
    /*
     * memoru.hpp
     *
     * 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"
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < typename T, typename Enable = void >
    
    class cow_shared_ptr;
    
    class cow_shared_ptr_base {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	cow_shared_ptr_base ( ) : m_UseCount ( 0 ) { }
    
    private:
    	int m_UseCount;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	template < typename T, typename Enable >
    	friend class cow_shared_ptr;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    class cow_shared_ptr < T, typename std::enable_if < std::is_base_of < cow_shared_ptr_base, T >::value >::type > {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit cow_shared_ptr ( ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit cow_shared_ptr ( T * data ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( data ) data->m_UseCount = 0;
    
    
    	cow_shared_ptr ( const cow_shared_ptr & other ) {
    
    		attach ( other.m_Data );
    	}
    
    
    	cow_shared_ptr ( cow_shared_ptr && other ) noexcept {
    
    		m_Data = other.m_Data;
    		other.m_Data = NULL;
    	}
    
    	~cow_shared_ptr ( ) noexcept {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    	cow_shared_ptr & operator =( const cow_shared_ptr & other ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( this == & other ) return * this;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    		attach ( other.m_Data );
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * this;
    
    	cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		swap ( * this, other );
    		return * this;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * operator ->( ) {
    		make_unique ( );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const * operator ->( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T & operator *( ) {
    		make_unique ( );
    		return * m_Data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const & operator *( ) const {
    		return * m_Data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * get ( ) {
    		make_unique ( );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const * get ( ) const {
    
    		return m_Data;
    	}
    
    	bool unique ( ) const {
    		return m_Data == NULL || m_Data->m_UseCount == 1;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	int getUseCount ( ) const {
    		if ( m_Data == NULL ) return 0;
    
    
    	explicit operator bool( ) const {
    		return getUseCount ( ) == 0;
    	}
    
    
    private:
    	void attach ( T * data ) {
    		m_Data = data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    
    		if ( m_Data ) m_Data->m_UseCount++;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void detach ( ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void make_unique ( ) {
    		if ( unique ( ) ) return;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		T * tmp = m_Data;
    		detach ( );
    		tmp = std::clone ( tmp );
    
    		tmp->m_UseCount = 0;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		attach ( tmp );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * m_Data;
    
    
    	friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		T * tmp = first.m_Data;
    
    		first.m_Data = second.m_Data;
    
    		second.m_Data = tmp;
    	}
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    class cow_shared_ptr < T, typename std::enable_if < !std::is_base_of < cow_shared_ptr_base, T >::value >::type > {
    
    	struct cow_shared_ptr_data {
    		T * m_Data;
    		int m_UseCount;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		cow_shared_ptr_data ( T * data ) : m_Data ( data ), m_UseCount ( 0 ) { }
    
    		~cow_shared_ptr_data ( ) {
    			delete m_Data;
    		}
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit cow_shared_ptr ( ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit cow_shared_ptr ( T * data ) {
    
    		attach ( data ? new cow_shared_ptr_data ( data ) : NULL );
    
    	cow_shared_ptr ( const cow_shared_ptr & other ) {
    
    		attach ( other.m_Data );
    	}
    
    
    	cow_shared_ptr ( cow_shared_ptr && other ) noexcept {
    
    		m_Data = other.m_Data;
    		other.m_Data = NULL;
    
    	}
    
    	~cow_shared_ptr ( ) noexcept {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    	cow_shared_ptr & operator =( const cow_shared_ptr & other ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( this == & other ) return * this;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    		attach ( other.m_Data );
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * this;
    
    	cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		swap ( * this, other );
    		return * this;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * operator ->( ) {
    		make_unique ( );
    
    		return m_Data->m_Data;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const * operator ->( ) const {
    
    		return m_Data->m_Data;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T & operator *( ) {
    		make_unique ( );
    		return * ( m_Data->m_Data );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const & operator *( ) const {
    		return * ( m_Data->m_Data );
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T * get ( ) {
    		make_unique ( );
    
    		return m_Data->m_Data;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	T const * get ( ) const {
    
    		return m_Data->m_Data;
    	}
    
    	bool unique ( ) const {
    
    		return m_Data == NULL || m_Data->m_UseCount == 1;
    
    	int getUseCount ( ) const {
    		if ( m_Data == NULL ) return 0;
    
    		return m_Data->m_UseCount;
    	}
    
    	explicit operator bool( ) const {
    		return getUseCount ( ) == 0;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void attach ( typename cow_shared_ptr < T >::cow_shared_ptr_data * data ) {
    
    		m_Data = data;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    
    		if ( m_Data ) m_Data->m_UseCount++;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void detach ( ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	void make_unique ( ) {
    		if ( unique ( ) ) return;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = m_Data;
    		detach ( );
    		attach ( new cow_shared_ptr_data ( std::clone ( tmp->m_Data ) ) );
    
    	}
    
    	cow_shared_ptr_data * m_Data;
    
    
    	friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		typename cow_shared_ptr < T >::cow_shared_ptr_data * tmp = first.m_Data;
    
    		first.m_Data = second.m_Data;
    
    		second.m_Data = tmp;
    	}
    
    template < class T >
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    class smart_ptr {
    	T * m_Data;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit smart_ptr ( ) : m_Data ( NULL ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit smart_ptr ( T * data ) : m_Data ( data ) {
    
    	template < class R >
    	smart_ptr ( smart_ptr < R > other ) : m_Data ( other.release ( ) ) {
    	}
    
    
    	smart_ptr ( const smart_ptr & other ) : m_Data ( std::clone ( other.m_Data ) ) {
    
    	smart_ptr ( smart_ptr && other ) noexcept : m_Data ( other.release ( ) ) {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	}
    
    	~smart_ptr ( ) noexcept {
    		delete m_Data;
    	}
    
    
    	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 = std::clone ( other.m_Data );
    
    		return * this;
    	}
    
    
    	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;
    	}
    
    	T * operator ->( ) {
    		return m_Data;
    	}
    
    
    	T * operator ->( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return m_Data;
    	}
    
    	T & operator *( ) {
    		return * m_Data;
    	}
    
    
    	T & operator *( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return * m_Data;
    	}
    
    	T * get ( ) {
    		return m_Data;
    	}
    
    
    	T * get ( ) const {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return m_Data;
    	}
    
    
    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;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	explicit operator bool( ) const {
    		return m_Data;
    	}
    
    };
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    
    std::ostream & operator <<( std::ostream & out, const std::cow_shared_ptr < T > & ptr ) {
    	out << * ptr;
    	return out;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    
    std::ostream & operator <<( std::ostream & out, const std::shared_ptr < T > & ptr ) {
    	out << * ptr;
    	return out;
    }
    
    template < class T >
    std::ostream & operator <<( std::ostream & out, const std::unique_ptr < T > & ptr ) {
    	out << * ptr;
    	return out;
    }
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    template < class T >
    std::ostream & operator <<( std::ostream & out, const std::smart_ptr < T > & ptr ) {
    	out << * ptr;
    	return out;
    }
    
    
    template < class T >
    struct compare < cow_shared_ptr < T > > {
    	int operator ()( const cow_shared_ptr < T > & first, const 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 );
    	}
    
    };
    
    template < class T >
    
    struct compare < std::shared_ptr < T > > {
    	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 );
    	}
    
    };
    
    template < class T >
    
    struct compare < std::unique_ptr < T > > {
    	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 );
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    };
    
    template < class T >
    struct compare < smart_ptr < T > > {
    	int operator ()( const smart_ptr < T > & first, const 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;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		return comp ( * first, * second );
    	}
    
    
    } /* namespace std */
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    #endif /* __MEMORY_HPP_ */