/* $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 */