gwnavruntime/kernel/SF_RefCount.h Source File

SF_RefCount.h
Go to the documentation of this file.
1 /*
2 * Copyright 2015 Autodesk, Inc. All rights reserved.
3 * Use of this software is subject to the terms of the Autodesk license agreement and any attachments or Appendices thereto provided at the time of installation or download,
4 * or which otherwise accompanies this software in either electronic or hard copy form, or which is signed by you and accepted by Autodesk.
5 */
6 
7 /**************************************************************************
8 
9 PublicHeader: Kernel
10 Filename : KY_RefCount.h
11 Content : Reference counting implementation headers
12 Created : January 14, 1999
13 Authors : Michael Antonov, Maxim Shemanarev, Sergey Sikorskiy
14 
15 **************************************************************************/
16 
17 #ifndef INC_KY_Kernel_RefCount_H
18 #define INC_KY_Kernel_RefCount_H
19 
22 
23 namespace Kaim {
24 
25 // ***** Reference Counting
26 
27 // There are three types of reference counting base classes:
28 //
29 // RefCountBase - Provides thread-safe reference counting (Default).
30 // RefCountBaseNTS - Non Thread Safe version of reference counting.
31 // RefCountBaseWeakSupport - Non Thread Safe ref-counting with WeakPtr support.
32 
33 
34 // ***** Declared classes
35 
36 template<class C, int StatType>
37 class RefCountBase;
38 template<class C, int StatType>
39 class RefCountBaseNTS;
40 template<class C, int StatType>
41 class RefCountBaseWeakSupport;
42 
43 class RefCountImpl;
44 class RefCountNTSImpl;
45 class RefCountWeakSupportImpl;
46 //class RefCountImpl;
47 
48 template<class C>
49 class WeakPtr;
50 class WeakPtrProxy;
51 
52 
53 // *** Macros for RefCountBase
54 
55 // These macros specify whether reference counting is configured to be
56 // thread safe or not. By default, reference counting is not thread-safe
57 // for most classes.
58 #define KY_REFCOUNT_NORMAL 0x00000000
59 #define KY_REFCOUNT_THREADSAFE 0x00000001
60 
61 
62 // ***** Implementation For Reference Counting
63 
64 // RefCountImplCore holds RefCount value and defines a few utility
65 // functions shared by all implementations.
66 
67 class RefCountImplCore
68 {
69 protected:
70  volatile int RefCount;
71 
72 public:
73  // RefCountImpl constructor always initializes RefCount to 1 by default.
74  KY_INLINE RefCountImplCore() : RefCount(1) { }
75 
76  // Need virtual destructor
77  // This: 1. Makes sure the right destructor's called.
78  // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
79  KY_EXPORT virtual ~RefCountImplCore();
80 
81  // Debug method only.
82  int GetRefCount() const { return RefCount; }
83 
84  // This logic is used to detect invalid 'delete' calls of reference counted
85  // objects. Direct delete calls are not allowed on them unless they come in
86  // internally from Release.
87 #ifdef KY_BUILD_DEBUG
88  static void KY_CDECL reportInvalidDelete(void *pmem);
89  inline static void checkInvalidDelete(RefCountImplCore *pmem)
90  {
91  if (pmem->RefCount != 0)
92  reportInvalidDelete(pmem);
93  }
94 #else
95  inline static void checkInvalidDelete(RefCountImplCore *) { }
96 #endif
97 
98  // Base class ref-count content should not be copied.
99  RefCountImplCore(const RefCountImplCore &) : RefCount(1) { }
100  void operator = (const RefCountImplCore &) { }
101 };
102 
103 class RefCountNTSImplCore
104 {
105 protected:
106  mutable int RefCount;
107 
108 public:
109  // RefCountImpl constructor always initializes RefCount to 1 by default.
110  KY_INLINE RefCountNTSImplCore() : RefCount(1) { }
111 
112  // Need virtual destructor
113  // This: 1. Makes sure the right destructor's called.
114  // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem()
115  KY_EXPORT virtual ~RefCountNTSImplCore();
116 
117  // Debug method only.
118  int GetRefCount() const { return RefCount; }
119 
120  // This logic is used to detect invalid 'delete' calls of reference counted
121  // objects. Direct delete calls are not allowed on them unless they come in
122  // internally from Release.
123 #ifdef KY_BUILD_DEBUG
124  static void KY_CDECL reportInvalidDelete(void *pmem);
125  KY_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem)
126  {
127  if (pmem->RefCount != 0)
128  reportInvalidDelete(pmem);
129  }
130 #else
131  KY_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { }
132 #endif
133 
134  // Base class ref-count content should not be copied.
135  RefCountNTSImplCore(const RefCountNTSImplCore &) : RefCount(1) { }
136  void operator = (const RefCountNTSImplCore &) { }
137 };
138 
139 
140 
141 // RefCountImpl provides Thread-Safe implementation of reference counting, so
142 // it should be used by default in most places.
143 
144 class RefCountImpl : public RefCountImplCore
145 {
146 public:
147  // Thread-Safe Ref-Count Implementation.
148  KY_EXPORT void AddRef();
149  KY_EXPORT void Release();
150 };
151 
152 // RefCountVImpl provides Thread-Safe implementation of reference counting, plus,
153 // virtual AddRef and Release.
154 
155 class RefCountVImpl : public RefCountImplCore
156 {
157 public:
158  // Thread-Safe Ref-Count Implementation.
159  virtual void AddRef();
160  virtual void Release();
161 };
162 
163 
164 // RefCountImplNTS provides Non-Thread-Safe implementation of reference counting,
165 // which is slightly more efficient since it doesn't use atomics.
166 
167 class RefCountNTSImpl : public RefCountNTSImplCore
168 {
169 public:
170  KY_INLINE void AddRef() const { RefCount++; }
171  KY_EXPORT void Release() const;
172 };
173 
174 // RefCountWeakSupportImpl provides reference counting with WeakProxy support,
175 // allowing for WeakPtr<> to be used on objects derived from this class. Weak pointer
176 // support is non-thread safe. Weak pointers are used for some ActionScript objects,
177 // especially when GC is disabled.
178 
179 class RefCountWeakSupportImpl : public RefCountNTSImpl
180 {
181 protected:
182  mutable WeakPtrProxy* pWeakProxy;
183 public:
184  RefCountWeakSupportImpl() { pWeakProxy = 0; }
185  KY_EXPORT virtual ~RefCountWeakSupportImpl();
186 
187  // Create/return create proxy, users must release proxy when no longer needed.
188  WeakPtrProxy* CreateWeakProxy() const;
189 };
190 
191 
192 // RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking
193 // to the reference counting implemenation. Base must be one of the RefCountImpl classes.
194 
195 template<class Base, int StatType>
196 class RefCountBaseStatImpl : public Base
197 {
198 public:
199  RefCountBaseStatImpl() { }
200 
201  // *** Override New and Delete
202 
203  // DOM-IGNORE-BEGIN
204  // Undef new temporarily if it is being redefined
205 #ifdef KY_BUILD_DEFINE_NEW
206 #ifdef KY_DEFINE_NEW
207 #undef new
208 #endif
209 #endif
210 
211 #ifdef KY_BUILD_DEBUG
212  // Custom check used to detect incorrect calls of 'delete' on ref-counted objects.
213  #define KY_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \
214  do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0)
215 #else
216  #define KY_REFCOUNTALLOC_CHECK_DELETE(class_name, p)
217 #endif
218 
219  // Redefine all new & delete operators.
220  KY_MEMORY_REDEFINE_NEW_IMPL(Base, KY_REFCOUNTALLOC_CHECK_DELETE, StatType)
221 
222 #ifdef KY_DEFINE_NEW
223 #define new KY_DEFINE_NEW
224 #endif
225  // KY_BUILD_DEFINE_NEW
226  // DOM-IGNORE-END
227 };
228 
229 
230 
231 
232 // *** End user RefCountBase<> classes
233 
234 
235 // RefCountBase is a base class for classes that require thread-safe reference
236 // counting; it also overrides the new and delete operators to use MemoryHeap.
237 //
238 // Reference counted objects start out with RefCount value of 1. Further lifetame
239 // management is done through the AddRef() and Release() methods, typically
240 // hidden by Ptr<>.
241 
242 template<class C, int Stat>
243 class RefCountBase : public RefCountBaseStatImpl<RefCountImpl, Stat>
244 {
245 public:
246  enum { StatType = Stat };
247  // Constructor.
248  KY_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl, Stat>() { }
249 };
250 
251 // RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release
252 
253 template<class C, int Stat>
254 class RefCountBaseV : public RefCountBaseStatImpl<RefCountVImpl, Stat>
255 {
256 public:
257  enum { StatType = Stat };
258  // Constructor.
259  KY_INLINE RefCountBaseV() : RefCountBaseStatImpl<RefCountVImpl, Stat>() { }
260 };
261 
262 
263 // RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference
264 // counting; it also overrides the new and delete operators to use MemoryHeap.
265 // This class should only be used if all pointers to it are known to be assigned,
266 // destroyed and manipulated within one thread.
267 //
268 // Reference counted objects start out with RefCount value of 1. Further lifetame
269 // management is done through the AddRef() and Release() methods, typically
270 // hidden by Ptr<>.
271 
272 template<class C, int Stat>
273 class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl, Stat>
274 {
275 public:
276  enum { StatType = Stat };
277  // Constructor.
278  KY_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl, Stat>() { }
279 };
280 
281 // RefCountBaseWeakSupport is a base class for classes that require Non-Thread-Safe
282 // reference counting and WeakPtr<> support; it also overrides the new and delete
283 // operators to use MemoryHeap. This class should only be used if all pointers to it
284 // are known to be assigned, destroyed and manipulated within one thread.
285 //
286 // Reference counted objects start out with RefCount value of 1. Further lifetame
287 // management is done through the AddRef() and Release() methods, typically
288 // hidden by Ptr<>.
289 
290 template<class C, int Stat>
291 class RefCountBaseWeakSupport : public RefCountBaseStatImpl<RefCountWeakSupportImpl, Stat>
292 {
293 public:
294  enum { StatType = Stat };
295  // Constructor.
296  KY_INLINE RefCountBaseWeakSupport() : RefCountBaseStatImpl<RefCountWeakSupportImpl, Stat>() { }
297 };
298 
299 
300 
301 // ***** Pickable template pointer
302 enum PickType { PickValue };
303 
304 template <typename T>
305 class Pickable
306 {
307 public:
308  Pickable() : pV(NULL) {}
309  explicit Pickable(T* p) : pV(p) {}
310  Pickable(T* p, PickType) : pV(p)
311  {
312  KY_ASSERT(pV);
313  if (pV)
314  pV->AddRef();
315  }
316  template <typename OT>
317  Pickable(const Pickable<OT>& other) : pV(other.GetPtr()) {}
318 
319 public:
320  Pickable& operator =(const Pickable& other)
321  {
322  KY_ASSERT(pV == NULL);
323  pV = other.pV;
324  // Extra check.
325  //other.pV = NULL;
326  return *this;
327  }
328 
329 public:
330  T* GetPtr() const { return pV; }
331  T* operator->() const
332  {
333  return pV;
334  }
335  T& operator*() const
336  {
337  KY_ASSERT(pV);
338  return *pV;
339  }
340 
341 private:
342  T* pV;
343 };
344 
345 template <typename T>
346 KY_INLINE
347 Pickable<T> MakePickable(T* p)
348 {
349  return Pickable<T>(p);
350 }
351 
352 // ***** Ref-Counted template pointer
353 
354 // Automatically AddRefs and Releases interfaces
355 
356 void* ReturnArg0(void* p);
357 
358 template<class C>
359 class Ptr
360 {
361 #ifdef KY_CC_ARM
362  static C* ReturnArg(void* p) { return (C*)ReturnArg0(p); }
363 #endif
364 
365 protected:
366  C *pObject;
367 
368 public:
369 
370  // Constructors
371  KY_INLINE Ptr() : pObject(0)
372  { }
373 #ifdef KY_CC_ARM
374  KY_INLINE Ptr(C &robj) : pObject(ReturnArg(&robj))
375 #else
376  KY_INLINE Ptr(C &robj) : pObject(&robj)
377 #endif
378  { }
379  KY_INLINE Ptr(Pickable<C> v) : pObject(v.GetPtr())
380  {
381  // No AddRef() on purpose.
382  }
383  KY_INLINE Ptr(Ptr<C>& other, PickType) : pObject(other.pObject)
384  {
385  other.pObject = NULL;
386  // No AddRef() on purpose.
387  }
388  KY_INLINE Ptr(C *pobj)
389  {
390  if (pobj) pobj->AddRef();
391  pObject = pobj;
392  }
393  KY_INLINE Ptr(const Ptr<C> &src)
394  {
395  if (src.pObject) src.pObject->AddRef();
396  pObject = src.pObject;
397  }
398 
399  template<class R>
400  KY_INLINE Ptr(Ptr<R> &src)
401  {
402  if (src) src->AddRef();
403  pObject = src;
404  }
405  template<class R>
406  KY_INLINE Ptr(Pickable<R> v) : pObject(v.GetPtr())
407  {
408  // No AddRef() on purpose.
409  }
410 
411  // Destructor
412  KY_INLINE ~Ptr()
413  {
414  if (pObject) pObject->Release();
415  }
416 
417  // Compares
418  KY_INLINE bool operator == (const Ptr &other) const { return pObject == other.pObject; }
419  KY_INLINE bool operator != (const Ptr &other) const { return pObject != other.pObject; }
420 
421  KY_INLINE bool operator == (C *pother) const { return pObject == pother; }
422  KY_INLINE bool operator != (C *pother) const { return pObject != pother; }
423 
424 
425  KY_INLINE bool operator < (const Ptr &other) const { return pObject < other.pObject; }
426 
427  // Assignment
428  template<class R>
429  KY_INLINE const Ptr<C>& operator = (const Ptr<R> &src)
430  {
431  if (src) src->AddRef();
432  if (pObject) pObject->Release();
433  pObject = src;
434  return *this;
435  }
436  // Specialization
437  KY_INLINE const Ptr<C>& operator = (const Ptr<C> &src)
438  {
439  if (src) src->AddRef();
440  if (pObject) pObject->Release();
441  pObject = src;
442  return *this;
443  }
444 
445  KY_INLINE const Ptr<C>& operator = (C *psrc)
446  {
447  if (psrc) psrc->AddRef();
448  if (pObject) pObject->Release();
449  pObject = psrc;
450  return *this;
451  }
452  KY_INLINE const Ptr<C>& operator = (C &src)
453  {
454  if (pObject) pObject->Release();
455  pObject = &src;
456  return *this;
457  }
458  KY_INLINE Ptr<C>& operator = (Pickable<C> src)
459  {
460  return Pick(src);
461  }
462  template<class R>
463  KY_INLINE Ptr<C>& operator = (Pickable<R> src)
464  {
465  return Pick(src);
466  }
467 
468  // Set Assignment
469  template<class R>
470  KY_INLINE Ptr<C>& SetPtr(const Ptr<R> &src)
471  {
472  if (src) src->AddRef();
473  if (pObject) pObject->Release();
474  pObject = src;
475  return *this;
476  }
477  // Specialization
478  KY_INLINE Ptr<C>& SetPtr(const Ptr<C> &src)
479  {
480  if (src) src->AddRef();
481  if (pObject) pObject->Release();
482  pObject = src;
483  return *this;
484  }
485 
486  KY_INLINE Ptr<C>& SetPtr(C *psrc)
487  {
488  if (psrc) psrc->AddRef();
489  if (pObject) pObject->Release();
490  pObject = psrc;
491  return *this;
492  }
493  KY_INLINE Ptr<C>& SetPtr(C &src)
494  {
495  if (pObject) pObject->Release();
496  pObject = &src;
497  return *this;
498  }
499  KY_INLINE Ptr<C>& SetPtr(Pickable<C> src)
500  {
501  return Pick(src);
502  }
503 
504  // Nulls ref-counted pointer without decrement
505  KY_INLINE void NullWithoutRelease()
506  {
507  pObject = 0;
508  }
509 
510  // Clears the pointer to the object
511  KY_INLINE void Clear()
512  {
513  if (pObject) pObject->Release();
514  pObject = 0;
515  }
516 
517  // Obtain pointer reference directly, for D3D interfaces
518  KY_INLINE C*& GetRawRef() { return pObject; }
519 
520  // Access Operators
521  KY_INLINE C* GetPtr() const { return pObject; }
522  KY_INLINE C& operator * () const { return *pObject; }
523  KY_INLINE C* operator -> () const { return pObject; }
524  // Conversion
525  KY_INLINE operator C* () const { return pObject; }
526 
527  // Pickers.
528 
529  // Pick a value.
530  KY_INLINE Ptr<C>& Pick(Ptr<C>& other)
531  {
532  if (&other != this)
533  {
534  if (pObject) pObject->Release();
535  pObject = other.pObject;
536  other.pObject = 0;
537  }
538 
539  return *this;
540  }
541 
542  KY_INLINE Ptr<C>& Pick(Pickable<C> v)
543  {
544  if (v.GetPtr() != pObject)
545  {
546  if (pObject) pObject->Release();
547  pObject = v.GetPtr();
548  }
549 
550  return *this;
551  }
552 
553  template<class R>
554  KY_INLINE Ptr<C>& Pick(Pickable<R> v)
555  {
556  if (v.GetPtr() != pObject)
557  {
558  if (pObject) pObject->Release();
559  pObject = v.GetPtr();
560  }
561 
562  return *this;
563  }
564 
565  KY_INLINE Ptr<C>& Pick(C* p)
566  {
567  if (p != pObject)
568  {
569  if (pObject) pObject->Release();
570  pObject = p;
571  }
572 
573  return *this;
574  }
575 };
576 
577 
578 
579 // *** Weak Pointer Support
580 
581 // Helper for making objects that can have weak_ptr's.
582 // TBD: Converted WeakPtr logic is not thread-safe, need to work this out
583 
584 class WeakPtrProxy : public NewOverrideBase<Stat_Default_Mem>
585 {
586 public:
587  WeakPtrProxy(RefCountWeakSupportImpl* pobject)
588  : RefCount(1), pObject(pobject)
589  { }
590 
591  // WeakPtr calls this to determine if its pointer is valid or not
592  KY_INLINE bool IsAlive() const { return (pObject != 0); }
593 
594  // Objects call this to inform of their death
595  KY_INLINE void NotifyObjectDied() { pObject = 0; }
596 
597  RefCountWeakSupportImpl* GetObject() const { return pObject; }
598 
599  KY_INLINE void AddRef()
600  {
601  RefCount++;
602  // Uncomment this to track potential bad use of Ptr
603  //KY_ASSERT(RefCount > -1 && RefCount < 0x00FFFFFF);
604  }
605 
606  KY_INLINE void Release()
607  {
608  // Uncomment this to track potential bad use of Ptr
609  //KY_ASSERT(RefCount > -1 && RefCount < 0x00FFFFFF);
610 
611  RefCount--;
612  if (RefCount == 0)
613  delete this;
614  }
615 
616 private:
617  // Hidden
618  WeakPtrProxy(const WeakPtrProxy& w) { KY_UNUSED(w); }
619  void operator=(const WeakPtrProxy& w) { KY_UNUSED(w); }
620 
621  int RefCount;
622  RefCountWeakSupportImpl* pObject;
623 };
624 
625 
626 // A weak pointer points at an object, but the object may be deleted
627 // at any time, in which case the weak pointer automatically becomes
628 // NULL. The only way to use a weak pointer is by converting it to a
629 // strong pointer (i.e. for temporary use).
630 //
631 // The class pointed to must have a "WeakPtrProxy* GetWeakPtrProxy()" method.
632 //
633 // Usage idiom:
634 //
635 // if (Ptr<my_type> ptr = weak_ptr_to_my_type) { ... use ptr->whatever() safely in here ... }
636 
637 
638 template<class C>
639 class WeakPtr
640 {
641 public:
642  WeakPtr()
643  { }
644 
645  KY_INLINE WeakPtr(C* ptr)
646  : pProxy(*(ptr ? ptr->CreateWeakProxy() : (WeakPtrProxy*)0))
647  { }
648  KY_INLINE WeakPtr(const Ptr<C>& ptr)
649  : pProxy(*(ptr.GetPtr() ? ptr->CreateWeakProxy() : (WeakPtrProxy*)0))
650  { }
651 
652  // Default constructor and assignment from WeakPtr<C> are OK
653  KY_INLINE void operator = (C* ptr)
654  {
655  if (ptr)
656  {
657  pProxy = *ptr->CreateWeakProxy();
658  }
659  else
660  {
661  pProxy.Clear();
662  }
663  }
664 
665  KY_INLINE void operator = (const Ptr<C>& ptr)
666  { operator=(ptr.GetPtr()); }
667 
668  // Conversion to Ptr
669  inline operator Ptr<C>() const
670  {
671  return Ptr<C>(GetObjectThroughProxy());
672  }
673 
674  KY_INLINE bool operator == (C* ptr)
675  { return GetObjectThroughProxy() == ptr; }
676  KY_INLINE bool operator == (const Ptr<C>& ptr)
677  { return GetObjectThroughProxy() == ptr.GetPtr(); }
678 
679 private:
680 
681  // Set pObject to NULL if the object died
682  KY_INLINE C* GetObjectThroughProxy() const
683  {
684  C* pobject = 0;
685 
686  if (pProxy)
687  {
688  if (pProxy->IsAlive())
689  {
690  pobject = (C*)pProxy->GetObject();
691  }
692  else
693  {
694  // Release proxy if the underlying object went away.
695  pProxy.Clear();
696  }
697  }
698  return pobject;
699  }
700 
701  mutable Ptr<WeakPtrProxy> pProxy;
702 };
703 
704 } // Scaleform
705 
706 #endif
Definition: gamekitcrowddispersion.h:20
Vec2f operator*(KyFloat32 s, const Vec2f &v)
Multiplies the X and Y coordinates of v by s.
Definition: vec2f.h:184