summaryrefslogtreecommitdiff
path: root/yapf/autocopyptr.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'yapf/autocopyptr.hpp')
-rw-r--r--yapf/autocopyptr.hpp82
1 files changed, 82 insertions, 0 deletions
diff --git a/yapf/autocopyptr.hpp b/yapf/autocopyptr.hpp
new file mode 100644
index 000000000..2206ca00f
--- /dev/null
+++ b/yapf/autocopyptr.hpp
@@ -0,0 +1,82 @@
+/* $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 */