00001 /************************************************************************************ 00002 00003 PublicHeader: Kernel 00004 Filename : OVR_RefCount.h 00005 Content : Reference counting implementation headers 00006 Created : September 19, 2012 00007 Notes : 00008 00009 Copyright : Copyright 2012 Oculus VR, Inc. All Rights reserved. 00010 00011 Use of this software is subject to the terms of the Oculus license 00012 agreement provided at the time of installation or download, or which 00013 otherwise accompanies this software in either electronic or hard copy form. 00014 00015 ************************************************************************************/ 00016 00017 #ifndef OVR_RefCount_h 00018 #define OVR_RefCount_h 00019 00020 #include "OVR_Types.h" 00021 #include "OVR_Allocator.h" 00022 00023 namespace OVR { 00024 00025 //----------------------------------------------------------------------------------- 00026 // ***** Reference Counting 00027 00028 // There are three types of reference counting base classes: 00029 // 00030 // RefCountBase - Provides thread-safe reference counting (Default). 00031 // RefCountBaseNTS - Non Thread Safe version of reference counting. 00032 00033 00034 // ***** Declared classes 00035 00036 template<class C> 00037 class RefCountBase; 00038 template<class C> 00039 class RefCountBaseNTS; 00040 00041 class RefCountImpl; 00042 class RefCountNTSImpl; 00043 00044 00045 //----------------------------------------------------------------------------------- 00046 // ***** Implementation For Reference Counting 00047 00048 // RefCountImplCore holds RefCount value and defines a few utility 00049 // functions shared by all implementations. 00050 00051 class RefCountImplCore 00052 { 00053 protected: 00054 volatile int RefCount; 00055 00056 public: 00057 // RefCountImpl constructor always initializes RefCount to 1 by default. 00058 OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { } 00059 00060 // Need virtual destructor 00061 // This: 1. Makes sure the right destructor's called. 00062 // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() 00063 virtual ~RefCountImplCore(); 00064 00065 // Debug method only. 00066 int GetRefCount() const { return RefCount; } 00067 00068 // This logic is used to detect invalid 'delete' calls of reference counted 00069 // objects. Direct delete calls are not allowed on them unless they come in 00070 // internally from Release. 00071 #ifdef OVR_BUILD_DEBUG 00072 static void OVR_CDECL reportInvalidDelete(void *pmem); 00073 inline static void checkInvalidDelete(RefCountImplCore *pmem) 00074 { 00075 if (pmem->RefCount != 0) 00076 reportInvalidDelete(pmem); 00077 } 00078 #else 00079 inline static void checkInvalidDelete(RefCountImplCore *) { } 00080 #endif 00081 00082 // Base class ref-count content should not be copied. 00083 void operator = (const RefCountImplCore &) { } 00084 }; 00085 00086 class RefCountNTSImplCore 00087 { 00088 protected: 00089 mutable int RefCount; 00090 00091 public: 00092 // RefCountImpl constructor always initializes RefCount to 1 by default. 00093 OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { } 00094 00095 // Need virtual destructor 00096 // This: 1. Makes sure the right destructor's called. 00097 // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() 00098 virtual ~RefCountNTSImplCore(); 00099 00100 // Debug method only. 00101 int GetRefCount() const { return RefCount; } 00102 00103 // This logic is used to detect invalid 'delete' calls of reference counted 00104 // objects. Direct delete calls are not allowed on them unless they come in 00105 // internally from Release. 00106 #ifdef OVR_BUILD_DEBUG 00107 static void OVR_CDECL reportInvalidDelete(void *pmem); 00108 OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem) 00109 { 00110 if (pmem->RefCount != 0) 00111 reportInvalidDelete(pmem); 00112 } 00113 #else 00114 OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { } 00115 #endif 00116 00117 // Base class ref-count content should not be copied. 00118 void operator = (const RefCountNTSImplCore &) { } 00119 }; 00120 00121 00122 00123 // RefCountImpl provides Thread-Safe implementation of reference counting, so 00124 // it should be used by default in most places. 00125 00126 class RefCountImpl : public RefCountImplCore 00127 { 00128 public: 00129 // Thread-Safe Ref-Count Implementation. 00130 void AddRef(); 00131 void Release(); 00132 }; 00133 00134 // RefCountVImpl provides Thread-Safe implementation of reference counting, plus, 00135 // virtual AddRef and Release. 00136 00137 class RefCountVImpl : public RefCountImplCore 00138 { 00139 public: 00140 // Thread-Safe Ref-Count Implementation. 00141 virtual void AddRef(); 00142 virtual void Release(); 00143 }; 00144 00145 00146 // RefCountImplNTS provides Non-Thread-Safe implementation of reference counting, 00147 // which is slightly more efficient since it doesn't use atomics. 00148 00149 class RefCountNTSImpl : public RefCountNTSImplCore 00150 { 00151 public: 00152 OVR_FORCE_INLINE void AddRef() const { RefCount++; } 00153 void Release() const; 00154 }; 00155 00156 00157 00158 // RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking 00159 // to the reference counting implementation. Base must be one of the RefCountImpl classes. 00160 00161 template<class Base> 00162 class RefCountBaseStatImpl : public Base 00163 { 00164 public: 00165 RefCountBaseStatImpl() { } 00166 00167 // *** Override New and Delete 00168 00169 // DOM-IGNORE-BEGIN 00170 // Undef new temporarily if it is being redefined 00171 #ifdef OVR_DEFINE_NEW 00172 #undef new 00173 #endif 00174 00175 #ifdef OVR_BUILD_DEBUG 00176 // Custom check used to detect incorrect calls of 'delete' on ref-counted objects. 00177 #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \ 00178 do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0) 00179 #else 00180 #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) 00181 #endif 00182 00183 // Redefine all new & delete operators. 00184 OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) 00185 00186 #ifdef OVR_DEFINE_NEW 00187 #define new OVR_DEFINE_NEW 00188 #endif 00189 // OVR_BUILD_DEFINE_NEW 00190 // DOM-IGNORE-END 00191 }; 00192 00193 00194 00195 //----------------------------------------------------------------------------------- 00196 // *** End user RefCountBase<> classes 00197 00198 00199 // RefCountBase is a base class for classes that require thread-safe reference 00200 // counting; it also overrides the new and delete operators to use MemoryHeap. 00201 // 00202 // Reference counted objects start out with RefCount value of 1. Further lifetime 00203 // management is done through the AddRef() and Release() methods, typically 00204 // hidden by Ptr<>. 00205 00206 template<class C> 00207 class RefCountBase : public RefCountBaseStatImpl<RefCountImpl> 00208 { 00209 public: 00210 // Constructor. 00211 OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { } 00212 }; 00213 00214 // RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release 00215 00216 template<class C> 00217 class RefCountBaseV : public RefCountBaseStatImpl<RefCountVImpl> 00218 { 00219 public: 00220 // Constructor. 00221 OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatImpl<RefCountVImpl>() { } 00222 }; 00223 00224 00225 // RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference 00226 // counting; it also overrides the new and delete operators to use MemoryHeap. 00227 // This class should only be used if all pointers to it are known to be assigned, 00228 // destroyed and manipulated within one thread. 00229 // 00230 // Reference counted objects start out with RefCount value of 1. Further lifetime 00231 // management is done through the AddRef() and Release() methods, typically 00232 // hidden by Ptr<>. 00233 00234 template<class C> 00235 class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl> 00236 { 00237 public: 00238 // Constructor. 00239 OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { } 00240 }; 00241 00242 //----------------------------------------------------------------------------------- 00243 // ***** Pickable template pointer 00244 enum PickType { PickValue }; 00245 00246 template <typename T> 00247 class Pickable 00248 { 00249 public: 00250 Pickable() : pV(NULL) {} 00251 explicit Pickable(T* p) : pV(p) {} 00252 Pickable(T* p, PickType) : pV(p) 00253 { 00254 OVR_ASSERT(pV); 00255 if (pV) 00256 pV->AddRef(); 00257 } 00258 template <typename OT> 00259 Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {} 00260 00261 public: 00262 Pickable& operator =(const Pickable& other) 00263 { 00264 OVR_ASSERT(pV == NULL); 00265 pV = other.pV; 00266 // Extra check. 00267 //other.pV = NULL; 00268 return *this; 00269 } 00270 00271 public: 00272 T* GetPtr() const { return pV; } 00273 T* operator->() const 00274 { 00275 return pV; 00276 } 00277 T& operator*() const 00278 { 00279 OVR_ASSERT(pV); 00280 return *pV; 00281 } 00282 00283 private: 00284 T* pV; 00285 }; 00286 00287 template <typename T> 00288 OVR_FORCE_INLINE 00289 Pickable<T> MakePickable(T* p) 00290 { 00291 return Pickable<T>(p); 00292 } 00293 00294 //----------------------------------------------------------------------------------- 00295 // ***** Ref-Counted template pointer 00296 00297 // Automatically AddRefs and Releases interfaces 00298 00299 void* ReturnArg0(void* p); 00300 00301 template<class C> 00302 class Ptr 00303 { 00304 #ifdef OVR_CC_ARM 00305 static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); } 00306 #endif 00307 00308 protected: 00309 C *pObject; 00310 00311 public: 00312 00313 // Constructors 00314 OVR_FORCE_INLINE Ptr() : pObject(0) 00315 { } 00316 #ifdef OVR_CC_ARM 00317 OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj)) 00318 #else 00319 OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj) 00320 #endif 00321 { } 00322 OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr()) 00323 { 00324 // No AddRef() on purpose. 00325 } 00326 OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject) 00327 { 00328 other.pObject = NULL; 00329 // No AddRef() on purpose. 00330 } 00331 OVR_FORCE_INLINE Ptr(C *pobj) 00332 { 00333 if (pobj) pobj->AddRef(); 00334 pObject = pobj; 00335 } 00336 OVR_FORCE_INLINE Ptr(const Ptr<C> &src) 00337 { 00338 if (src.pObject) src.pObject->AddRef(); 00339 pObject = src.pObject; 00340 } 00341 00342 template<class R> 00343 OVR_FORCE_INLINE Ptr(Ptr<R> &src) 00344 { 00345 if (src) src->AddRef(); 00346 pObject = src; 00347 } 00348 template<class R> 00349 OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr()) 00350 { 00351 // No AddRef() on purpose. 00352 } 00353 00354 // Destructor 00355 OVR_FORCE_INLINE ~Ptr() 00356 { 00357 if (pObject) pObject->Release(); 00358 } 00359 00360 // Compares 00361 OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; } 00362 OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; } 00363 00364 OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; } 00365 OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; } 00366 00367 00368 OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; } 00369 00370 // Assignment 00371 template<class R> 00372 OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src) 00373 { 00374 if (src) src->AddRef(); 00375 if (pObject) pObject->Release(); 00376 pObject = src; 00377 return *this; 00378 } 00379 // Specialization 00380 OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src) 00381 { 00382 if (src) src->AddRef(); 00383 if (pObject) pObject->Release(); 00384 pObject = src; 00385 return *this; 00386 } 00387 00388 OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc) 00389 { 00390 if (psrc) psrc->AddRef(); 00391 if (pObject) pObject->Release(); 00392 pObject = psrc; 00393 return *this; 00394 } 00395 OVR_FORCE_INLINE const Ptr<C>& operator = (C &src) 00396 { 00397 if (pObject) pObject->Release(); 00398 pObject = &src; 00399 return *this; 00400 } 00401 OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src) 00402 { 00403 return Pick(src); 00404 } 00405 template<class R> 00406 OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src) 00407 { 00408 return Pick(src); 00409 } 00410 00411 // Set Assignment 00412 template<class R> 00413 OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src) 00414 { 00415 if (src) src->AddRef(); 00416 if (pObject) pObject->Release(); 00417 pObject = src; 00418 return *this; 00419 } 00420 // Specialization 00421 OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src) 00422 { 00423 if (src) src->AddRef(); 00424 if (pObject) pObject->Release(); 00425 pObject = src; 00426 return *this; 00427 } 00428 00429 OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc) 00430 { 00431 if (psrc) psrc->AddRef(); 00432 if (pObject) pObject->Release(); 00433 pObject = psrc; 00434 return *this; 00435 } 00436 OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src) 00437 { 00438 if (pObject) pObject->Release(); 00439 pObject = &src; 00440 return *this; 00441 } 00442 OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src) 00443 { 00444 return Pick(src); 00445 } 00446 00447 // Nulls ref-counted pointer without decrement 00448 OVR_FORCE_INLINE void NullWithoutRelease() 00449 { 00450 pObject = 0; 00451 } 00452 00453 // Clears the pointer to the object 00454 OVR_FORCE_INLINE void Clear() 00455 { 00456 if (pObject) pObject->Release(); 00457 pObject = 0; 00458 } 00459 00460 // Obtain pointer reference directly, for D3D interfaces 00461 OVR_FORCE_INLINE C*& GetRawRef() { return pObject; } 00462 00463 // Access Operators 00464 OVR_FORCE_INLINE C* GetPtr() const { return pObject; } 00465 OVR_FORCE_INLINE C& operator * () const { return *pObject; } 00466 OVR_FORCE_INLINE C* operator -> () const { return pObject; } 00467 // Conversion 00468 OVR_FORCE_INLINE operator C* () const { return pObject; } 00469 00470 // Pickers. 00471 00472 // Pick a value. 00473 OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other) 00474 { 00475 if (&other != this) 00476 { 00477 if (pObject) pObject->Release(); 00478 pObject = other.pObject; 00479 other.pObject = 0; 00480 } 00481 00482 return *this; 00483 } 00484 00485 OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v) 00486 { 00487 if (v.GetPtr() != pObject) 00488 { 00489 if (pObject) pObject->Release(); 00490 pObject = v.GetPtr(); 00491 } 00492 00493 return *this; 00494 } 00495 00496 template<class R> 00497 OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v) 00498 { 00499 if (v.GetPtr() != pObject) 00500 { 00501 if (pObject) pObject->Release(); 00502 pObject = v.GetPtr(); 00503 } 00504 00505 return *this; 00506 } 00507 00508 OVR_FORCE_INLINE Ptr<C>& Pick(C* p) 00509 { 00510 if (p != pObject) 00511 { 00512 if (pObject) pObject->Release(); 00513 pObject = p; 00514 } 00515 00516 return *this; 00517 } 00518 }; 00519 00520 } // OVR 00521 00522 #endif