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