c++-gtk-utils
|
00001 /* Copyright (C) 2006, 2009 and 2011 Chris Vine 00002 00003 The library comprised in this file or of which this file is part is 00004 distributed by Chris Vine under the GNU Lesser General Public 00005 License as follows: 00006 00007 This library is free software; you can redistribute it and/or 00008 modify it under the terms of the GNU Lesser General Public License 00009 as published by the Free Software Foundation; either version 2.1 of 00010 the License, or (at your option) any later version. 00011 00012 This library is distributed in the hope that it will be useful, but 00013 WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 Lesser General Public License, version 2.1, for more details. 00016 00017 You should have received a copy of the GNU Lesser General Public 00018 License, version 2.1, along with this library (see the file LGPL.TXT 00019 which came with this source code package in the c++-gtk-utils 00020 sub-directory); if not, write to the Free Software Foundation, Inc., 00021 59 Temple Place - Suite 330, Boston, MA, 02111-1307, USA. 00022 00023 However, it is not intended that the object code of a program whose 00024 source code instantiates a template from this file or uses macros or 00025 inline functions (of any length) should by reason only of that 00026 instantiation or use be subject to the restrictions of use in the GNU 00027 Lesser General Public License. With that in mind, the words "and 00028 macros, inline functions and instantiations of templates (of any 00029 length)" shall be treated as substituted for the words "and small 00030 macros and small inline functions (ten lines or less in length)" in 00031 the fourth paragraph of section 5 of that licence. This does not 00032 affect any other reason why object code may be subject to the 00033 restrictions in that licence (nor for the avoidance of doubt does it 00034 affect the application of section 2 of that licence to modifications 00035 of the source code in this file). 00036 00037 */ 00038 00039 #ifndef CGU_INTRUSIVE_PTR_H 00040 #define CGU_INTRUSIVE_PTR_H 00041 00042 // define this if, instead of GLIB atomic funcions/memory barriers, 00043 // you want to use a (slower) mutex to lock the reference count in the 00044 // IntrusiveLockCounter class (however, if wanted, this is best left for 00045 // definition in the user code) 00046 /* #define CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 1 */ 00047 00048 #include <utility> // for std::move and std::swap 00049 #include <functional> // for std::less and std::hash<T*> 00050 #include <cstddef> // for std::size_t 00051 00052 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 00053 #include <c++-gtk-utils/mutex.h> 00054 #else 00055 #include <glib.h> 00056 #endif 00057 00058 #include <c++-gtk-utils/cgu_config.h> 00059 00060 /** 00061 * @addtogroup handles handles and smart pointers 00062 */ 00063 00064 namespace Cgu { 00065 00066 /** 00067 * @class IntrusivePtr intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h 00068 * @brief This is a smart pointer for managing objects allocated on 00069 * freestore which maintain their own reference count. 00070 * @ingroup handles 00071 * 00072 * @details This is a class which manages objects which maintain their 00073 * own reference count. It requires that the referenced object has 00074 * two functions called ref() and unref(), which increment and 00075 * decrement the reference count respectively. The IntrusiveCounter 00076 * or IntrusiveLockCounter class can be inherited from to do this, but 00077 * they do not have to be used. The IntrusiveLockCounter class is the 00078 * same as the IntrusiveCounter class, except that it locks the 00079 * reference count when it is incremented or decremented in order that 00080 * IntrusivePtr objects in different threads can access the same 00081 * object. (But only the reference count is locked, not the methods 00082 * of the referenced object.) 00083 * 00084 * All the constructors (including the constructor which takes a raw 00085 * pointer) increment the reference count, and the destructor 00086 * decrements it and expects the referenced object to be deleted when 00087 * the last IntrusivePtr referencing a particular object is destroyed. 00088 * The IntrusiveCounter and IntrusiveLockCounter classes behave in 00089 * this way. (This is different from the behaviour of GobjHandle 00090 * smart pointers, which are constrained by the GObject reference 00091 * counting system which begins with a reference count of 1 rather 00092 * than 0, and of course different from normal shared pointer 00093 * implementations for the same reason. The advantage of the approach 00094 * with IntrusivePtr is that an already-managed object may safely be 00095 * passed to the constructor taking a raw pointer without any 00096 * additional steps being necessary.) 00097 */ 00098 00099 template <class T> class IntrusivePtr { 00100 00101 T* obj_p; 00102 00103 void unreference() { 00104 if (obj_p) obj_p->unref(); 00105 } 00106 00107 void reference() { 00108 if (obj_p) obj_p->ref(); 00109 } 00110 00111 public: 00112 /** 00113 * This constructor does not throw. 00114 * @param ptr The object which the IntrusivePtr is to manage (if 00115 * any). 00116 */ 00117 explicit IntrusivePtr(T* ptr = 0) { 00118 obj_p = ptr; 00119 reference(); 00120 } 00121 00122 /** 00123 * This copy constructor does not throw. 00124 * @param intr_ptr The intrusive pointer to be copied. 00125 */ 00126 IntrusivePtr(const IntrusivePtr& intr_ptr) { 00127 obj_p = intr_ptr.obj_p; 00128 reference(); 00129 } 00130 00131 /** 00132 * The move constructor does not throw. It has move semantics. 00133 * @param intr_ptr The instrusive pointer to be moved. 00134 */ 00135 IntrusivePtr(IntrusivePtr&& intr_ptr) { 00136 obj_p = intr_ptr.obj_p; 00137 intr_ptr.obj_p = 0; 00138 } 00139 00140 template <class U> friend class IntrusivePtr; 00141 00142 /** 00143 * A version of the copy constructor which enables pointer type 00144 * conversion (assuming the type passed is implicitly type 00145 * convertible to the managed type, such as a derived type). This 00146 * copy constructor does not throw. 00147 * @param intr_ptr The intrusive pointer to be copied. 00148 */ 00149 template <class U> IntrusivePtr(const IntrusivePtr<U>& intr_ptr) { 00150 obj_p = intr_ptr.obj_p; 00151 reference(); 00152 } 00153 00154 /** 00155 * A version of the move constructor which enables pointer type 00156 * conversion (assuming the type passed is implicitly type 00157 * convertible to the managed type, such as a derived type). This 00158 * move constructor does not throw. 00159 * @param intr_ptr The intrusive pointer to be moved. 00160 */ 00161 template <class U> IntrusivePtr(IntrusivePtr<U>&& intr_ptr) { 00162 obj_p = intr_ptr.obj_p; 00163 intr_ptr.obj_p = 0; 00164 } 00165 00166 /** 00167 * This method (and so copy or move assignment) does not throw unless 00168 * the destructor of a managed object throws. 00169 * @param intr_ptr The assignee. 00170 * @return The IntrusivePtr object after assignment. 00171 */ 00172 // having a value type as the argument, rather than reference to const 00173 // and then initialising a tmp object, gives the compiler more scope 00174 // for optimisation, and also caters for r-values without a separate 00175 // overload 00176 IntrusivePtr& operator=(IntrusivePtr intr_ptr) { 00177 std::swap(obj_p, intr_ptr.obj_p); 00178 return *this; 00179 } 00180 00181 /** 00182 * A version of the assignment operator which enables pointer type 00183 * conversion (assuming the type passed is implicitly type 00184 * convertible to the managed type, such as a derived type). This 00185 * method does not throw unless the destructor of a managed object 00186 * throws. 00187 * @param intr_ptr The assignee. 00188 * @return The IntrusivePtr object after assignment. 00189 */ 00190 template <class U> IntrusivePtr& operator=(const IntrusivePtr<U>& intr_ptr) { 00191 return operator=(IntrusivePtr(intr_ptr)); 00192 } 00193 00194 /** 00195 * A version of the operator for move assignment which enables 00196 * pointer type conversion (assuming the type passed is implicitly 00197 * type convertible to the managed type, such as a derived type). 00198 * This method does not throw unless the destructor of a managed 00199 * object throws. 00200 * @param intr_ptr The intrusive pointer to be moved. 00201 * @return The IntrusivePtr object after the move operation. 00202 */ 00203 template <class U> IntrusivePtr& operator=(IntrusivePtr<U>&& intr_ptr) { 00204 return operator=(IntrusivePtr(std::move(intr_ptr))); 00205 } 00206 00207 /** 00208 * This method does not throw. 00209 * @return A pointer to the managed object (or NULL if none is 00210 * handled). 00211 */ 00212 T* get() const {return obj_p;} 00213 00214 /** 00215 * This method does not throw. 00216 * @return A reference to the managed object. 00217 */ 00218 T& operator*() const {return *obj_p;} 00219 00220 /** 00221 * This method does not throw. 00222 * @return A pointer to the managed object (or NULL if none is 00223 * handled). 00224 */ 00225 T* operator->() const {return obj_p;} 00226 00227 /** 00228 * Causes the intrusive pointer to cease to manage its managed 00229 * object, deleting it if this is the last intrusive pointer managing 00230 * it. If the argument passed is not NULL, the intrusive pointer 00231 * will manage the new object passed. This method does not throw 00232 * unless the destructor of a managed object throws. 00233 * @param ptr NULL (the default), or a new object to manage. 00234 */ 00235 void reset(T* ptr = 0) { 00236 IntrusivePtr tmp(ptr); 00237 std::swap(obj_p, tmp.obj_p); 00238 } 00239 00240 /** 00241 * The destructor does not throw unless the destructor of a managed 00242 * object throws - that should never happen. 00243 */ 00244 ~IntrusivePtr() {unreference();} 00245 }; 00246 00247 /** 00248 * @class IntrusiveCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h 00249 * @brief This is a counter class providing the ref() and unref() 00250 * functions required by IntrusivePtr. 00251 * @ingroup handles 00252 * @sa IntrusiveLockCounter. 00253 * 00254 * This is a counter class providing the ref() and unref() functions 00255 * required by IntrusivePtr. It is intended to be inherited from by 00256 * classes which are to be managed by such a smart pointer. 00257 */ 00258 00259 class IntrusiveCounter { 00260 unsigned int count; 00261 00262 public: 00263 // we should not be able to copy objects of this class 00264 // - objects, if constructed on the heap, should be passed 00265 // via an IntrusivePtr object. An object of a derived class 00266 // might still copy itself via its copy constructor and take 00267 // along a new base IntrusiveCounter object constructed via 00268 // the default constructor, and thus have a correct reference 00269 // count of 0, but derived classes should not try to provide 00270 // their own assignment operators. 00271 /** 00272 * This class cannot be copied. The copy constructor is deleted. 00273 */ 00274 IntrusiveCounter(const IntrusiveCounter&) = delete; 00275 /** 00276 * This class cannot be copied. The assignment operator is deleted. 00277 */ 00278 IntrusiveCounter& operator=(const IntrusiveCounter&) = delete; 00279 00280 /** 00281 * Increments the reference count. This method does not throw. 00282 */ 00283 void ref() {++count;} 00284 00285 /** 00286 * Decrements the reference count, and if the count reaches 0 deletes 00287 * itself (ie the managed object). This method does not throw unless 00288 * the destructor of a derived class throws - that should never 00289 * happen. 00290 */ 00291 void unref() { 00292 --count; 00293 if (count == 0) delete this; 00294 } 00295 00296 IntrusiveCounter(): count(0) {} 00297 virtual ~IntrusiveCounter() {} 00298 }; 00299 00300 /** 00301 * @class IntrusiveLockCounter intrusive_ptr.h c++-gtk-utils/intrusive_ptr.h 00302 * @brief This is a counter class providing the ref() and unref() 00303 * functions required by IntrusivePtr, with a thread safe reference 00304 * count.. 00305 * @ingroup handles 00306 * @sa IntrusiveCounter. 00307 * 00308 * This is a counter class providing the ref() and unref() functions 00309 * required by IntrusivePtr. It is intended to be inherited from by 00310 * classes which are to be managed by such a smart pointer, and 00311 * includes locking so that such an inheriting class object can be 00312 * accessed by different IntrusivePtr objects in different threads 00313 * (although the word Lock is in the title, by default it uses glib 00314 * atomic functions to access the reference count rather than a mutex, 00315 * so the overhead should be very small). Note that only the 00316 * reference count is protected, so this is thread safe in the sense 00317 * in which a raw pointer is thread safe. 00318 * 00319 * As mentioned, by default glib atomic functions are used to provide 00320 * thread-safe manipulation of the reference count. However, a 00321 * library user can define the symbol 00322 * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX before this file is parsed so 00323 * as to use mutexes instead, which might be useful for some debugging 00324 * purposes. 00325 */ 00326 00327 class IntrusiveLockCounter { 00328 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 00329 unsigned int count; 00330 Thread::Mutex mutex; 00331 #else 00332 gint count; 00333 #endif 00334 00335 public: 00336 // we should not be able to copy objects of this class 00337 // - objects, if constructed on the heap, should be passed 00338 // via an IntrusivePtr object. An object of a derived class 00339 // might still copy itself via its copy constructor and take 00340 // along a new base IntrusiveLockCounter object constructed via 00341 // the default constructor, and thus have a correct reference 00342 // count of 0, but derived classes should not try to provide 00343 // their own assignment operators. 00344 /** 00345 * This class cannot be copied. The copy constructor is deleted. 00346 */ 00347 IntrusiveLockCounter(const IntrusiveLockCounter&) = delete; 00348 /** 00349 * This class cannot be copied. The assignment operator is deleted. 00350 */ 00351 IntrusiveLockCounter& operator=(const IntrusiveLockCounter&) = delete; 00352 00353 /** 00354 * Increments the reference count. This method does not throw. 00355 */ 00356 void ref() { 00357 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 00358 Thread::Mutex::Lock lock(mutex); 00359 ++count; 00360 #else 00361 g_atomic_int_inc(&count); 00362 #endif 00363 } 00364 00365 /** 00366 * Decrements the reference count, and if the count reaches 0 deletes 00367 * itself (ie the managed object). This method does not throw unless 00368 * the destructor of a derived class throws - that should never 00369 * happen. 00370 */ 00371 void unref() { 00372 #ifdef CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX 00373 mutex.lock(); 00374 --count; 00375 if (count == 0) { 00376 mutex.unlock(); 00377 delete this; 00378 } 00379 else mutex.unlock(); 00380 #else 00381 if (g_atomic_int_dec_and_test(&count)) { 00382 delete this; 00383 } 00384 #endif 00385 } 00386 00387 /** 00388 * By default, glib atomic functions are used to provide thread-safe 00389 * manipulation of the reference count. However, from version 1.2.0 a 00390 * library user can define the symbol 00391 * CGU_INTRUSIVE_LOCK_COUNTER_USE_MUTEX before this file is parsed so 00392 * as to use mutexes instead, which might be useful for some debugging 00393 * purposes. Were she to do so, Cgu::Thread::MutexError might be 00394 * thrown by this constructor if initialization of the mutex fails, 00395 * but it is usually not worth checking for this. 00396 * 00397 * Otherwise, this constructor does not throw. 00398 */ 00399 IntrusiveLockCounter(): count(0) {} 00400 00401 /** 00402 * This destructor does not throw, unless the destructor of a derived 00403 * class throws. 00404 */ 00405 virtual ~IntrusiveLockCounter() {} 00406 }; 00407 00408 #if defined(CGU_USE_SMART_PTR_COMPARISON) || defined(DOXYGEN_PARSING) 00409 00410 // we can use built-in operator == when comparing pointers referencing 00411 // different objects of the same type 00412 /** 00413 * @ingroup handles 00414 * 00415 * This comparison operator does not throw. It compares the addresses 00416 * of the managed objects. 00417 * 00418 * Since 2.0.0-rc2 00419 */ 00420 template <class T> 00421 bool operator==(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) { 00422 return (s1.get() == s2.get()); 00423 } 00424 00425 /** 00426 * @ingroup handles 00427 * 00428 * This comparison operator does not throw. It compares the addresses 00429 * of the managed objects. 00430 * 00431 * Since 2.0.0-rc2 00432 */ 00433 template <class T> 00434 bool operator!=(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) { 00435 return !(s1 == s2); 00436 } 00437 00438 // we must use std::less rather than the < built-in operator for 00439 // pointers to objects not within the same array or object: "For 00440 // templates greater, less, greater_equal, and less_equal, the 00441 // specializations for any pointer type yield a total order, even if 00442 // the built-in operators <, >, <=, >= do not." (para 20.3.3/8). 00443 /** 00444 * @ingroup handles 00445 * 00446 * This comparison operator does not throw. It compares the addresses 00447 * of the managed objects. 00448 * 00449 * Since 2.0.0-rc2 00450 */ 00451 template <class T> 00452 bool operator<(const IntrusivePtr<T>& s1, const IntrusivePtr<T>& s2) { 00453 return std::less<T*>()(s1.get(), s2.get()); 00454 } 00455 00456 #endif // CGU_USE_SMART_PTR_COMPARISON 00457 00458 } // namespace Cgu 00459 00460 // doxygen produces long filenames that tar can't handle: 00461 // we have generic documentation for std::hash specialisations 00462 // in doxygen.main.in 00463 #if defined(CGU_USE_SMART_PTR_COMPARISON) && !defined(DOXYGEN_PARSING) 00464 /* This struct allows InstrusivePtr objects to be keys in unordered 00465 associative containers */ 00466 namespace std { 00467 template <class T> 00468 struct hash<Cgu::IntrusivePtr<T>> { 00469 typedef std::size_t result_type; 00470 typedef Cgu::IntrusivePtr<T> argument_type; 00471 result_type operator()(const argument_type& s) const { 00472 // this is fine: std::hash structs do not normally contain data and 00473 // std::hash<T*> certainly won't, so we don't have overhead constructing 00474 // std::hash<T*> on the fly 00475 return std::hash<T*>()(s.get()); 00476 } 00477 }; 00478 } // namespace std 00479 #endif // CGU_USE_SMART_PTR_COMPARISON 00480 00481 #endif