ovr_sdk
diff LibOVR/Src/Kernel/OVR_RefCount.h @ 0:1b39a1b46319
initial 0.4.4
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 14 Jan 2015 06:51:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_RefCount.h Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,565 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +PublicHeader: Kernel 1.7 +Filename : OVR_RefCount.h 1.8 +Content : Reference counting implementation headers 1.9 +Created : September 19, 2012 1.10 +Notes : 1.11 + 1.12 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.13 + 1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.16 +which is provided at the time of installation or download, or which 1.17 +otherwise accompanies this software in either electronic or hard copy form. 1.18 + 1.19 +You may obtain a copy of the License at 1.20 + 1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.22 + 1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.24 +distributed under the License is distributed on an "AS IS" BASIS, 1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.26 +See the License for the specific language governing permissions and 1.27 +limitations under the License. 1.28 + 1.29 +************************************************************************************/ 1.30 + 1.31 +#ifndef OVR_RefCount_h 1.32 +#define OVR_RefCount_h 1.33 + 1.34 +#include "OVR_Types.h" 1.35 +#include "OVR_Allocator.h" 1.36 + 1.37 +namespace OVR { 1.38 + 1.39 +//----------------------------------------------------------------------------------- 1.40 +// ***** Reference Counting 1.41 + 1.42 +// There are three types of reference counting base classes: 1.43 +// 1.44 +// RefCountBase - Provides thread-safe reference counting (Default). 1.45 +// RefCountBaseNTS - Non Thread Safe version of reference counting. 1.46 + 1.47 + 1.48 +// ***** Declared classes 1.49 + 1.50 +template<class C> 1.51 +class RefCountBase; 1.52 +template<class C> 1.53 +class RefCountBaseNTS; 1.54 + 1.55 +class RefCountImpl; 1.56 +class RefCountNTSImpl; 1.57 + 1.58 + 1.59 +//----------------------------------------------------------------------------------- 1.60 +// ***** Implementation For Reference Counting 1.61 + 1.62 +// RefCountImplCore holds RefCount value and defines a few utility 1.63 +// functions shared by all implementations. 1.64 + 1.65 +class RefCountImplCore 1.66 +{ 1.67 +protected: 1.68 + volatile int RefCount; 1.69 + 1.70 +public: 1.71 + // RefCountImpl constructor always initializes RefCount to 1 by default. 1.72 + OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { } 1.73 + 1.74 + // Need virtual destructor 1.75 + // This: 1. Makes sure the right destructor's called. 1.76 + // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() 1.77 + virtual ~RefCountImplCore(); 1.78 + 1.79 + // Debug method only. 1.80 + int GetRefCount() const { return RefCount; } 1.81 + 1.82 + // This logic is used to detect invalid 'delete' calls of reference counted 1.83 + // objects. Direct delete calls are not allowed on them unless they come in 1.84 + // internally from Release. 1.85 +#ifdef OVR_BUILD_DEBUG 1.86 + static void OVR_CDECL reportInvalidDelete(void *pmem); 1.87 + inline static void checkInvalidDelete(RefCountImplCore *pmem) 1.88 + { 1.89 + if (pmem->RefCount != 0) 1.90 + reportInvalidDelete(pmem); 1.91 + } 1.92 +#else 1.93 + inline static void checkInvalidDelete(RefCountImplCore *) { } 1.94 +#endif 1.95 + 1.96 + // Base class ref-count content should not be copied. 1.97 + void operator = (const RefCountImplCore &) { } 1.98 +}; 1.99 + 1.100 +class RefCountNTSImplCore 1.101 +{ 1.102 +protected: 1.103 + mutable int RefCount; 1.104 + 1.105 +public: 1.106 + // RefCountImpl constructor always initializes RefCount to 1 by default. 1.107 + OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { } 1.108 + 1.109 + // Need virtual destructor 1.110 + // This: 1. Makes sure the right destructor's called. 1.111 + // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() 1.112 + virtual ~RefCountNTSImplCore(); 1.113 + 1.114 + // Debug method only. 1.115 + int GetRefCount() const { return RefCount; } 1.116 + 1.117 + // This logic is used to detect invalid 'delete' calls of reference counted 1.118 + // objects. Direct delete calls are not allowed on them unless they come in 1.119 + // internally from Release. 1.120 +#ifdef OVR_BUILD_DEBUG 1.121 + static void OVR_CDECL reportInvalidDelete(void *pmem); 1.122 + OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem) 1.123 + { 1.124 + if (pmem->RefCount != 0) 1.125 + reportInvalidDelete(pmem); 1.126 + } 1.127 +#else 1.128 + OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { } 1.129 +#endif 1.130 + 1.131 + // Base class ref-count content should not be copied. 1.132 + void operator = (const RefCountNTSImplCore &) { } 1.133 +}; 1.134 + 1.135 + 1.136 + 1.137 +// RefCountImpl provides Thread-Safe implementation of reference counting, so 1.138 +// it should be used by default in most places. 1.139 + 1.140 +class RefCountImpl : public RefCountImplCore 1.141 +{ 1.142 +public: 1.143 + // Thread-Safe Ref-Count Implementation. 1.144 + void AddRef(); 1.145 + void Release(); 1.146 +}; 1.147 + 1.148 +// RefCountVImpl provides Thread-Safe implementation of reference counting, plus, 1.149 +// virtual AddRef and Release. 1.150 + 1.151 +class RefCountVImpl : virtual public RefCountImplCore 1.152 +{ 1.153 +public: 1.154 + // Thread-Safe Ref-Count Implementation. 1.155 + virtual void AddRef(); 1.156 + virtual void Release(); 1.157 +}; 1.158 + 1.159 + 1.160 +// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting, 1.161 +// which is slightly more efficient since it doesn't use atomics. 1.162 + 1.163 +class RefCountNTSImpl : public RefCountNTSImplCore 1.164 +{ 1.165 +public: 1.166 + OVR_FORCE_INLINE void AddRef() const { RefCount++; } 1.167 + void Release() const; 1.168 +}; 1.169 + 1.170 + 1.171 + 1.172 +// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking 1.173 +// to the reference counting implementation. Base must be one of the RefCountImpl classes. 1.174 + 1.175 +template<class Base> 1.176 +class RefCountBaseStatImpl : public Base 1.177 +{ 1.178 +public: 1.179 + RefCountBaseStatImpl() { } 1.180 + 1.181 + // *** Override New and Delete 1.182 + 1.183 + // DOM-IGNORE-BEGIN 1.184 + // Undef new temporarily if it is being redefined 1.185 +#ifdef OVR_DEFINE_NEW 1.186 +#undef new 1.187 +#endif 1.188 + 1.189 +#ifdef OVR_BUILD_DEBUG 1.190 + // Custom check used to detect incorrect calls of 'delete' on ref-counted objects. 1.191 + #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \ 1.192 + do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0) 1.193 +#else 1.194 + #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) 1.195 +#endif 1.196 + 1.197 + // Redefine all new & delete operators. 1.198 + OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) 1.199 + 1.200 +#undef OVR_REFCOUNTALLOC_CHECK_DELETE 1.201 + 1.202 +#ifdef OVR_DEFINE_NEW 1.203 +#define new OVR_DEFINE_NEW 1.204 +#endif 1.205 + // OVR_BUILD_DEFINE_NEW 1.206 + // DOM-IGNORE-END 1.207 +}; 1.208 + 1.209 + 1.210 +template<class Base> 1.211 +class RefCountBaseStatVImpl : virtual public Base 1.212 +{ 1.213 +public: 1.214 + RefCountBaseStatVImpl() { } 1.215 + 1.216 + // *** Override New and Delete 1.217 + 1.218 + // DOM-IGNORE-BEGIN 1.219 + // Undef new temporarily if it is being redefined 1.220 +#ifdef OVR_DEFINE_NEW 1.221 +#undef new 1.222 +#endif 1.223 + 1.224 +#define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) 1.225 + 1.226 + // Redefine all new & delete operators. 1.227 + OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) 1.228 + 1.229 +#undef OVR_REFCOUNTALLOC_CHECK_DELETE 1.230 + 1.231 +#ifdef OVR_DEFINE_NEW 1.232 +#define new OVR_DEFINE_NEW 1.233 +#endif 1.234 + // OVR_BUILD_DEFINE_NEW 1.235 + // DOM-IGNORE-END 1.236 +}; 1.237 + 1.238 + 1.239 + 1.240 +//----------------------------------------------------------------------------------- 1.241 +// *** End user RefCountBase<> classes 1.242 + 1.243 + 1.244 +// RefCountBase is a base class for classes that require thread-safe reference 1.245 +// counting; it also overrides the new and delete operators to use MemoryHeap. 1.246 +// 1.247 +// Reference counted objects start out with RefCount value of 1. Further lifetime 1.248 +// management is done through the AddRef() and Release() methods, typically 1.249 +// hidden by Ptr<>. 1.250 + 1.251 +template<class C> 1.252 +class RefCountBase : public RefCountBaseStatImpl<RefCountImpl> 1.253 +{ 1.254 +public: 1.255 + // Constructor. 1.256 + OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { } 1.257 +}; 1.258 + 1.259 +// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release 1.260 + 1.261 +template<class C> 1.262 +class RefCountBaseV : virtual public RefCountBaseStatVImpl<RefCountVImpl> 1.263 +{ 1.264 +public: 1.265 + // Constructor. 1.266 + OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatVImpl<RefCountVImpl>() { } 1.267 +}; 1.268 + 1.269 + 1.270 +// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference 1.271 +// counting; it also overrides the new and delete operators to use MemoryHeap. 1.272 +// This class should only be used if all pointers to it are known to be assigned, 1.273 +// destroyed and manipulated within one thread. 1.274 +// 1.275 +// Reference counted objects start out with RefCount value of 1. Further lifetime 1.276 +// management is done through the AddRef() and Release() methods, typically 1.277 +// hidden by Ptr<>. 1.278 + 1.279 +template<class C> 1.280 +class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl> 1.281 +{ 1.282 +public: 1.283 + // Constructor. 1.284 + OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { } 1.285 +}; 1.286 + 1.287 +//----------------------------------------------------------------------------------- 1.288 +// ***** Pickable template pointer 1.289 +enum PickType { PickValue }; 1.290 + 1.291 +template <typename T> 1.292 +class Pickable 1.293 +{ 1.294 +public: 1.295 + Pickable() : pV(NULL) {} 1.296 + explicit Pickable(T* p) : pV(p) {} 1.297 + Pickable(T* p, PickType) : pV(p) 1.298 + { 1.299 + OVR_ASSERT(pV); 1.300 + if (pV) 1.301 + pV->AddRef(); 1.302 + } 1.303 + template <typename OT> 1.304 + Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {} 1.305 + 1.306 +public: 1.307 + Pickable& operator =(const Pickable& other) 1.308 + { 1.309 + OVR_ASSERT(pV == NULL); 1.310 + pV = other.pV; 1.311 + // Extra check. 1.312 + //other.pV = NULL; 1.313 + return *this; 1.314 + } 1.315 + 1.316 +public: 1.317 + T* GetPtr() const { return pV; } 1.318 + T* operator->() const 1.319 + { 1.320 + return pV; 1.321 + } 1.322 + T& operator*() const 1.323 + { 1.324 + OVR_ASSERT(pV); 1.325 + return *pV; 1.326 + } 1.327 + 1.328 +private: 1.329 + T* pV; 1.330 +}; 1.331 + 1.332 +template <typename T> 1.333 +OVR_FORCE_INLINE 1.334 +Pickable<T> MakePickable(T* p) 1.335 +{ 1.336 + return Pickable<T>(p); 1.337 +} 1.338 + 1.339 +//----------------------------------------------------------------------------------- 1.340 +// ***** Ref-Counted template pointer 1.341 + 1.342 +// Automatically AddRefs and Releases interfaces 1.343 + 1.344 +void* ReturnArg0(void* p); 1.345 + 1.346 +template<class C> 1.347 +class Ptr 1.348 +{ 1.349 +#ifdef OVR_CC_ARM 1.350 + static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); } 1.351 +#endif 1.352 + 1.353 +protected: 1.354 + C *pObject; 1.355 + 1.356 +public: 1.357 + 1.358 + // Constructors 1.359 + OVR_FORCE_INLINE Ptr() : pObject(0) 1.360 + { } 1.361 +#ifdef OVR_CC_ARM 1.362 + OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj)) 1.363 +#else 1.364 + OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj) 1.365 +#endif 1.366 + { } 1.367 + OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr()) 1.368 + { 1.369 + // No AddRef() on purpose. 1.370 + } 1.371 + OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject) 1.372 + { 1.373 + other.pObject = NULL; 1.374 + // No AddRef() on purpose. 1.375 + } 1.376 + OVR_FORCE_INLINE Ptr(C *pobj) 1.377 + { 1.378 + if (pobj) pobj->AddRef(); 1.379 + pObject = pobj; 1.380 + } 1.381 + OVR_FORCE_INLINE Ptr(const Ptr<C> &src) 1.382 + { 1.383 + if (src.pObject) src.pObject->AddRef(); 1.384 + pObject = src.pObject; 1.385 + } 1.386 + 1.387 + template<class R> 1.388 + OVR_FORCE_INLINE Ptr(Ptr<R> &src) 1.389 + { 1.390 + if (src) src->AddRef(); 1.391 + pObject = src; 1.392 + } 1.393 + template<class R> 1.394 + OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr()) 1.395 + { 1.396 + // No AddRef() on purpose. 1.397 + } 1.398 + 1.399 + // Destructor 1.400 + OVR_FORCE_INLINE ~Ptr() 1.401 + { 1.402 + if (pObject) pObject->Release(); 1.403 + } 1.404 + 1.405 + // Compares 1.406 + OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; } 1.407 + OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; } 1.408 + 1.409 + OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; } 1.410 + OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; } 1.411 + 1.412 + 1.413 + OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; } 1.414 + 1.415 + // Assignment 1.416 + template<class R> 1.417 + OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src) 1.418 + { 1.419 + // By design we don't check for src == pObject, as we don't expect that to be the case the large majority of the time. 1.420 + if (src) src->AddRef(); 1.421 + if (pObject) pObject->Release(); 1.422 + pObject = src; 1.423 + return *this; 1.424 + } 1.425 + // Specialization 1.426 + OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src) 1.427 + { 1.428 + if (src) src->AddRef(); 1.429 + if (pObject) pObject->Release(); 1.430 + pObject = src; 1.431 + return *this; 1.432 + } 1.433 + 1.434 + OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc) 1.435 + { 1.436 + if (psrc) psrc->AddRef(); 1.437 + if (pObject) pObject->Release(); 1.438 + pObject = psrc; 1.439 + return *this; 1.440 + } 1.441 + OVR_FORCE_INLINE const Ptr<C>& operator = (C &src) 1.442 + { 1.443 + if (pObject) pObject->Release(); 1.444 + pObject = &src; 1.445 + return *this; 1.446 + } 1.447 + OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src) 1.448 + { 1.449 + return Pick(src); 1.450 + } 1.451 + template<class R> 1.452 + OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src) 1.453 + { 1.454 + return Pick(src); 1.455 + } 1.456 + 1.457 + // Set Assignment 1.458 + template<class R> 1.459 + OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src) 1.460 + { 1.461 + if (src) src->AddRef(); 1.462 + if (pObject) pObject->Release(); 1.463 + pObject = src; 1.464 + return *this; 1.465 + } 1.466 + // Specialization 1.467 + OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src) 1.468 + { 1.469 + if (src) src->AddRef(); 1.470 + if (pObject) pObject->Release(); 1.471 + pObject = src; 1.472 + return *this; 1.473 + } 1.474 + 1.475 + OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc) 1.476 + { 1.477 + if (psrc) psrc->AddRef(); 1.478 + if (pObject) pObject->Release(); 1.479 + pObject = psrc; 1.480 + return *this; 1.481 + } 1.482 + OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src) 1.483 + { 1.484 + if (pObject) pObject->Release(); 1.485 + pObject = &src; 1.486 + return *this; 1.487 + } 1.488 + OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src) 1.489 + { 1.490 + return Pick(src); 1.491 + } 1.492 + 1.493 + // Nulls ref-counted pointer without decrement 1.494 + OVR_FORCE_INLINE void NullWithoutRelease() 1.495 + { 1.496 + pObject = 0; 1.497 + } 1.498 + 1.499 + // Clears the pointer to the object 1.500 + OVR_FORCE_INLINE void Clear() 1.501 + { 1.502 + if (pObject) pObject->Release(); 1.503 + pObject = 0; 1.504 + } 1.505 + 1.506 + // Obtain pointer reference directly, for D3D interfaces 1.507 + OVR_FORCE_INLINE C*& GetRawRef() { return pObject; } 1.508 + 1.509 + // Access Operators 1.510 + OVR_FORCE_INLINE C* GetPtr() const { return pObject; } 1.511 + OVR_FORCE_INLINE C& operator * () const { return *pObject; } 1.512 + OVR_FORCE_INLINE C* operator -> () const { return pObject; } 1.513 + // Conversion 1.514 + OVR_FORCE_INLINE operator C* () const { return pObject; } 1.515 + 1.516 + // Pickers. 1.517 + 1.518 + // Pick a value. 1.519 + OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other) 1.520 + { 1.521 + if (&other != this) 1.522 + { 1.523 + if (pObject) pObject->Release(); 1.524 + pObject = other.pObject; 1.525 + other.pObject = 0; 1.526 + } 1.527 + 1.528 + return *this; 1.529 + } 1.530 + 1.531 + OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v) 1.532 + { 1.533 + if (v.GetPtr() != pObject) 1.534 + { 1.535 + if (pObject) pObject->Release(); 1.536 + pObject = v.GetPtr(); 1.537 + } 1.538 + 1.539 + return *this; 1.540 + } 1.541 + 1.542 + template<class R> 1.543 + OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v) 1.544 + { 1.545 + if (v.GetPtr() != pObject) 1.546 + { 1.547 + if (pObject) pObject->Release(); 1.548 + pObject = v.GetPtr(); 1.549 + } 1.550 + 1.551 + return *this; 1.552 + } 1.553 + 1.554 + OVR_FORCE_INLINE Ptr<C>& Pick(C* p) 1.555 + { 1.556 + if (p != pObject) 1.557 + { 1.558 + if (pObject) pObject->Release(); 1.559 + pObject = p; 1.560 + } 1.561 + 1.562 + return *this; 1.563 + } 1.564 +}; 1.565 + 1.566 +} // OVR 1.567 + 1.568 +#endif