ovr_sdk

view 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 source
1 /************************************************************************************
3 PublicHeader: Kernel
4 Filename : OVR_RefCount.h
5 Content : Reference counting implementation headers
6 Created : September 19, 2012
7 Notes :
9 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
11 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
12 you may not use the Oculus VR Rift SDK except in compliance with the License,
13 which is provided at the time of installation or download, or which
14 otherwise accompanies this software in either electronic or hard copy form.
16 You may obtain a copy of the License at
18 http://www.oculusvr.com/licenses/LICENSE-3.2
20 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
26 ************************************************************************************/
28 #ifndef OVR_RefCount_h
29 #define OVR_RefCount_h
31 #include "OVR_Types.h"
32 #include "OVR_Allocator.h"
34 namespace OVR {
36 //-----------------------------------------------------------------------------------
37 // ***** Reference Counting
39 // There are three types of reference counting base classes:
40 //
41 // RefCountBase - Provides thread-safe reference counting (Default).
42 // RefCountBaseNTS - Non Thread Safe version of reference counting.
45 // ***** Declared classes
47 template<class C>
48 class RefCountBase;
49 template<class C>
50 class RefCountBaseNTS;
52 class RefCountImpl;
53 class RefCountNTSImpl;
56 //-----------------------------------------------------------------------------------
57 // ***** Implementation For Reference Counting
59 // RefCountImplCore holds RefCount value and defines a few utility
60 // functions shared by all implementations.
62 class RefCountImplCore
63 {
64 protected:
65 volatile int RefCount;
67 public:
68 // RefCountImpl constructor always initializes RefCount to 1 by default.
69 OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { }
71 // Need virtual destructor
72 // This: 1. Makes sure the right destructor's called.
73 // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
74 virtual ~RefCountImplCore();
76 // Debug method only.
77 int GetRefCount() const { return RefCount; }
79 // This logic is used to detect invalid 'delete' calls of reference counted
80 // objects. Direct delete calls are not allowed on them unless they come in
81 // internally from Release.
82 #ifdef OVR_BUILD_DEBUG
83 static void OVR_CDECL reportInvalidDelete(void *pmem);
84 inline static void checkInvalidDelete(RefCountImplCore *pmem)
85 {
86 if (pmem->RefCount != 0)
87 reportInvalidDelete(pmem);
88 }
89 #else
90 inline static void checkInvalidDelete(RefCountImplCore *) { }
91 #endif
93 // Base class ref-count content should not be copied.
94 void operator = (const RefCountImplCore &) { }
95 };
97 class RefCountNTSImplCore
98 {
99 protected:
100 mutable int RefCount;
102 public:
103 // RefCountImpl constructor always initializes RefCount to 1 by default.
104 OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { }
106 // Need virtual destructor
107 // This: 1. Makes sure the right destructor's called.
108 // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
109 virtual ~RefCountNTSImplCore();
111 // Debug method only.
112 int GetRefCount() const { return RefCount; }
114 // This logic is used to detect invalid 'delete' calls of reference counted
115 // objects. Direct delete calls are not allowed on them unless they come in
116 // internally from Release.
117 #ifdef OVR_BUILD_DEBUG
118 static void OVR_CDECL reportInvalidDelete(void *pmem);
119 OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
120 {
121 if (pmem->RefCount != 0)
122 reportInvalidDelete(pmem);
123 }
124 #else
125 OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
126 #endif
128 // Base class ref-count content should not be copied.
129 void operator = (const RefCountNTSImplCore &) { }
130 };
134 // RefCountImpl provides Thread-Safe implementation of reference counting, so
135 // it should be used by default in most places.
137 class RefCountImpl : public RefCountImplCore
138 {
139 public:
140 // Thread-Safe Ref-Count Implementation.
141 void AddRef();
142 void Release();
143 };
145 // RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
146 // virtual AddRef and Release.
148 class RefCountVImpl : virtual public RefCountImplCore
149 {
150 public:
151 // Thread-Safe Ref-Count Implementation.
152 virtual void AddRef();
153 virtual void Release();
154 };
157 // RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
158 // which is slightly more efficient since it doesn't use atomics.
160 class RefCountNTSImpl : public RefCountNTSImplCore
161 {
162 public:
163 OVR_FORCE_INLINE void AddRef() const { RefCount++; }
164 void Release() const;
165 };
169 // RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
170 // to the reference counting implementation. Base must be one of the RefCountImpl classes.
172 template<class Base>
173 class RefCountBaseStatImpl : public Base
174 {
175 public:
176 RefCountBaseStatImpl() { }
178 // *** Override New and Delete
180 // DOM-IGNORE-BEGIN
181 // Undef new temporarily if it is being redefined
182 #ifdef OVR_DEFINE_NEW
183 #undef new
184 #endif
186 #ifdef OVR_BUILD_DEBUG
187 // Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
188 #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
189 do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
190 #else
191 #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
192 #endif
194 // Redefine all new & delete operators.
195 OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
197 #undef OVR_REFCOUNTALLOC_CHECK_DELETE
199 #ifdef OVR_DEFINE_NEW
200 #define new OVR_DEFINE_NEW
201 #endif
202 // OVR_BUILD_DEFINE_NEW
203 // DOM-IGNORE-END
204 };
207 template<class Base>
208 class RefCountBaseStatVImpl : virtual public Base
209 {
210 public:
211 RefCountBaseStatVImpl() { }
213 // *** Override New and Delete
215 // DOM-IGNORE-BEGIN
216 // Undef new temporarily if it is being redefined
217 #ifdef OVR_DEFINE_NEW
218 #undef new
219 #endif
221 #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
223 // Redefine all new & delete operators.
224 OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE)
226 #undef OVR_REFCOUNTALLOC_CHECK_DELETE
228 #ifdef OVR_DEFINE_NEW
229 #define new OVR_DEFINE_NEW
230 #endif
231 // OVR_BUILD_DEFINE_NEW
232 // DOM-IGNORE-END
233 };
237 //-----------------------------------------------------------------------------------
238 // *** End user RefCountBase<> classes
241 // RefCountBase is a base class for classes that require thread-safe reference
242 // counting; it also overrides the new and delete operators to use MemoryHeap.
243 //
244 // Reference counted objects start out with RefCount value of 1. Further lifetime
245 // management is done through the AddRef() and Release() methods, typically
246 // hidden by Ptr<>.
248 template<class C>
249 class RefCountBase : public RefCountBaseStatImpl<RefCountImpl>
250 {
251 public:
252 // Constructor.
253 OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { }
254 };
256 // RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
258 template<class C>
259 class RefCountBaseV : virtual public RefCountBaseStatVImpl<RefCountVImpl>
260 {
261 public:
262 // Constructor.
263 OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatVImpl<RefCountVImpl>() { }
264 };
267 // RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
268 // counting; it also overrides the new and delete operators to use MemoryHeap.
269 // This class should only be used if all pointers to it are known to be assigned,
270 // destroyed and manipulated within one thread.
271 //
272 // Reference counted objects start out with RefCount value of 1. Further lifetime
273 // management is done through the AddRef() and Release() methods, typically
274 // hidden by Ptr<>.
276 template<class C>
277 class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl>
278 {
279 public:
280 // Constructor.
281 OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { }
282 };
284 //-----------------------------------------------------------------------------------
285 // ***** Pickable template pointer
286 enum PickType { PickValue };
288 template <typename T>
289 class Pickable
290 {
291 public:
292 Pickable() : pV(NULL) {}
293 explicit Pickable(T* p) : pV(p) {}
294 Pickable(T* p, PickType) : pV(p)
295 {
296 OVR_ASSERT(pV);
297 if (pV)
298 pV->AddRef();
299 }
300 template <typename OT>
301 Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
303 public:
304 Pickable& operator =(const Pickable& other)
305 {
306 OVR_ASSERT(pV == NULL);
307 pV = other.pV;
308 // Extra check.
309 //other.pV = NULL;
310 return *this;
311 }
313 public:
314 T* GetPtr() const { return pV; }
315 T* operator->() const
316 {
317 return pV;
318 }
319 T& operator*() const
320 {
321 OVR_ASSERT(pV);
322 return *pV;
323 }
325 private:
326 T* pV;
327 };
329 template <typename T>
330 OVR_FORCE_INLINE
331 Pickable<T> MakePickable(T* p)
332 {
333 return Pickable<T>(p);
334 }
336 //-----------------------------------------------------------------------------------
337 // ***** Ref-Counted template pointer
339 // Automatically AddRefs and Releases interfaces
341 void* ReturnArg0(void* p);
343 template<class C>
344 class Ptr
345 {
346 #ifdef OVR_CC_ARM
347 static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
348 #endif
350 protected:
351 C *pObject;
353 public:
355 // Constructors
356 OVR_FORCE_INLINE Ptr() : pObject(0)
357 { }
358 #ifdef OVR_CC_ARM
359 OVR_FORCE_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
360 #else
361 OVR_FORCE_INLINE Ptr(C &robj) : pObject(&robj)
362 #endif
363 { }
364 OVR_FORCE_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
365 {
366 // No AddRef() on purpose.
367 }
368 OVR_FORCE_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
369 {
370 other.pObject = NULL;
371 // No AddRef() on purpose.
372 }
373 OVR_FORCE_INLINE Ptr(C *pobj)
374 {
375 if (pobj) pobj->AddRef();
376 pObject = pobj;
377 }
378 OVR_FORCE_INLINE Ptr(const Ptr<C> &src)
379 {
380 if (src.pObject) src.pObject->AddRef();
381 pObject = src.pObject;
382 }
384 template<class R>
385 OVR_FORCE_INLINE Ptr(Ptr<R> &src)
386 {
387 if (src) src->AddRef();
388 pObject = src;
389 }
390 template<class R>
391 OVR_FORCE_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
392 {
393 // No AddRef() on purpose.
394 }
396 // Destructor
397 OVR_FORCE_INLINE ~Ptr()
398 {
399 if (pObject) pObject->Release();
400 }
402 // Compares
403 OVR_FORCE_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
404 OVR_FORCE_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
406 OVR_FORCE_INLINE bool operator == (C *pother) const { return pObject == pother; }
407 OVR_FORCE_INLINE bool operator != (C *pother) const { return pObject != pother; }
410 OVR_FORCE_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
412 // Assignment
413 template<class R>
414 OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
415 {
416 // 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.
417 if (src) src->AddRef();
418 if (pObject) pObject->Release();
419 pObject = src;
420 return *this;
421 }
422 // Specialization
423 OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
424 {
425 if (src) src->AddRef();
426 if (pObject) pObject->Release();
427 pObject = src;
428 return *this;
429 }
431 OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc)
432 {
433 if (psrc) psrc->AddRef();
434 if (pObject) pObject->Release();
435 pObject = psrc;
436 return *this;
437 }
438 OVR_FORCE_INLINE const Ptr<C>& operator = (C &src)
439 {
440 if (pObject) pObject->Release();
441 pObject = &src;
442 return *this;
443 }
444 OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<C> src)
445 {
446 return Pick(src);
447 }
448 template<class R>
449 OVR_FORCE_INLINE Ptr<C>& operator = (Pickable<R> src)
450 {
451 return Pick(src);
452 }
454 // Set Assignment
455 template<class R>
456 OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
457 {
458 if (src) src->AddRef();
459 if (pObject) pObject->Release();
460 pObject = src;
461 return *this;
462 }
463 // Specialization
464 OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
465 {
466 if (src) src->AddRef();
467 if (pObject) pObject->Release();
468 pObject = src;
469 return *this;
470 }
472 OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc)
473 {
474 if (psrc) psrc->AddRef();
475 if (pObject) pObject->Release();
476 pObject = psrc;
477 return *this;
478 }
479 OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src)
480 {
481 if (pObject) pObject->Release();
482 pObject = &src;
483 return *this;
484 }
485 OVR_FORCE_INLINE Ptr<C>& SetPtr(Pickable<C> src)
486 {
487 return Pick(src);
488 }
490 // Nulls ref-counted pointer without decrement
491 OVR_FORCE_INLINE void NullWithoutRelease()
492 {
493 pObject = 0;
494 }
496 // Clears the pointer to the object
497 OVR_FORCE_INLINE void Clear()
498 {
499 if (pObject) pObject->Release();
500 pObject = 0;
501 }
503 // Obtain pointer reference directly, for D3D interfaces
504 OVR_FORCE_INLINE C*& GetRawRef() { return pObject; }
506 // Access Operators
507 OVR_FORCE_INLINE C* GetPtr() const { return pObject; }
508 OVR_FORCE_INLINE C& operator * () const { return *pObject; }
509 OVR_FORCE_INLINE C* operator -> () const { return pObject; }
510 // Conversion
511 OVR_FORCE_INLINE operator C* () const { return pObject; }
513 // Pickers.
515 // Pick a value.
516 OVR_FORCE_INLINE Ptr<C>& Pick(Ptr<C>& other)
517 {
518 if (&other != this)
519 {
520 if (pObject) pObject->Release();
521 pObject = other.pObject;
522 other.pObject = 0;
523 }
525 return *this;
526 }
528 OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<C> v)
529 {
530 if (v.GetPtr() != pObject)
531 {
532 if (pObject) pObject->Release();
533 pObject = v.GetPtr();
534 }
536 return *this;
537 }
539 template<class R>
540 OVR_FORCE_INLINE Ptr<C>& Pick(Pickable<R> v)
541 {
542 if (v.GetPtr() != pObject)
543 {
544 if (pObject) pObject->Release();
545 pObject = v.GetPtr();
546 }
548 return *this;
549 }
551 OVR_FORCE_INLINE Ptr<C>& Pick(C* p)
552 {
553 if (p != pObject)
554 {
555 if (pObject) pObject->Release();
556 pObject = p;
557 }
559 return *this;
560 }
561 };
563 } // OVR
565 #endif