lean cpp library
A lean C++ library providing efficient utility classes for high-performance C++ applications.
|
00001 /*****************************************************/ 00002 /* lean Smart (c) Tobias Zirr 2011 */ 00003 /*****************************************************/ 00004 00005 #ifndef LEAN_SMART_REF_COUNTER 00006 #define LEAN_SMART_REF_COUNTER 00007 00008 #include <memory> 00009 #include "../lean.h" 00010 #include "../concurrent/atomic.h" 00011 00012 namespace lean 00013 { 00014 namespace smart 00015 { 00016 00018 template < class Counter = long, class Allocator = std::allocator<Counter> > 00019 class ref_counter 00020 { 00021 public: 00023 class ref_counts 00024 { 00025 private: 00026 // Allocator 00027 typedef typename Allocator::template rebind<ref_counts>::other allocator_type_; 00028 allocator_type_ m_allocator; 00029 00030 protected: 00032 ref_counts(const allocator_type_& allocator, Counter references, Counter weakReferences) 00033 : m_allocator(allocator), 00034 references(references), 00035 weakReferences(weakReferences) { }; 00036 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00037 00038 ref_counts(allocator_type_&& allocator, Counter references, Counter weakReferences) 00039 : m_allocator(::std::move(allocator)), 00040 references(references), 00041 weakReferences(weakReferences) { }; 00042 #endif 00043 #ifndef LEAN_OPTIMIZE_DEFAULT_DESTRUCTOR 00044 // Destructor. 00045 ~ref_counts() throw() { }; 00046 #endif 00047 public: 00049 typedef allocator_type_ allocator_type; 00050 00052 Counter references; 00053 00055 Counter weakReferences; 00056 00058 static ref_counts* create(allocator_type allocator, Counter references, Counter weakReferences) 00059 { 00060 ref_counts *counts = allocator.allocate(1); 00061 00062 try 00063 { 00064 new (counts) ref_counts(allocator, references, weakReferences); 00065 } 00066 catch (...) 00067 { 00068 allocator.deallocate(counts, 1); 00069 throw; 00070 } 00071 00072 return counts; 00073 } 00074 00076 static void destroy(const ref_counts *counts) 00077 { 00078 LEAN_ASSERT(counts); 00079 00080 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00081 allocator_type allocator(::std::move(counts->m_allocator)); 00082 #else 00083 allocator_type allocator(counts->m_allocator); 00084 #endif 00085 counts->~ref_counts(); 00086 allocator.deallocate(const_cast<ref_counts*>(counts), 1); 00087 } 00088 }; 00089 00090 // Reference counts 00091 ref_counts *m_counts; 00092 00094 static ref_counts* acquire(ref_counts *counts) 00095 { 00096 if (counts) 00097 atomic_increment(counts->weakReferences); 00098 00099 return counts; 00100 } 00101 00103 void release(ref_counts *counts) 00104 { 00105 // Clean up, if this is the last reference 00106 if (counts && !atomic_decrement(counts->weakReferences)) 00107 ref_counts::destroy(counts); 00108 } 00109 00111 explicit ref_counter(ref_counts *counts) 00112 : m_counts(counts) { } 00113 00114 public: 00116 typedef Counter counter_type; 00118 typedef Allocator allocator_type; 00119 00121 explicit ref_counter(counter_type references = 1) 00122 : m_counts( ref_counts::create(typename ref_counts::allocator_type(), references, 1) ) { } 00124 explicit ref_counter(allocator_type allocator) 00125 : m_counts( ref_counts::create(allocator, 1, 1) ) { } 00127 ref_counter(counter_type references, allocator_type allocator) 00128 : m_counts( ref_counts::create(allocator, references, 1) ) { } 00130 ref_counter(const ref_counter& refCounter) 00131 : m_counts( acquire(refCounter.m_counts) ) { } 00132 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00133 00134 ref_counter(ref_counter&& refCounter) 00135 : m_counts(std::move(refCounter.m_counts)) 00136 { 00137 // Warning: this effectively "breaks" the other object 00138 refCounter.m_counts = nullptr; 00139 } 00140 #endif 00141 00142 ~ref_counter() throw() 00143 { 00144 release(m_counts); 00145 } 00146 00148 static LEAN_INLINE ref_counter null() 00149 { 00150 // Warning: this object is effectively "broken" 00151 return ref_counter(nullptr); 00152 } 00153 00155 ref_counter& operator =(const ref_counter& refCounter) 00156 { 00157 // Don't re-assign the same 00158 if(m_counts != refCounter.m_counts) 00159 { 00160 ref_counts *prevReferences = m_counts; 00161 m_counts = acquire(refCounter.m_counts); 00162 release(prevReferences); 00163 } 00164 00165 return *this; 00166 } 00167 #ifndef LEAN0X_NO_RVALUE_REFERENCES 00168 00169 ref_counter& operator =(ref_counter&& refCounter) 00170 { 00171 // Don't re-assign the same 00172 if(m_counts != refCounter.m_counts) 00173 { 00174 ref_counts *prevReferences = m_counts; 00175 00176 m_counts = ::std::move(refCounter.m_counts); 00177 // Warning: this effectively "breaks" the other object 00178 refCounter.m_counts = nullptr; 00179 00180 release(prevReferences); 00181 } 00182 00183 return *this; 00184 } 00185 #endif 00186 00188 bool increment_checked() const 00189 { 00190 LEAN_ASSERT(m_counts); 00191 00192 for (;;) 00193 { 00194 Counter references = (volatile Counter&)m_counts->references; 00195 00196 // Make sure reference count has not become 0 yet 00197 if (references < 1) 00198 return false; 00199 // Make sure value has not changed until it has successfully been updated 00200 else if (atomic_test_and_set(m_counts->references, references, references + 1)) 00201 return true; 00202 } 00203 00204 LEAN_ASSERT(0); 00205 } 00207 counter_type increment() const 00208 { 00209 LEAN_ASSERT(m_counts); 00210 00211 return atomic_increment(m_counts->references); 00212 } 00214 counter_type decrement() const 00215 { 00216 LEAN_ASSERT(m_counts); 00217 00218 return atomic_decrement(m_counts->references); 00219 } 00220 00222 LEAN_INLINE bool is_null() { return (m_counts == nullptr); } 00223 00225 LEAN_INLINE counter_type count() const { LEAN_ASSERT(m_counts); return m_counts->references; }; 00227 LEAN_INLINE bool valid() const { LEAN_ASSERT(m_counts); return (m_counts->references > 0); }; 00228 00230 LEAN_INLINE counter_type weak_count() const { LEAN_ASSERT(m_counts); return m_counts->weakReferences; }; 00231 00233 LEAN_INLINE ref_counter& operator ++() { ++const_cast<const ref_counter&>(*this); return *this; }; 00235 LEAN_INLINE const ref_counter& operator ++() const { increment(); return *this; }; 00237 LEAN_INLINE ref_counter& operator --() { --const_cast<const ref_counter&>(*this); return *this; }; 00239 LEAN_INLINE const ref_counter& operator --() const { decrement(); return *this; }; 00241 LEAN_INLINE counter_type operator ++(int) const { counter_type prevCount = count(); ++(*this); return prevCount; }; 00243 LEAN_INLINE counter_type operator --(int) const { counter_type prevCount = count(); --(*this); return prevCount;}; 00244 00246 LEAN_INLINE operator counter_type() const { return count(); }; 00248 LEAN_INLINE operator bool() const { return valid(); }; 00249 }; 00250 00251 } // namespace 00252 00253 using smart::ref_counter; 00254 00255 } // namespace 00256 00257 #endif