yapf/autocopyptr.hpp
changeset 3900 4984308f9125
child 4434 4175805666a5
equal deleted inserted replaced
3899:4c5b1de6cb17 3900:4984308f9125
       
     1 /* $Id$ */
       
     2 
       
     3 #ifndef  AUTOCOPYPTR_HPP
       
     4 #define  AUTOCOPYPTR_HPP
       
     5 
       
     6 /** CAutoCopyPtrT - kind of CoW (Copy on Write) pointer.
       
     7 		It is non-invasive smart pointer (reference counter is held outside
       
     8 		of Tdata).
       
     9 		When copied, its new copy shares the same underlaying structure Tdata.
       
    10 		When dereferenced, its behavior depends on 2 factors:
       
    11 		   - whether the data is shared (used by more than one pointer)
       
    12 		   - type of access (read/write)
       
    13 		  When shared pointer is dereferenced for write, new clone of Tdata
       
    14 		is made first.
       
    15 		Can't be used for polymorphic data types (interfaces).
       
    16 */
       
    17 template <class Tdata_>
       
    18 class CAutoCopyPtrT {
       
    19 protected:
       
    20 	typedef Tdata_ Tdata;
       
    21 
       
    22 	struct CItem	{
       
    23 		int     m_ref_cnt;  ///< reference counter
       
    24 		Tdata   m_data;     ///< custom data itself
       
    25 
       
    26 		FORCEINLINE CItem()                  : m_ref_cnt(1)                     {};
       
    27 		FORCEINLINE CItem(const Tdata& data) : m_ref_cnt(1), m_data(data)       {};
       
    28 		FORCEINLINE CItem(const CItem& src)  : m_ref_cnt(1), m_data(src.m_data) {};
       
    29 	};
       
    30 
       
    31 	mutable CItem* m_pI; ///< points to the ref-counted data
       
    32 
       
    33 public:
       
    34 	FORCEINLINE CAutoCopyPtrT() : m_pI(NULL) {};
       
    35 	FORCEINLINE CAutoCopyPtrT(const Tdata& data) : m_pI(new CItem(data)) {};
       
    36 	FORCEINLINE CAutoCopyPtrT(const CAutoCopyPtrT& src) : m_pI(src.m_pI) {if (m_pI != NULL) m_pI->m_ref_cnt++;}
       
    37 	FORCEINLINE ~CAutoCopyPtrT() {if (m_pI == NULL || (--m_pI->m_ref_cnt) > 0) return; delete m_pI; m_pI = NULL;}
       
    38 
       
    39 	/** data accessor (read only) */
       
    40 	FORCEINLINE const Tdata& GetDataRO() const {if (m_pI == NULL) m_pI = new CItem(); return m_pI->m_data;}
       
    41 	/** data accessor (read / write) */
       
    42 	FORCEINLINE Tdata& GetDataRW() {CloneIfShared(); if (m_pI == NULL) m_pI = new CItem(); return m_pI->m_data;}
       
    43 
       
    44 	/** clone data if it is shared */
       
    45 	FORCEINLINE void CloneIfShared()
       
    46 	{
       
    47 		if (m_pI != NULL && m_pI->m_ref_cnt > 1) {
       
    48 			// we share data item with somebody, clone it to become an exclusive owner
       
    49 			CItem* pNewI = new CItem(*m_pI);
       
    50 			m_pI->m_ref_cnt--;
       
    51 			m_pI = pNewI;
       
    52 		}
       
    53 	}
       
    54 
       
    55 	/** assign pointer from the other one (maintaining ref counts) */
       
    56 	FORCEINLINE void Assign(const CAutoCopyPtrT& src)
       
    57 	{
       
    58 		if (m_pI == src.m_pI) return;
       
    59 		if (m_pI != NULL && (--m_pI->m_ref_cnt) <= 0) delete m_pI;
       
    60 		m_pI = src.m_pI;
       
    61 		if (m_pI != NULL) m_pI->m_ref_cnt++;
       
    62 	}
       
    63 
       
    64 	/** dereference operator (read only) */
       
    65 	FORCEINLINE const Tdata* operator -> () const {return &GetDataRO();}
       
    66 	/** dereference operator (read / write) */
       
    67 	FORCEINLINE Tdata* operator -> () {return &GetDataRW();}
       
    68 
       
    69 	/** assignment operator */
       
    70 	FORCEINLINE CAutoCopyPtrT& operator = (const CAutoCopyPtrT& src) {Assign(src); return *this;}
       
    71 
       
    72 	/** forwarding 'lower then' operator to the underlaying items */
       
    73 	FORCEINLINE bool operator < (const CAutoCopyPtrT& other) const
       
    74 	{
       
    75 		assert(m_pI != NULL);
       
    76 		assert(other.m_pI != NULL);
       
    77 		return (m_pI->m_data) < (other.m_pI->m_data);
       
    78 	}
       
    79 };
       
    80 
       
    81 
       
    82 #endif /* AUTOCOPYPTR_HPP */