home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / h / vd2 / system / refcount.h < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  8.5 KB  |  283 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #ifndef f_VD2_SYSTEM_REFCOUNT_H
  27. #define f_VD2_SYSTEM_REFCOUNT_H
  28.  
  29. #include <vd2/system/vdtypes.h>
  30. #include <vd2/system/atomic.h>
  31.  
  32. ///////////////////////////////////////////////////////////////////////////
  33. //    IVDRefCount
  34. ///    Base interface for reference-counted objects.
  35. ///
  36. /// Reference counting is a relatively straightforward and simple method
  37. /// of garbage collection. The rules are:
  38. ///
  39. /// 1) Objects increment their reference count on an AddRef() and
  40. ///    decrement it on a Release().
  41. /// 2) Objects destroy themselves when their reference count is dropped
  42. ///    to zero.
  43. /// 3) Clients create references with AddRef() and destroy them with
  44. ///    Release().
  45. ///
  46. /// One way to interact with refcounted objects is to call AddRef()
  47. /// whenever a pointer is created, and Release() when the pointer is
  48. /// nulled or changed.  The vdrefptr<T> template does this automatically.
  49. /// Reference counting may be "combined" between pointers for optimization
  50. /// reasons, such that fewer reference counts are outstanding than actual
  51. /// pointers; this requires weak (non-refcounted) pointers and explicit
  52. /// refcount management.
  53. ///
  54. /// Reference counting has two issues:
  55. ///
  56. /// A) It is expensive.  VirtualDub uses it somewhat sparingly.
  57. ///
  58. /// B) Reference counting cannot cope with cycles.  This issue is
  59. ///    avoided by arranging objects in a clearly ordered tree, such that
  60. ///    no class ever holds a pointer to another object of the same class
  61. ///    or to a parent in the reference hierarchy.  vdrefptr<T> can
  62. ///    implicitly create cycles if you are not careful.
  63. ///
  64. ///    In VirtualDub, reference counting must be multithread safe, so atomic
  65. ///    increment/decrement should be used.  vdrefcounted<T> handles this
  66. ///    automatically for the template type class.
  67. ///
  68. ///    Two final implementation details:
  69. ///
  70. ///    - Little or no code should be executed after the reference count
  71. ///      drops to zero, preferably nothing more than the destructor implicitly
  72. ///      generated by the compiler.  The reason is that otherwise there is the
  73. ///      potential for an object to be resurrected past its final release by
  74. ///      temporarily creating a new reference on the object.
  75. ///
  76. /// - AddRef() and Release() traditionally return the reference count on
  77. ///      the object after increment or decrement, but this is not required.
  78. ///      For Release builds, it is only required that the value for Release()
  79. ///      be zero iff the object is destroyed.  (The same applies for AddRef(),
  80. ///      but since the result of AddRef() is always non-zero, the return of
  81. ///      AddRef() is of no use unless it is the actual count.)
  82. ///
  83. class VDINTERFACE IVDRefCount {
  84. public:
  85.     virtual int AddRef()=0;
  86.     virtual int Release()=0;
  87. };
  88.  
  89. ///////////////////////////////////////////////////////////////////////////
  90. //    vdrefcounted<T>
  91. ///    Implements thread-safe reference counting on top of a base class.
  92. ///
  93. ///    vdrefcounted<T> is used to either add reference counting to a base
  94. ///    class or to implement it on an interface. Use it by deriving your
  95. ///    class from it.
  96. ///
  97. template<class T> class vdrefcounted : public T {
  98. public:
  99.     vdrefcounted() : mRefCount(0) {}
  100.     vdrefcounted(const vdrefcounted<T>& src) : mRefCount(0) {}        // do not copy the refcount
  101.     virtual ~vdrefcounted() {}
  102.  
  103.     vdrefcounted<T>& operator=(const vdrefcounted<T>&) {}            // do not copy the refcount
  104.  
  105.     inline virtual int AddRef() {
  106.         return mRefCount.inc();
  107.     }
  108.  
  109.     inline virtual int Release() {
  110.         int rc = --mRefCount;
  111.  
  112.         if (!rc) {
  113.             delete this;
  114.             return 0;
  115.         }
  116.  
  117.         VDASSERT(rc > 0);
  118.  
  119.         return rc;
  120.     }
  121.  
  122. protected:
  123.     VDAtomicInt        mRefCount;
  124. };
  125.  
  126. ///////////////////////////////////////////////////////////////////////////
  127. //    vdrefptr<T>
  128. ///    Reference-counting smart pointer.
  129. ///
  130. ///    Maintains a strong reference on any object that supports AddRef/Release
  131. ///    semantics. This includes any interface including IVDRefCount,
  132. ///    IVDRefUnknown, or the IUnknown interface in Microsoft COM. Because
  133. ///    references are automatically traded as necessary, smart pointers are
  134. ///    very useful for maintaining exception safety.
  135. ///
  136. template<class T> class vdrefptr {
  137. protected:
  138.     T *ptr;
  139.  
  140. public:
  141.     typedef vdrefptr<T> self_type;
  142.     typedef T            element_type;
  143.  
  144.     /// Creates a new smart pointer and obtains a new reference on the
  145.     /// specified object.
  146.     explicit vdrefptr(T *p = 0) : ptr(p) {
  147.         if (p)
  148.             p->AddRef();
  149.     }
  150.  
  151.     /// Clones a smart pointer, duplicating any held reference.
  152.     vdrefptr(const self_type& src) {
  153.         ptr = src.ptr;
  154.         if (ptr)
  155.             ptr->AddRef();
  156.     }
  157.  
  158.     /// Destroys the smart pointer, releasing any held reference.
  159.     ~vdrefptr() {
  160.         if (ptr)
  161.             ptr->Release();
  162.     }
  163.  
  164.     /// Assigns a new object to a smart pointer. Any old object is released
  165.     /// and the new object is addrefed.
  166.     inline self_type& operator=(T *src) {
  167.         if (src)
  168.             src->AddRef();
  169.         if (ptr)
  170.             ptr->Release();
  171.         ptr = src;
  172.         return *this;
  173.     }
  174.  
  175.     /// Assigns a new object to a smart pointer. Any old object is released
  176.     /// and the new object is addrefed.
  177.     inline self_type& operator=(const vdrefptr& src) {
  178.         if (src.ptr)
  179.             src.ptr->AddRef();
  180.         if (ptr)
  181.             ptr->Release();
  182.         ptr = src.ptr;
  183.         return *this;
  184.     }
  185.  
  186.     operator T*() const { return ptr; }
  187.     T& operator*() const { return *ptr; }
  188.     T *operator->() const { return ptr; }
  189.  
  190.     /// Removes any old reference and returns a double-pointer to the nulled
  191.     /// internal pointer. This is useful for passing to IUnknown-derived
  192.     /// interfaces that accept (T **) parameters, like QueryInterface().
  193.     T** operator~() {
  194.         if (ptr) {
  195.             ptr->Release();
  196.             ptr = NULL;
  197.         }
  198.         return &ptr;
  199.     }
  200.  
  201.     /// Removes any held reference.
  202.     inline void clear() {
  203.         if (ptr)
  204.             ptr->Release();
  205.         ptr = NULL;
  206.     }
  207.  
  208.     /// Removes any existing reference and moves a reference from another
  209.     /// smart pointer. The source pointer is cleared afterward.
  210.     inline void from(vdrefptr& src) {
  211.         if (ptr)
  212.             ptr->Release();
  213.         ptr = src.ptr;
  214.         src.ptr = NULL;
  215.     }
  216.  
  217.     /// Removes any existing reference and accepts a reference to a new
  218.     /// object without actually obtaining one. This is useful if someone
  219.     /// has already addrefed an object for you.
  220.     inline void set(T* src) {
  221.         if (ptr)
  222.             ptr->Release();
  223.  
  224.         ptr = src;
  225.     }
  226.  
  227.     /// Returns the held reference and clears the smart pointer without
  228.     /// releasing the reference. This is useful for holding onto a reference
  229.     /// in an exception-safe manner up until the last moment.
  230.     inline T *release() {
  231.         T *p = ptr;
  232.         ptr = NULL;
  233.         return p;
  234.     }
  235.  
  236.     /// Swaps the references between two smart pointers.
  237.     void swap(vdrefptr& r) {
  238.         T *p = ptr;
  239.         ptr = r.ptr;
  240.         r.ptr = p;
  241.     }
  242. };
  243.  
  244. ///////////////////////////////////////////////////////////////////////////
  245.  
  246. template<class T, class U>
  247. bool VDRefCountObjectFactory(U **pp) {
  248.     T *p = new_nothrow T;
  249.     if (!p)
  250.         return false;
  251.  
  252.     *pp = static_cast<U *>(p);
  253.     p->AddRef();
  254.     return true;
  255. }
  256.  
  257. ///////////////////////////////////////////////////////////////////////////
  258.  
  259. struct vdsaferelease_t {};
  260. extern vdsaferelease_t vdsaferelease;
  261.  
  262. template<class T>
  263. inline vdsaferelease_t& operator<<=(vdsaferelease_t& x, T *& p) {
  264.     if (p) {
  265.         p->Release();
  266.         p = 0;
  267.     }
  268.  
  269.     return x;
  270. }
  271.  
  272. template<class T>
  273. inline vdsaferelease_t& operator,(vdsaferelease_t& x, T *& p) {
  274.     if (p) {
  275.         p->Release();
  276.         p = 0;
  277.     }
  278.  
  279.     return x;
  280. }
  281.  
  282. #endif
  283.