#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: cow_shared_ptr ( ) { attach ( NULL ); } cow_shared_ptr ( T * data ) { if ( data ) data->m_UseCount = 0; attach ( data ); } cow_shared_ptr ( const cow_shared_ptr < T > & other ) { attach ( other.m_Data ); } cow_shared_ptr ( cow_shared_ptr < T > && other ) noexcept { m_Data = other.m_Data; other.m_Data = NULL; } ~cow_shared_ptr ( ) noexcept { detach ( ); } cow_shared_ptr < T > & operator =( const cow_shared_ptr < T > & other ) { if ( this == & other ) return * this; detach ( ); attach ( other.m_Data ); return * this; } cow_shared_ptr < T > & operator =( cow_shared_ptr < T > && 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; } 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 < T > & first, cow_shared_ptr < T > & 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: cow_shared_ptr ( ) { attach ( NULL ); } cow_shared_ptr ( T * data ) { attach ( new cow_shared_ptr_data ( data ) ); } cow_shared_ptr ( const cow_shared_ptr < T > & other ) { attach ( other.m_Data ); } cow_shared_ptr ( cow_shared_ptr < T > && other ) noexcept { m_Data = other.m_Data; other.m_Data = NULL; } ~cow_shared_ptr ( ) noexcept { detach ( ); } cow_shared_ptr < T > & operator =( const cow_shared_ptr < T > & other ) { if ( this == & other ) return * this; detach ( ); attach ( other.m_Data ); return * this; } cow_shared_ptr < T > & operator =( cow_shared_ptr < T > && 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; } 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 < T > & first, cow_shared_ptr < T > & 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 > const cow_shared_ptr < T > & make_const ( cow_shared_ptr < T > & ptr ) { return static_cast < const cow_shared_ptr < T > & > ( ptr ); } template < class T > const cow_shared_ptr < T > & make_const ( const cow_shared_ptr < T > & ptr ) { return ptr; } } /* namespace std */ #endif // _MEMORY_HPP__