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