csutil/ref.h
Go to the documentation of this file.00001 /* 00002 Crystal Space Smart Pointers 00003 Copyright (C) 2002 by Jorrit Tyberghein and Matthias Braun 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Library General Public 00007 License as published by the Free Software Foundation; either 00008 version 2 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public 00016 License along with this library; if not, write to the Free 00017 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00018 */ 00019 00020 #ifndef __CS_REF_H__ 00021 #define __CS_REF_H__ 00022 00027 #include "csextern.h" 00028 00029 #include "csutil/customallocated.h" 00030 #include "csutil/threading/atomicops.h" 00031 00032 #define CS_VOIDED_PTR ((intptr_t)-1) 00033 00034 template <class T> class csRef; 00035 00036 #if defined(CS_DEBUG) 00037 # define CS_TEST_VOIDPTRUSAGE 00038 #else 00039 # undef CS_TEST_VOIDPTRUSAGE 00040 #endif 00041 00042 #ifdef CS_REF_TRACKER 00043 #include <typeinfo> 00044 #include "csutil/reftrackeraccess.h" 00045 00046 #define CSREF_TRACK(x, cmd, refCount, obj, tag) \ 00047 { \ 00048 const int rc = obj ? refCount : -1; \ 00049 if (obj) \ 00050 { \ 00051 cmd; \ 00052 csRefTrackerAccess::SetDescriptionWeak (obj, \ 00053 typeid(T).name()); \ 00054 csRefTrackerAccess::Match ## x (obj, rc, tag);\ 00055 } \ 00056 } 00057 #define CSREF_TRACK_INCREF(obj,tag) \ 00058 CSREF_TRACK(IncRef, obj->IncRef(), obj->GetRefCount(), obj, tag); 00059 #define CSREF_TRACK_DECREF(obj,tag) \ 00060 CSREF_TRACK(DecRef, obj->DecRef(), obj->GetRefCount(), obj, tag); 00061 #define CSREF_TRACK_ASSIGN(obj,tag) \ 00062 CSREF_TRACK(IncRef, void(0), obj->GetRefCount() - 1, obj, tag); 00063 #else 00064 #define CSREF_TRACK_INCREF(obj,tag) \ 00065 if (obj) obj->IncRef(); 00066 #define CSREF_TRACK_DECREF(obj,tag) \ 00067 if (obj) obj->DecRef(); 00068 #define CSREF_TRACK_ASSIGN(obj,tag) 00069 #endif 00070 00093 template <class T> 00094 class csPtr : public CS::Memory::CustomAllocated 00095 { 00096 private: 00097 friend class csRef<T>; 00098 T* obj; 00099 00100 public: 00101 csPtr (T* p) : obj (p) { CSREF_TRACK_ASSIGN(obj, this); } 00102 00103 template <class T2> 00104 csPtr (csRef<T2> const& r) : obj((T2*)r) 00105 { 00106 CSREF_TRACK_INCREF (obj, this); 00107 } 00108 00109 #ifdef CS_TEST_VOIDPTRUSAGE 00110 ~csPtr () 00111 { 00112 // If not assigned to a csRef we have a problem (leak). 00113 // So if this assert fires for you, then you are calling 00114 // a function that returns a csPtr and not using the result 00115 // (or at least not assigning it to a csRef). This is a memory 00116 // leak and you should fix that. 00117 CS_ASSERT_MSG ("csPtr<> was not assigned to a csRef<> prior destruction", 00118 obj == (T*)CS_VOIDED_PTR); 00119 } 00120 #endif 00121 00122 csPtr (const csPtr<T>& copy) 00123 { 00124 obj = copy.obj; 00125 #ifdef CS_TEST_VOIDPTRUSAGE 00126 ((csPtr<T>&)copy).obj = (T*)CS_VOIDED_PTR; 00127 #endif 00128 } 00129 }; 00130 00170 template <class T> 00171 class csRef : public CS::Memory::CustomAllocated 00172 { 00173 private: 00174 T* obj; 00175 00176 public: 00182 csRef () : obj (0) {} 00183 00189 csRef (const csPtr<T>& newobj) 00190 { 00191 obj = newobj.obj; 00192 # ifdef CS_TEST_VOIDPTRUSAGE 00193 CS_ASSERT_MSG ("csPtr<> was already assigned to a csRef<>", 00194 newobj.obj != (T*)CS_VOIDED_PTR); 00195 # endif 00196 // The following line is outside the ifdef to make sure 00197 // we have binary compatibility. 00198 ((csPtr<T>&)newobj).obj = (T*)CS_VOIDED_PTR; 00199 } 00200 00205 csRef (T* newobj) : obj (newobj) 00206 { 00207 CSREF_TRACK_INCREF (obj, this); 00208 } 00209 00214 template <class T2> 00215 csRef (T2* newobj) : obj ((T2*)newobj) 00216 { 00217 CSREF_TRACK_INCREF (obj, this); 00218 } 00219 00223 template <class T2> 00224 csRef (csRef<T2> const& other) : obj ((T2*)other) 00225 { 00226 CSREF_TRACK_INCREF (obj, this); 00227 } 00228 00232 csRef (csRef const& other) : obj (other.obj) 00233 { 00234 CSREF_TRACK_INCREF (obj, this); 00235 } 00236 00240 ~csRef () 00241 { 00242 CSREF_TRACK_DECREF (obj, this); 00243 } 00244 00254 csRef& operator = (const csPtr<T>& newobj) 00255 { 00256 # ifdef CS_TEST_VOIDPTRUSAGE 00257 CS_ASSERT_MSG ("csPtr<> was already assigned to a csRef<>", 00258 newobj.obj != (T*)CS_VOIDED_PTR); 00259 # endif 00260 T* oldobj = (T*)CS::Threading::AtomicOperations::Read ((void**)&obj); 00261 // First assign and then DecRef() of old object! 00262 if (CS::Threading::AtomicOperations::CompareAndSet ((void**)&obj, 00263 newobj.obj, oldobj) == oldobj) 00264 { 00265 CSREF_TRACK_DECREF (oldobj, this); 00266 } 00267 else 00268 { 00269 /* Assign was not successful. But to pretend we have taken ownership, 00270 * DecRef() new object */ 00271 CSREF_TRACK_DECREF (newobj.obj, this); 00272 } 00273 // The following line is outside the ifdef to make sure 00274 // we have binary compatibility. 00275 ((csPtr<T>&)newobj).obj = (T*)CS_VOIDED_PTR; 00276 return *this; 00277 } 00278 00291 csRef& operator = (T* newobj) 00292 { 00293 T* oldobj = (T*)CS::Threading::AtomicOperations::Read ((void**)&obj); 00294 if (oldobj != newobj) 00295 { 00296 // It is very important to first assign the new value to 00297 // 'obj' BEFORE calling DecRef() on the old object. Otherwise 00298 // it is easy to get in infinite loops with objects being 00299 // destructed forever (when ref=0 is used for example). 00300 if (CS::Threading::AtomicOperations::CompareAndSet ((void**)&obj, 00301 newobj, oldobj) == oldobj) 00302 { 00303 CSREF_TRACK_INCREF (newobj, this); 00304 CSREF_TRACK_DECREF (oldobj, this); 00305 } 00306 } 00307 return *this; 00308 } 00309 00332 void AttachNew (csPtr<T> newObj) 00333 { 00334 // Note: The parameter usage of csPtr<T> instead of csPtr<T>& is 00335 // deliberate and not to be considered a bug. 00336 00337 // Just Re-use csPtr assignment logic 00338 *this = newObj; 00339 } 00340 00342 template <class T2> 00343 csRef& operator = (csRef<T2> const& other) 00344 { 00345 T* p = (T2*)other; 00346 this->operator=(p); 00347 return *this; 00348 } 00349 00351 csRef& operator = (csRef const& other) 00352 { 00353 this->operator=(other.obj); 00354 return *this; 00355 } 00356 00358 inline friend bool operator == (const csRef& r1, const csRef& r2) 00359 { 00360 return r1.obj == r2.obj; 00361 } 00363 inline friend bool operator != (const csRef& r1, const csRef& r2) 00364 { 00365 return r1.obj != r2.obj; 00366 } 00368 inline friend bool operator == (const csRef& r1, T* obj) 00369 { 00370 return r1.obj == obj; 00371 } 00373 inline friend bool operator != (const csRef& r1, T* obj) 00374 { 00375 return r1.obj != obj; 00376 } 00378 inline friend bool operator == (T* obj, const csRef& r1) 00379 { 00380 return r1.obj == obj; 00381 } 00383 inline friend bool operator != (T* obj, const csRef& r1) 00384 { 00385 return r1.obj != obj; 00386 } 00392 inline friend bool operator < (const csRef& r1, const csRef& r2) 00393 { 00394 return r1.obj < r2.obj; 00395 } 00396 00397 00399 T* operator -> () const 00400 { return obj; } 00401 00403 operator T* () const 00404 { return obj; } 00405 00407 T& operator* () const 00408 { return *obj; } 00409 00414 bool IsValid () const 00415 { return (obj != 0); } 00416 00418 void Invalidate() 00419 { *this = (T*)0; } 00420 00422 uint GetHash() const 00423 { return (uintptr_t)obj; } 00424 }; 00425 00426 #undef CSREF_TRACK_INCREF 00427 #undef CSREF_TRACK_DECREF 00428 #undef CSREF_TRACK_ASSIGN 00429 00430 #endif // __CS_REF_H__
Generated for Crystal Space 2.1 by doxygen 1.6.1
