Home | History | Annotate | Download | only in core
      1 
      2 /*
      3  * Copyright 2006 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #ifndef SkRefCnt_DEFINED
     11 #define SkRefCnt_DEFINED
     12 
     13 #include "SkThread.h"
     14 #include "SkInstCnt.h"
     15 #include "SkTemplates.h"
     16 
     17 /** \class SkRefCnt
     18 
     19     SkRefCnt is the base class for objects that may be shared by multiple
     20     objects. When an existing owner wants to share a reference, it calls ref().
     21     When an owner wants to release its reference, it calls unref(). When the
     22     shared object's reference count goes to zero as the result of an unref()
     23     call, its (virtual) destructor is called. It is an error for the
     24     destructor to be called explicitly (or via the object going out of scope on
     25     the stack or calling delete) if getRefCnt() > 1.
     26 */
     27 class SK_API SkRefCnt : SkNoncopyable {
     28 public:
     29     SK_DECLARE_INST_COUNT_ROOT(SkRefCnt)
     30 
     31     /** Default construct, initializing the reference count to 1.
     32     */
     33     SkRefCnt() : fRefCnt(1) {}
     34 
     35     /** Destruct, asserting that the reference count is 1.
     36     */
     37     virtual ~SkRefCnt() {
     38 #ifdef SK_DEBUG
     39         SkASSERT(fRefCnt == 1);
     40         fRefCnt = 0;    // illegal value, to catch us if we reuse after delete
     41 #endif
     42     }
     43 
     44     /** Return the reference count.
     45     */
     46     int32_t getRefCnt() const { return fRefCnt; }
     47 
     48     /** Increment the reference count. Must be balanced by a call to unref().
     49     */
     50     void ref() const {
     51         SkASSERT(fRefCnt > 0);
     52         sk_atomic_inc(&fRefCnt);  // No barrier required.
     53     }
     54 
     55     /** Decrement the reference count. If the reference count is 1 before the
     56         decrement, then delete the object. Note that if this is the case, then
     57         the object needs to have been allocated via new, and not on the stack.
     58     */
     59     void unref() const {
     60         SkASSERT(fRefCnt > 0);
     61         // Release barrier (SL/S), if not provided below.
     62         if (sk_atomic_dec(&fRefCnt) == 1) {
     63             // Aquire barrier (L/SL), if not provided above.
     64             // Prevents code in dispose from happening before the decrement.
     65             sk_membar_aquire__after_atomic_dec();
     66             internal_dispose();
     67         }
     68     }
     69 
     70     void validate() const {
     71         SkASSERT(fRefCnt > 0);
     72     }
     73 
     74     /**
     75      *  Alias for ref(), for compatibility with scoped_refptr.
     76      */
     77     void AddRef() { this->ref(); }
     78 
     79     /**
     80      *  Alias for unref(), for compatibility with scoped_refptr.
     81      */
     82     void Release() { this->unref(); }
     83 
     84 protected:
     85     /**
     86      *  Allow subclasses to call this if they've overridden internal_dispose
     87      *  so they can reset fRefCnt before the destructor is called. Should only
     88      *  be called right before calling through to inherited internal_dispose()
     89      *  or before calling the destructor.
     90      */
     91     void internal_dispose_restore_refcnt_to_1() const {
     92 #ifdef SK_DEBUG
     93         SkASSERT(0 == fRefCnt);
     94         fRefCnt = 1;
     95 #endif
     96     }
     97 
     98 private:
     99     /**
    100      *  Called when the ref count goes to 0.
    101      */
    102     virtual void internal_dispose() const {
    103         this->internal_dispose_restore_refcnt_to_1();
    104         SkDELETE(this);
    105     }
    106 
    107     friend class SkWeakRefCnt;
    108     friend class GrTexture;     // to allow GrTexture's internal_dispose to
    109                                 // call SkRefCnt's & directly set fRefCnt (to 1)
    110 
    111     mutable int32_t fRefCnt;
    112 
    113     typedef SkNoncopyable INHERITED;
    114 };
    115 
    116 ///////////////////////////////////////////////////////////////////////////////
    117 
    118 /** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
    119     null in on each side of the assignment, and ensuring that ref() is called
    120     before unref(), in case the two pointers point to the same object.
    121  */
    122 #define SkRefCnt_SafeAssign(dst, src)   \
    123     do {                                \
    124         if (src) src->ref();            \
    125         if (dst) dst->unref();          \
    126         dst = src;                      \
    127     } while (0)
    128 
    129 
    130 /** Call obj->ref() and return obj. The obj must not be NULL.
    131  */
    132 template <typename T> static inline T* SkRef(T* obj) {
    133     SkASSERT(obj);
    134     obj->ref();
    135     return obj;
    136 }
    137 
    138 /** Check if the argument is non-null, and if so, call obj->ref() and return obj.
    139  */
    140 template <typename T> static inline T* SkSafeRef(T* obj) {
    141     if (obj) {
    142         obj->ref();
    143     }
    144     return obj;
    145 }
    146 
    147 /** Check if the argument is non-null, and if so, call obj->unref()
    148  */
    149 template <typename T> static inline void SkSafeUnref(T* obj) {
    150     if (obj) {
    151         obj->unref();
    152     }
    153 }
    154 
    155 ///////////////////////////////////////////////////////////////////////////////
    156 
    157 /**
    158  *  Utility class that simply unref's its argument in the destructor.
    159  */
    160 template <typename T> class SkAutoTUnref : SkNoncopyable {
    161 public:
    162     explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
    163     ~SkAutoTUnref() { SkSafeUnref(fObj); }
    164 
    165     T* get() const { return fObj; }
    166 
    167     void reset(T* obj) {
    168         SkSafeUnref(fObj);
    169         fObj = obj;
    170     }
    171 
    172     void swap(SkAutoTUnref* other) {
    173         T* tmp = fObj;
    174         fObj = other->fObj;
    175         other->fObj = tmp;
    176     }
    177 
    178     /**
    179      *  Return the hosted object (which may be null), transferring ownership.
    180      *  The reference count is not modified, and the internal ptr is set to NULL
    181      *  so unref() will not be called in our destructor. A subsequent call to
    182      *  detach() will do nothing and return null.
    183      */
    184     T* detach() {
    185         T* obj = fObj;
    186         fObj = NULL;
    187         return obj;
    188     }
    189 
    190     /**
    191      * BlockRef<B> is a type which inherits from B, cannot be created,
    192      * and makes ref and unref private.
    193      */
    194     template<typename B> class BlockRef : public B {
    195     private:
    196         BlockRef();
    197         void ref() const;
    198         void unref() const;
    199     };
    200 
    201     /** If T is const, the type returned from operator-> will also be const. */
    202     typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType;
    203 
    204     /**
    205      *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
    206      *  for the user to ref or unref through SkAutoTUnref. Therefore
    207      *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
    208      *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
    209      */
    210     BlockRefType *operator->() const {
    211         return static_cast<BlockRefType*>(fObj);
    212     }
    213     operator T*() { return fObj; }
    214 
    215 private:
    216     T*  fObj;
    217 };
    218 
    219 class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
    220 public:
    221     SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
    222 };
    223 
    224 class SkAutoRef : SkNoncopyable {
    225 public:
    226     SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
    227     ~SkAutoRef() { SkSafeUnref(fObj); }
    228 private:
    229     SkRefCnt* fObj;
    230 };
    231 
    232 /** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
    233     a SkRefCnt (or subclass) object.
    234  */
    235 template <typename T> class SkRefPtr {
    236 public:
    237     SkRefPtr() : fObj(NULL) {}
    238     SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
    239     SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
    240     ~SkRefPtr() { SkSafeUnref(fObj); }
    241 
    242     SkRefPtr& operator=(const SkRefPtr& rp) {
    243         SkRefCnt_SafeAssign(fObj, rp.fObj);
    244         return *this;
    245     }
    246     SkRefPtr& operator=(T* obj) {
    247         SkRefCnt_SafeAssign(fObj, obj);
    248         return *this;
    249     }
    250 
    251     T* get() const { return fObj; }
    252     T& operator*() const { return *fObj; }
    253     T* operator->() const { return fObj; }
    254 
    255     typedef T* SkRefPtr::*unspecified_bool_type;
    256     operator unspecified_bool_type() const {
    257         return fObj ? &SkRefPtr::fObj : NULL;
    258     }
    259 
    260 private:
    261     T* fObj;
    262 };
    263 
    264 #endif
    265