Fawkes API
Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * refptr.h - reference counting shared smartpointer 00004 * 00005 * Created: Sat Jan 24 12:29:41 2009 00006 * Copyright 2002 The gtkmm Development Team 00007 * 2005 The cairomm Development Team 00008 * 2009 Tim Niemueller [www.niemueller.de] 00009 * 00010 ****************************************************************************/ 00011 00012 /* This program is free software; you can redistribute it and/or modify 00013 * it under the terms of the GNU General Public License as published by 00014 * the Free Software Foundation; either version 2 of the License, or 00015 * (at your option) any later version. A runtime exception applies to 00016 * this software (see LICENSE.GPL_WRE file mentioned below for details). 00017 * 00018 * This program is distributed in the hope that it will be useful, 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00021 * GNU Library General Public License for more details. 00022 * 00023 * Read the full text in the LICENSE.GPL_WRE file in the doc directory. 00024 */ 00025 00026 #ifndef __CORE_UTILS_REFPTR_H_ 00027 #define __CORE_UTILS_REFPTR_H_ 00028 00029 #include <core/threading/mutex.h> 00030 00031 namespace fawkes { 00032 00033 /** RefPtr<> is a reference-counting shared smartpointer. 00034 * 00035 * Reference counting means that a shared reference count is incremented each 00036 * time a RefPtr is copied, and decremented each time a RefPtr is destroyed, 00037 * for instance when it leaves its scope. When the reference count reaches 00038 * zero, the contained object is deleted 00039 * 00040 * Fawkes uses RefPtr so that you don't need to remember 00041 * to delete the object explicitly, or know when a method expects you to delete 00042 * the object that it returns, and to prevent any need to manually reference 00043 * and unreference cairo objects. 00044 * 00045 * Note that RefPtr is thread-safe. 00046 * 00047 * @ingroup FCL 00048 */ 00049 template <class T_CppObject> 00050 class RefPtr 00051 { 00052 public: 00053 /** Default constructor 00054 * 00055 * Afterwards it will be null and use of -> will cause a segmentation fault. 00056 */ 00057 inline RefPtr(); 00058 00059 /// Destructor - decrements reference count. 00060 inline ~RefPtr(); 00061 00062 /** Constructor that takes ownership. 00063 * 00064 * This takes ownership of @a cpp_object, so it will be deleted when the 00065 * last RefPtr is deleted, for instance when it goes out of scope. 00066 * @param cpp_object C++ object to take ownership of 00067 */ 00068 explicit inline RefPtr(T_CppObject* cpp_object); 00069 00070 /** Copy constructor 00071 * This increments the shared reference count. 00072 * @param src refptr to copy 00073 */ 00074 inline RefPtr(const RefPtr<T_CppObject>& src); 00075 00076 /** Copy constructor (from different, but castable type). 00077 * Increments the reference count. 00078 * @param src refptr to copy 00079 */ 00080 template <class T_CastFrom> 00081 inline RefPtr(const RefPtr<T_CastFrom>& src); 00082 00083 /** Swap the contents of two RefPtr<>. 00084 * This method swaps the internal pointers to T_CppObject. This can be 00085 * done safely without involving a reference/unreference cycle and is 00086 * therefore highly efficient. 00087 * @param other other instance to swap with. 00088 */ 00089 inline void swap(RefPtr<T_CppObject>& other); 00090 00091 /** Copy from another RefPtr. 00092 * @param src refptr to copy from 00093 * @return reference to this instance 00094 */ 00095 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src); 00096 00097 /** Copy from different, but castable type). 00098 * Increments the reference count. 00099 * @param src refptr to copy from 00100 * @return reference to this instance 00101 */ 00102 template <class T_CastFrom> 00103 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src); 00104 00105 /** Assign object and claim ownership. 00106 * @param ptr pointer to object, this refptr will claim ownership of the src! 00107 * @return reference to this instance 00108 */ 00109 inline RefPtr<T_CppObject>& operator=(T_CppObject *ptr); 00110 00111 00112 /** Tests whether the RefPtr<> point to the same underlying instance. 00113 * @param src refptr to compare to 00114 * @return true if both refptrs point to the same instance. 00115 */ 00116 inline bool operator==(const RefPtr<T_CppObject>& src) const; 00117 00118 /** Tests whether the RefPtr<> do not point to the same underlying instance. 00119 * @param src refptr to compare to 00120 * @return true if both refptrs do not point to the same instance. 00121 */ 00122 inline bool operator!=(const RefPtr<T_CppObject>& src) const; 00123 00124 /** Dereferencing. 00125 * Use the methods of the underlying instance like so: 00126 * <code>refptr->memberfun()</code>. 00127 * @return pointer to encapsulated object 00128 */ 00129 inline T_CppObject* operator->() const; 00130 00131 /** Test whether the RefPtr<> points to any underlying instance. 00132 * 00133 * Mimics usage of ordinary pointers: 00134 * @code 00135 * if (ptr) 00136 * do_something(); 00137 * @endcode 00138 */ 00139 inline operator bool() const; 00140 00141 /// Set underlying instance to 0, decrementing reference count of existing instance appropriately. 00142 inline void clear(); 00143 00144 00145 /** Dynamic cast to derived class. 00146 * 00147 * The RefPtr can't be cast with the usual notation so instead you can use 00148 * @code 00149 * ptr_derived = RefPtr<Derived>::cast_dynamic(ptr_base); 00150 * @endcode 00151 * @param src source refptr to cast 00152 * @return refptr to object casted to given type 00153 */ 00154 template <class T_CastFrom> 00155 static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src); 00156 00157 /** Static cast to derived class. 00158 * 00159 * Like the dynamic cast; the notation is 00160 * @code 00161 * ptr_derived = RefPtr<Derived>::cast_static(ptr_base); 00162 * @endcode 00163 * @param src source refptr to cast 00164 * @return refptr to object casted to given type 00165 */ 00166 template <class T_CastFrom> 00167 static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src); 00168 00169 /** Cast to non-const. 00170 * 00171 * The RefPtr can't be cast with the usual notation so instead you can use 00172 * @code 00173 * ptr_unconst = RefPtr<UnConstType>::cast_const(ptr_const); 00174 * @endcode 00175 * @param src source refptr to cast 00176 * @return refptr to object casted to given type 00177 */ 00178 template <class T_CastFrom> 00179 static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src); 00180 00181 /** For use only in the internal implementation of sharedptr. 00182 * @param cpp_object C++ object to wrap 00183 * @param refcount reference count 00184 * @param refmutex reference count mutex 00185 */ 00186 explicit inline RefPtr(T_CppObject *cpp_object, int *refcount, Mutex *refmutex); 00187 00188 /** For use only in the internal implementation of sharedptr. 00189 * Get reference count pointer. 00190 * Warning: This is for internal use only. Do not manually modify the 00191 * reference count with this pointer. 00192 * @return pointer to refcount integer 00193 */ 00194 inline int * refcount_ptr() const { return __ref_count; } 00195 00196 /** For use only in the internal implementation of sharedptr. 00197 * Get reference mutex. 00198 * @return pointer to refcount mutex 00199 */ 00200 inline Mutex * refmutex_ptr() const { return __ref_mutex; } 00201 00202 private: 00203 00204 T_CppObject *__cpp_object; 00205 mutable int *__ref_count; 00206 mutable Mutex *__ref_mutex; 00207 00208 }; 00209 00210 00211 // RefPtr<>::operator->() comes first here since it's used by other methods. 00212 // If it would come after them it wouldn't be inlined. 00213 00214 template <class T_CppObject> inline 00215 T_CppObject* RefPtr<T_CppObject>::operator->() const 00216 { 00217 return __cpp_object; 00218 } 00219 00220 template <class T_CppObject> inline 00221 RefPtr<T_CppObject>::RefPtr() 00222 : 00223 __cpp_object(0), 00224 __ref_count(0), 00225 __ref_mutex(0) 00226 {} 00227 00228 template <class T_CppObject> inline 00229 RefPtr<T_CppObject>::~RefPtr() 00230 { 00231 if(__ref_count && __ref_mutex) 00232 { 00233 __ref_mutex->lock(); 00234 00235 --(*__ref_count); 00236 00237 if(*__ref_count == 0) 00238 { 00239 if(__cpp_object) 00240 { 00241 delete __cpp_object; 00242 __cpp_object = 0; 00243 } 00244 00245 delete __ref_count; 00246 delete __ref_mutex; 00247 __ref_count = 0; 00248 __ref_mutex = 0; 00249 } else { 00250 __ref_mutex->unlock(); 00251 } 00252 } 00253 } 00254 00255 00256 template <class T_CppObject> inline 00257 RefPtr<T_CppObject>::RefPtr(T_CppObject* cpp_object) 00258 : 00259 __cpp_object(cpp_object), 00260 __ref_count(0), 00261 __ref_mutex(0) 00262 { 00263 if(cpp_object) 00264 { 00265 __ref_count = new int; 00266 __ref_mutex = new Mutex(); 00267 *__ref_count = 1; //This will be decremented in the destructor. 00268 } 00269 } 00270 00271 //Used by cast_*() implementations: 00272 template <class T_CppObject> inline 00273 RefPtr<T_CppObject>::RefPtr(T_CppObject* cpp_object, int* refcount, Mutex *refmutex) 00274 : 00275 __cpp_object(cpp_object), 00276 __ref_count(refcount), 00277 __ref_mutex(refmutex) 00278 { 00279 if(__cpp_object && __ref_count && __ref_mutex) { 00280 __ref_mutex->lock(); 00281 ++(*__ref_count); 00282 __ref_mutex->unlock(); 00283 } 00284 } 00285 00286 template <class T_CppObject> inline 00287 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src) 00288 : 00289 __cpp_object (src.__cpp_object), 00290 __ref_count(src.__ref_count), 00291 __ref_mutex(src.__ref_mutex) 00292 { 00293 if(__cpp_object && __ref_count && __ref_mutex) 00294 { 00295 __ref_mutex->lock(); 00296 ++(*__ref_count); 00297 __ref_mutex->unlock(); 00298 } 00299 } 00300 00301 // The templated ctor allows copy construction from any object that's 00302 // castable. Thus, it does downcasts: 00303 // base_ref = derived_ref 00304 template <class T_CppObject> 00305 template <class T_CastFrom> 00306 inline 00307 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src) 00308 : 00309 // A different RefPtr<> will not allow us access to __cpp_object. We need 00310 // to add a get_underlying() for this, but that would encourage incorrect 00311 // use, so we use the less well-known operator->() accessor: 00312 __cpp_object (src.operator->()), 00313 __ref_count(src.refcount_ptr()), 00314 __ref_mutex(src.refmutex_ptr()) 00315 { 00316 if(__cpp_object && __ref_count && __ref_mutex) { 00317 __ref_mutex->lock(); 00318 ++(*__ref_count); 00319 __ref_mutex->unlock(); 00320 } 00321 } 00322 00323 template <class T_CppObject> inline 00324 void 00325 RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other) 00326 { 00327 T_CppObject *const temp = __cpp_object; 00328 int *temp_count = __ref_count; 00329 Mutex *temp_mutex = __ref_mutex; 00330 00331 __cpp_object = other.__cpp_object; 00332 __ref_count = other.__ref_count; 00333 __ref_mutex = other.__ref_mutex; 00334 00335 other.__cpp_object = temp; 00336 other.__ref_count = temp_count; 00337 other.__ref_mutex = temp_mutex; 00338 } 00339 00340 template <class T_CppObject> inline 00341 RefPtr<T_CppObject>& 00342 RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src) 00343 { 00344 // In case you haven't seen the swap() technique to implement copy 00345 // assignment before, here's what it does: 00346 // 00347 // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby 00348 // increasing the reference count of the source object. 00349 // 00350 // 2) Swap the internal object pointers of *this and the temporary 00351 // RefPtr<>. After this step, *this already contains the new pointer, 00352 // and the old pointer is now managed by temp. 00353 // 00354 // 3) The destructor of temp is executed, thereby unreferencing the 00355 // old object pointer. 00356 // 00357 // This technique is described in Herb Sutter's "Exceptional C++", and 00358 // has a number of advantages over conventional approaches: 00359 // 00360 // - Code reuse by calling the copy ctor. 00361 // - Strong exception safety for free. 00362 // - Self assignment is handled implicitely. 00363 // - Simplicity. 00364 // - It just works and is hard to get wrong; i.e. you can use it without 00365 // even thinking about it to implement copy assignment whereever the 00366 // object data is managed indirectly via a pointer, which is very common. 00367 00368 RefPtr<T_CppObject> temp (src); 00369 this->swap(temp); 00370 return *this; 00371 } 00372 00373 template <class T_CppObject> inline 00374 RefPtr<T_CppObject>& 00375 RefPtr<T_CppObject>::operator=(T_CppObject *ptr) 00376 { 00377 RefPtr<T_CppObject> temp(ptr); 00378 this->swap(temp); 00379 return *this; 00380 } 00381 00382 00383 template <class T_CppObject> 00384 template <class T_CastFrom> 00385 inline 00386 RefPtr<T_CppObject>& 00387 RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) 00388 { 00389 RefPtr<T_CppObject> temp (src); 00390 this->swap(temp); 00391 return *this; 00392 } 00393 00394 template <class T_CppObject> inline 00395 bool 00396 RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const 00397 { 00398 return (__cpp_object == src.__cpp_object); 00399 } 00400 00401 template <class T_CppObject> inline 00402 bool 00403 RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const 00404 { 00405 return (__cpp_object != src.__cpp_object); 00406 } 00407 00408 template <class T_CppObject> inline 00409 RefPtr<T_CppObject>::operator bool() const 00410 { 00411 return (__cpp_object != 0); 00412 } 00413 00414 template <class T_CppObject> inline 00415 void RefPtr<T_CppObject>::clear() 00416 { 00417 RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this 00418 this->swap(temp); 00419 } 00420 00421 template <class T_CppObject> 00422 template <class T_CastFrom> 00423 inline 00424 RefPtr<T_CppObject> 00425 RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src) 00426 { 00427 T_CppObject *const cpp_object = dynamic_cast<T_CppObject*>(src.operator->()); 00428 00429 if(cpp_object) //Check whether dynamic_cast<> succeeded so we don't pass a null object with a used refcount: 00430 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00431 else 00432 return RefPtr<T_CppObject>(); 00433 } 00434 00435 template <class T_CppObject> 00436 template <class T_CastFrom> 00437 inline 00438 RefPtr<T_CppObject> 00439 RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src) 00440 { 00441 T_CppObject *const cpp_object = static_cast<T_CppObject*>(src.operator->()); 00442 00443 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00444 } 00445 00446 template <class T_CppObject> 00447 template <class T_CastFrom> 00448 inline 00449 RefPtr<T_CppObject> 00450 RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src) 00451 { 00452 T_CppObject *const cpp_object = const_cast<T_CppObject*>(src.operator->()); 00453 00454 return RefPtr<T_CppObject>(cpp_object, src.refcount_ptr(), src.refmutex_ptr()); 00455 } 00456 00457 00458 /** Swap refptr instances. 00459 * @param lrp "left" refptr 00460 * @param rrp "right" refptr 00461 * @relates fawkes::RefPtr 00462 */ 00463 template <class T_CppObject> inline 00464 void 00465 swap(RefPtr<T_CppObject>& lrp, RefPtr<T_CppObject>& rrp) 00466 { 00467 lrp.swap(rrp); 00468 } 00469 00470 } // end namespace fawkes 00471 00472 00473 #endif