/* * memoru.hpp * * Created on: May 1, 2015 * Author: Jan Travnicek */ #ifndef __MEMORY_HPP_ #define __MEMORY_HPP_ namespace std { template < typename T, typename Enable = void > class cow_shared_ptr; class cow_shared_ptr_base { public: cow_shared_ptr_base ( ) : m_UseCount ( 0 ) { } private: int m_UseCount; template < typename T, typename Enable > friend class cow_shared_ptr; }; template < class T > class cow_shared_ptr < T, typename std::enable_if < std::is_base_of < cow_shared_ptr_base, T >::value >::type > { public: explicit cow_shared_ptr ( ) { attach ( NULL ); } explicit cow_shared_ptr ( T * data ) { if ( data ) data->m_UseCount = 0; attach ( data ); } 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 { detach ( ); } cow_shared_ptr & operator =( const cow_shared_ptr & other ) { if ( this == & other ) return * this; detach ( ); attach ( other.m_Data ); return * this; } cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept { swap ( * this, other ); return * this; } T * operator ->( ) { make_unique ( ); return m_Data; } T const * operator ->( ) const { return m_Data; } T & operator *( ) { make_unique ( ); return * m_Data; } T const & operator *( ) const { return * m_Data; } T * get ( ) { make_unique ( ); return m_Data; } T const * get ( ) const { return 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; } private: void attach ( T * data ) { m_Data = data; if ( m_Data ) m_Data->m_UseCount++; } void detach ( ) { if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data; m_Data = NULL; } void make_unique ( ) { if ( unique ( ) ) return; T * tmp = m_Data; detach ( ); tmp = std::clone ( tmp ); tmp->m_UseCount = 0; attach ( tmp ); } T * m_Data; friend void swap ( cow_shared_ptr & first, cow_shared_ptr & second ) { T * tmp = first.m_Data; first.m_Data = second.m_Data; second.m_Data = tmp; } }; 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; cow_shared_ptr_data ( T * data ) : m_Data ( data ), m_UseCount ( 0 ) { } ~cow_shared_ptr_data ( ) { delete m_Data; } }; public: explicit cow_shared_ptr ( ) { attach ( NULL ); } 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 { detach ( ); } cow_shared_ptr & operator =( const cow_shared_ptr & other ) { if ( this == & other ) return * this; detach ( ); attach ( other.m_Data ); return * this; } cow_shared_ptr & operator =( cow_shared_ptr && other ) noexcept { swap ( * this, other ); return * this; } T * operator ->( ) { make_unique ( ); return m_Data->m_Data; } T const * operator ->( ) const { return m_Data->m_Data; } T & operator *( ) { make_unique ( ); return * ( m_Data->m_Data ); } T const & operator *( ) const { return * ( m_Data->m_Data ); } T * get ( ) { make_unique ( ); return m_Data->m_Data; } 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; } private: void attach ( typename cow_shared_ptr < T >::cow_shared_ptr_data * data ) { m_Data = data; if ( m_Data ) m_Data->m_UseCount++; } void detach ( ) { if ( m_Data && ( --( m_Data->m_UseCount ) <= 0 ) ) delete m_Data; m_Data = NULL; } void make_unique ( ) { if ( unique ( ) ) return; 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 ) { 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 > class smart_ptr { T * m_Data; public: explicit smart_ptr ( ) : m_Data ( NULL ) { } 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 ( ) ) { } ~smart_ptr ( ) noexcept { delete m_Data; } smart_ptr & operator =( const smart_ptr & other ) { if ( this == & other ) return * this; delete m_Data; m_Data = std::clone ( other.m_Data ); return * this; } smart_ptr & operator =( smart_ptr && other ) noexcept { swap ( this->m_Data, other.m_Data ); return * this; } T * operator ->( ) { return m_Data; } T * operator ->( ) const { return m_Data; } T & operator *( ) { return * m_Data; } T & operator *( ) const { return * m_Data; } T * get ( ) { return m_Data; } T * get ( ) const { return m_Data; } T * release ( ) { T * res = m_Data; m_Data = nullptr; return res; } explicit operator bool( ) const { return m_Data; } }; template < class T > std::ostream & operator <<( std::ostream & out, const std::cow_shared_ptr < T > & ptr ) { out << * ptr; return out; } 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; } 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; compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; template < class T > struct compare < shared_ptr < T > > { int operator ()( const shared_ptr < T > & first, const shared_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; if ( !first ) return -1; if ( !second ) return 1; compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; template < class T > struct compare < unique_ptr < T > > { int operator ()( const unique_ptr < T > & first, const unique_ptr < T > & second ) const { if ( first.get ( ) == second.get ( ) ) return 0; if ( !first ) return -1; if ( !second ) return 1; compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; 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; compare < typename std::decay < T >::type > comp; return comp ( * first, * second ); } }; // TODO remove after switching to c++14 template < typename T, typename ... Args > std::unique_ptr < T > make_unique ( Args && ... args ) { return std::unique_ptr < T > ( new T ( std::forward < Args > ( args ) ... ) ); } template < typename T, typename ... Args > std::smart_ptr < T > make_smart ( Args && ... args ) { return std::smart_ptr < T > ( new T ( std::forward < Args > ( args ) ... ) ); } } /* namespace std */ #endif /* __MEMORY_HPP_ */