LCOV - code coverage report
Current view: top level - gfx/sfntly/cpp/src/sfntly/port - refcount.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 72 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 854 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2011 Google Inc. All Rights Reserved.
       3             :  *
       4             :  * Licensed under the Apache License, Version 2.0 (the "License");
       5             :  * you may not use this file except in compliance with the License.
       6             :  * You may obtain a copy of the License at
       7             :  *
       8             :  *      http://www.apache.org/licenses/LICENSE-2.0
       9             :  *
      10             :  * Unless required by applicable law or agreed to in writing, software
      11             :  * distributed under the License is distributed on an "AS IS" BASIS,
      12             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13             :  * See the License for the specific language governing permissions and
      14             :  * limitations under the License.
      15             :  */
      16             : 
      17             : // Object reference count and smart pointer implementation.
      18             : 
      19             : // Smart pointer usage in sfntly:
      20             : //
      21             : // sfntly carries a smart pointer implementation like COM.  Ref-countable object
      22             : // type inherits from RefCounted<>, which have AddRef and Release just like
      23             : // IUnknown (but no QueryInterface).  Use a Ptr<> based smart pointer to hold
      24             : // the object so that the object ref count is handled correctly.
      25             : //
      26             : // class Foo : public RefCounted<Foo> {
      27             : //  public:
      28             : //   static Foo* CreateInstance() {
      29             : //     Ptr<Foo> obj = new Foo();  // ref count = 1
      30             : //     return obj.Detach();
      31             : //   }
      32             : // };
      33             : // typedef Ptr<Foo> FooPtr;  // common short-hand notation
      34             : // FooPtr obj;
      35             : // obj.Attach(Foo::CreatedInstance());  // ref count = 1
      36             : // {
      37             : //   FooPtr obj2 = obj;  // ref count = 2
      38             : // }  // ref count = 1, obj2 out of scope
      39             : // obj.Release();  // ref count = 0, object destroyed
      40             : 
      41             : // Notes on usage:
      42             : // 1. Virtual inherit from RefCount interface in base class if smart pointers
      43             : //    are going to be defined.
      44             : // 2. All RefCounted objects must be instantiated on the heap.  Allocating the
      45             : //    object on stack will cause crash.
      46             : // 3. Be careful when you have complex inheritance.  For example,
      47             : //    class A : public RefCounted<A>;
      48             : //    class B : public A, public RefCounted<B>;
      49             : //    In this case the smart pointer is pretty dumb and don't count on it to
      50             : //    nicely destroy your objects as designed. Try refactor your code like
      51             : //    class I;  // the common interface and implementations
      52             : //    class A : public I, public RefCounted<A>;  // A specific implementation
      53             : //    class B : public I, public RefCounted<B>;  // B specific implementation
      54             : // 4. Smart pointers here are very bad candidates for function parameters.  Use
      55             : //    dumb pointers in function parameter list.
      56             : // 5. When down_cast is performed on a dangling pointer due to bugs in code,
      57             : //    VC++ will generate SEH which is not handled well in VC++ debugger.  One
      58             : //    can use WinDBG to run it and get the faulting stack.
      59             : // 6. Idioms for heap object as return value
      60             : //    Foo* createFoo() { FooPtr obj = new Foo(); return obj.Detach(); }
      61             : //    Foo* passthru() { FooPtr obj = createFoo(), return obj; }
      62             : //    FooPtr end_scope_pointer;
      63             : //    end_scope_pointer.Attach(passThrough);
      64             : //    If you are not passing that object back, you are the end of scope.
      65             : 
      66             : #ifndef SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
      67             : #define SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_
      68             : 
      69             : #if !defined (NDEBUG)
      70             :   #define ENABLE_OBJECT_COUNTER
      71             : //  #define REF_COUNT_DEBUGGING
      72             : #endif
      73             : 
      74             : #if defined (REF_COUNT_DEBUGGING)
      75             :   #include <stdio.h>
      76             :   #include <typeinfo>
      77             : #endif
      78             : 
      79             : #include "sfntly/port/atomic.h"
      80             : #include "sfntly/port/type.h"
      81             : 
      82             : // Special tag for functions that requires caller to attach instead of using
      83             : // assignment operators.
      84             : #define CALLER_ATTACH
      85             : 
      86             : #if defined (REF_COUNT_DEBUGGING)
      87             :   #define DEBUG_OUTPUT(a) \
      88             :       fprintf(stderr, "%s%s:oc=%d,oid=%d,rc=%d\n", a, \
      89             :               typeid(this).name(), object_counter_, object_id_, ref_count_)
      90             : #else
      91             :   #define DEBUG_OUTPUT(a)
      92             : #endif
      93             : 
      94             : #if defined (_MSC_VER)
      95             :   // VC 2008/2010 incorrectly gives this warning for pure virtual functions
      96             :   // in virtual inheritance.  The only way to get around it is to disable it.
      97             :   #pragma warning(disable:4250)
      98             : #endif
      99             : 
     100             : namespace sfntly {
     101             : 
     102             : template <typename T>
     103             : class Ptr;
     104             : 
     105           0 : class RefCount {
     106             :  public:
     107             :   // Make gcc -Wnon-virtual-dtor happy.
     108           0 :   virtual ~RefCount() {}
     109             : 
     110             :  private:
     111             :   template <typename T>
     112             :   friend class Ptr;
     113             : 
     114             :   virtual size_t AddRef() const = 0;
     115             :   virtual size_t Release() const = 0;
     116             : };
     117             : 
     118             : template <typename TDerived>
     119             : class RefCounted : virtual public RefCount {
     120             :  public:
     121           0 :   RefCounted() : ref_count_(0) {
     122             : #if defined (ENABLE_OBJECT_COUNTER)
     123           0 :     object_id_ = AtomicIncrement(&next_id_);
     124           0 :     AtomicIncrement(&object_counter_);
     125             :     DEBUG_OUTPUT("C ");
     126             : #endif
     127           0 :   }
     128             :   RefCounted(const RefCounted<TDerived>&) : ref_count_(0) {}
     129           0 :   virtual ~RefCounted() {
     130             : #if defined (ENABLE_OBJECT_COUNTER)
     131           0 :     AtomicDecrement(&object_counter_);
     132             :     DEBUG_OUTPUT("D ");
     133             : #endif
     134           0 :   }
     135             : 
     136             :   RefCounted<TDerived>& operator=(const RefCounted<TDerived>&) {
     137             :     // Each object maintains own ref count, don't propagate.
     138             :     return *this;
     139             :   }
     140             : 
     141             :  private:
     142           0 :   virtual size_t AddRef() const {
     143           0 :     size_t new_count = AtomicIncrement(&ref_count_);
     144             :     DEBUG_OUTPUT("A ");
     145           0 :     return new_count;
     146             :   }
     147             : 
     148           0 :   virtual size_t Release() const {
     149           0 :     size_t new_ref_count = AtomicDecrement(&ref_count_);
     150             :     DEBUG_OUTPUT("R ");
     151           0 :     if (new_ref_count == 0) {
     152             :       // A C-style is used to cast away const-ness and to derived.
     153             :       // lint does not like this but this is how it works.
     154           0 :       delete (TDerived*)(this);
     155             :     }
     156           0 :     return new_ref_count;
     157             :   }
     158             : 
     159             :   mutable size_t ref_count_;  // reference count of current object
     160             : #if defined (ENABLE_OBJECT_COUNTER)
     161             :   static size_t object_counter_;
     162             :   static size_t next_id_;
     163             :   mutable size_t object_id_;
     164             : #endif
     165             : };
     166             : 
     167             : #if defined (ENABLE_OBJECT_COUNTER)
     168             : template <typename TDerived> size_t RefCounted<TDerived>::object_counter_ = 0;
     169             : template <typename TDerived> size_t RefCounted<TDerived>::next_id_ = 0;
     170             : #endif
     171             : 
     172             : // semi-smart pointer for RefCount derived objects, similar to CComPtr
     173             : template <typename T>
     174             : class Ptr {
     175             :  public:
     176           0 :   Ptr() : p_(NULL) {
     177           0 :   }
     178             : 
     179             :   // This constructor shall not be explicit.
     180             :   // lint does not like this but this is how it works.
     181           0 :   Ptr(T* pT) : p_(NULL) {
     182           0 :     *this = pT;
     183           0 :   }
     184             : 
     185           0 :   Ptr(const Ptr<T>& p) : p_(NULL) {
     186           0 :     *this = p;
     187           0 :   }
     188             : 
     189           0 :   ~Ptr() {
     190           0 :     Release();
     191           0 :   }
     192             : 
     193           0 :   T* operator=(T* pT) {
     194           0 :     if (p_ == pT) {
     195           0 :       return p_;
     196             :     }
     197           0 :     if (pT) {
     198           0 :       RefCount* p = static_cast<RefCount*>(pT);
     199           0 :       if (p == NULL) {
     200           0 :         return NULL;
     201             :       }
     202           0 :       p->AddRef();  // always AddRef() before Release()
     203             :     }
     204           0 :     Release();
     205           0 :     p_ = pT;
     206           0 :     return p_;
     207             :   }
     208             : 
     209           0 :   T* operator=(const Ptr<T>& p) {
     210           0 :     if (p_ == p.p_) {
     211           0 :       return p_;
     212             :     }
     213           0 :     return operator=(p.p_);
     214             :   }
     215             : 
     216           0 :   operator T*&() {
     217           0 :     return p_;
     218             :   }
     219             : 
     220             :   T& operator*() const {
     221             :     return *p_;  // It can throw!
     222             :   }
     223             : 
     224           0 :   T* operator->() const {
     225           0 :     return p_;  // It can throw!
     226             :   }
     227             : 
     228           0 :   bool operator!() const {
     229           0 :     return (p_ == NULL);
     230             :   }
     231             : 
     232           0 :   bool operator<(const Ptr<T>& p) const {
     233           0 :     return (p_ < p.p_);
     234             :   }
     235             : 
     236           0 :   bool operator!=(T* pT) const {
     237           0 :     return !operator==(pT);
     238             :   }
     239             : 
     240           0 :   bool operator==(T* pT) const {
     241           0 :     return (p_ == pT);
     242             :   }
     243             : 
     244           0 :   size_t Release() const {
     245           0 :     size_t ref_count = 0;
     246           0 :     if (p_) {
     247           0 :       RefCount* p = static_cast<RefCount*>(p_);
     248           0 :       if (p) {
     249           0 :         ref_count = p->Release();
     250             :       }
     251           0 :       p_ = NULL;
     252             :     }
     253           0 :     return ref_count;
     254             :   }
     255             : 
     256           0 :   void Attach(T* pT) {
     257           0 :     if (p_ != pT) {
     258           0 :       Release();
     259           0 :       p_ = pT;
     260             :     }
     261           0 :   }
     262             : 
     263           0 :   T* Detach() {
     264           0 :     T* pT = p_;
     265           0 :     p_ = NULL;
     266           0 :     return pT;
     267             :   }
     268             : 
     269             :   mutable T* p_;
     270             : };
     271             : 
     272             : }  // namespace sfntly
     273             : 
     274             : #endif  // SFNTLY_CPP_SRC_SFNTLY_PORT_REFCOUNT_H_

Generated by: LCOV version 1.13