Skip to content
Snippets Groups Projects
memory.hpp 4.43 KiB
Newer Older
  • Learn to ignore specific revisions
  • #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 {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    	}
    
    	cow_shared_ptr<T> & operator = ( const cow_shared_ptr<T> & other ) {
    		if(this == &other) return *this;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		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++;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	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;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		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 {
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		detach ( );
    
    	}
    
    	cow_shared_ptr<T> & operator = ( const cow_shared_ptr<T> & other ) {
    		if(this == &other) return *this;
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		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;
    
    	void attach ( typename cow_shared_ptr<T>::cow_shared_ptr_data * data ) {
    
    		m_Data = data;
    		if(m_Data) m_Data->m_UseCount++;
    	}
    
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    	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;
    
    Jan Trávníček's avatar
    Jan Trávníček committed
    		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__