83 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			83 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* $Id$ */
 | |
| 
 | |
| #ifndef  AUTOCOPYPTR_HPP
 | |
| #define  AUTOCOPYPTR_HPP
 | |
| 
 | |
| /** CAutoCopyPtrT - kind of CoW (Copy on Write) pointer.
 | |
| 		It is non-invasive smart pointer (reference counter is held outside
 | |
| 		of Tdata).
 | |
| 		When copied, its new copy shares the same underlaying structure Tdata.
 | |
| 		When dereferenced, its behavior depends on 2 factors:
 | |
| 		   - whether the data is shared (used by more than one pointer)
 | |
| 		   - type of access (read/write)
 | |
| 		  When shared pointer is dereferenced for write, new clone of Tdata
 | |
| 		is made first.
 | |
| 		Can't be used for polymorphic data types (interfaces).
 | |
| */
 | |
| template <class Tdata_>
 | |
| class CAutoCopyPtrT {
 | |
| protected:
 | |
| 	typedef Tdata_ Tdata;
 | |
| 
 | |
| 	struct CItem {
 | |
| 		int     m_ref_cnt;  ///< reference counter
 | |
| 		Tdata   m_data;     ///< custom data itself
 | |
| 
 | |
| 		FORCEINLINE CItem()                  : m_ref_cnt(1)                     {};
 | |
| 		FORCEINLINE CItem(const Tdata& data) : m_ref_cnt(1), m_data(data)       {};
 | |
| 		FORCEINLINE CItem(const CItem& src)  : m_ref_cnt(1), m_data(src.m_data) {};
 | |
| 	};
 | |
| 
 | |
| 	mutable CItem* m_pI; ///< points to the ref-counted data
 | |
| 
 | |
| public:
 | |
| 	FORCEINLINE CAutoCopyPtrT() : m_pI(NULL) {};
 | |
| 	FORCEINLINE CAutoCopyPtrT(const Tdata& data) : m_pI(new CItem(data)) {};
 | |
| 	FORCEINLINE CAutoCopyPtrT(const CAutoCopyPtrT& src) : m_pI(src.m_pI) {if (m_pI != NULL) m_pI->m_ref_cnt++;}
 | |
| 	FORCEINLINE ~CAutoCopyPtrT() {if (m_pI == NULL || (--m_pI->m_ref_cnt) > 0) return; delete m_pI; m_pI = NULL;}
 | |
| 
 | |
| 	/** data accessor (read only) */
 | |
| 	FORCEINLINE const Tdata& GetDataRO() const {if (m_pI == NULL) m_pI = new CItem(); return m_pI->m_data;}
 | |
| 	/** data accessor (read / write) */
 | |
| 	FORCEINLINE Tdata& GetDataRW() {CloneIfShared(); if (m_pI == NULL) m_pI = new CItem(); return m_pI->m_data;}
 | |
| 
 | |
| 	/** clone data if it is shared */
 | |
| 	FORCEINLINE void CloneIfShared()
 | |
| 	{
 | |
| 		if (m_pI != NULL && m_pI->m_ref_cnt > 1) {
 | |
| 			// we share data item with somebody, clone it to become an exclusive owner
 | |
| 			CItem* pNewI = new CItem(*m_pI);
 | |
| 			m_pI->m_ref_cnt--;
 | |
| 			m_pI = pNewI;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	/** assign pointer from the other one (maintaining ref counts) */
 | |
| 	FORCEINLINE void Assign(const CAutoCopyPtrT& src)
 | |
| 	{
 | |
| 		if (m_pI == src.m_pI) return;
 | |
| 		if (m_pI != NULL && (--m_pI->m_ref_cnt) <= 0) delete m_pI;
 | |
| 		m_pI = src.m_pI;
 | |
| 		if (m_pI != NULL) m_pI->m_ref_cnt++;
 | |
| 	}
 | |
| 
 | |
| 	/** dereference operator (read only) */
 | |
| 	FORCEINLINE const Tdata* operator -> () const {return &GetDataRO();}
 | |
| 	/** dereference operator (read / write) */
 | |
| 	FORCEINLINE Tdata* operator -> () {return &GetDataRW();}
 | |
| 
 | |
| 	/** assignment operator */
 | |
| 	FORCEINLINE CAutoCopyPtrT& operator = (const CAutoCopyPtrT& src) {Assign(src); return *this;}
 | |
| 
 | |
| 	/** forwarding 'lower then' operator to the underlaying items */
 | |
| 	FORCEINLINE bool operator < (const CAutoCopyPtrT& other) const
 | |
| 	{
 | |
| 		assert(m_pI != NULL);
 | |
| 		assert(other.m_pI != NULL);
 | |
| 		return (m_pI->m_data) < (other.m_pI->m_data);
 | |
| 	}
 | |
| };
 | |
| 
 | |
| 
 | |
| #endif /* AUTOCOPYPTR_HPP */
 | 
