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. Use only for debugging. */
     45     int32_t getRefCnt() const { return fRefCnt; }
     46 
     47     /** Returns true if the caller is the only owner.
     48      *  Ensures that all previous owner's actions are complete.
     49      */
     50     bool unique() const {
     51         bool const unique = (1 == fRefCnt);
     52         if (unique) {
     53             // Aquire barrier (L/SL), if not provided by load of fRefCnt.
     54             // Prevents user's 'unique' code from happening before decrements.
     55             //TODO: issue the barrier.
     56         }
     57         return unique;
     58     }
     59 
     60     /** Increment the reference count. Must be balanced by a call to unref().
     61     */
     62     void ref() const {
     63         SkASSERT(fRefCnt > 0);
     64         sk_atomic_inc(&fRefCnt);  // No barrier required.
     65     }
     66 
     67     /** Decrement the reference count. If the reference count is 1 before the
     68         decrement, then delete the object. Note that if this is the case, then
     69         the object needs to have been allocated via new, and not on the stack.
     70     */
     71     void unref() const {
     72         SkASSERT(fRefCnt > 0);
     73         // Release barrier (SL/S), if not provided below.
     74         if (sk_atomic_dec(&fRefCnt) == 1) {
     75             // Aquire barrier (L/SL), if not provided above.
     76             // Prevents code in dispose from happening before the decrement.
     77             sk_membar_aquire__after_atomic_dec();
     78             internal_dispose();
     79         }
     80     }
     81 
     82     void validate() const {
     83         SkASSERT(fRefCnt > 0);
     84     }
     85 
     86     /**
     87      * Alias for unref(), for compatibility with WTF::RefPtr.
     88      */
     89     void deref() { this->unref(); }
     90 
     91 protected:
     92     /**
     93      *  Allow subclasses to call this if they've overridden internal_dispose
     94      *  so they can reset fRefCnt before the destructor is called. Should only
     95      *  be called right before calling through to inherited internal_dispose()
     96      *  or before calling the destructor.
     97      */
     98     void internal_dispose_restore_refcnt_to_1() const {
     99 #ifdef SK_DEBUG
    100         SkASSERT(0 == fRefCnt);
    101         fRefCnt = 1;
    102 #endif
    103     }
    104 
    105 private:
    106     /**
    107      *  Called when the ref count goes to 0.
    108      */
    109     virtual void internal_dispose() const {
    110         this->internal_dispose_restore_refcnt_to_1();
    111         SkDELETE(this);
    112     }
    113 
    114     // The following friends are those which override internal_dispose()
    115     // and conditionally call SkRefCnt::internal_dispose().
    116     friend class GrTexture;
    117     friend class SkWeakRefCnt;
    118 
    119     mutable int32_t fRefCnt;
    120 
    121     typedef SkNoncopyable INHERITED;
    122 };
    123 
    124 ///////////////////////////////////////////////////////////////////////////////
    125 
    126 /** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
    127     null in on each side of the assignment, and ensuring that ref() is called
    128     before unref(), in case the two pointers point to the same object.
    129  */
    130 #define SkRefCnt_SafeAssign(dst, src)   \
    131     do {                                \
    132         if (src) src->ref();            \
    133         if (dst) dst->unref();          \
    134         dst = src;                      \
    135     } while (0)
    136 
    137 
    138 /** Call obj->ref() and return obj. The obj must not be NULL.
    139  */
    140 template <typename T> static inline T* SkRef(T* obj) {
    141     SkASSERT(obj);
    142     obj->ref();
    143     return obj;
    144 }
    145 
    146 /** Check if the argument is non-null, and if so, call obj->ref() and return obj.
    147  */
    148 template <typename T> static inline T* SkSafeRef(T* obj) {
    149     if (obj) {
    150         obj->ref();
    151     }
    152     return obj;
    153 }
    154 
    155 /** Check if the argument is non-null, and if so, call obj->unref()
    156  */
    157 template <typename T> static inline void SkSafeUnref(T* obj) {
    158     if (obj) {
    159         obj->unref();
    160     }
    161 }
    162 
    163 ///////////////////////////////////////////////////////////////////////////////
    164 
    165 /**
    166  *  Utility class that simply unref's its argument in the destructor.
    167  */
    168 template <typename T> class SkAutoTUnref : SkNoncopyable {
    169 public:
    170     explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
    171     ~SkAutoTUnref() { SkSafeUnref(fObj); }
    172 
    173     T* get() const { return fObj; }
    174 
    175     T* reset(T* obj) {
    176         SkSafeUnref(fObj);
    177         fObj = obj;
    178         return obj;
    179     }
    180 
    181     void swap(SkAutoTUnref* other) {
    182         T* tmp = fObj;
    183         fObj = other->fObj;
    184         other->fObj = tmp;
    185     }
    186 
    187     /**
    188      *  Return the hosted object (which may be null), transferring ownership.
    189      *  The reference count is not modified, and the internal ptr is set to NULL
    190      *  so unref() will not be called in our destructor. A subsequent call to
    191      *  detach() will do nothing and return null.
    192      */
    193     T* detach() {
    194         T* obj = fObj;
    195         fObj = NULL;
    196         return obj;
    197     }
    198 
    199     /**
    200      *  BlockRef<B> is a type which inherits from B, cannot be created,
    201      *  cannot be deleted, and makes ref and unref private.
    202      */
    203     template<typename B> class BlockRef : public B {
    204     private:
    205         BlockRef();
    206         ~BlockRef();
    207         void ref() const;
    208         void unref() const;
    209     };
    210 
    211     /** If T is const, the type returned from operator-> will also be const. */
    212     typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType;
    213 
    214     /**
    215      *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
    216      *  for the user to ref or unref through SkAutoTUnref. Therefore
    217      *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
    218      *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
    219      */
    220     BlockRefType *operator->() const {
    221         return static_cast<BlockRefType*>(fObj);
    222     }
    223     operator T*() { return fObj; }
    224 
    225 private:
    226     T*  fObj;
    227 };
    228 
    229 class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
    230 public:
    231     SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
    232 };
    233 
    234 class SkAutoRef : SkNoncopyable {
    235 public:
    236     SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
    237     ~SkAutoRef() { SkSafeUnref(fObj); }
    238 private:
    239     SkRefCnt* fObj;
    240 };
    241 
    242 /** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
    243     a SkRefCnt (or subclass) object.
    244  */
    245 template <typename T> class SkRefPtr {
    246 public:
    247     SkRefPtr() : fObj(NULL) {}
    248     SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
    249     SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
    250     ~SkRefPtr() { SkSafeUnref(fObj); }
    251 
    252     SkRefPtr& operator=(const SkRefPtr& rp) {
    253         SkRefCnt_SafeAssign(fObj, rp.fObj);
    254         return *this;
    255     }
    256     SkRefPtr& operator=(T* obj) {
    257         SkRefCnt_SafeAssign(fObj, obj);
    258         return *this;
    259     }
    260 
    261     T* get() const { return fObj; }
    262     T& operator*() const { return *fObj; }
    263     T* operator->() const { return fObj; }
    264 
    265     typedef T* SkRefPtr::*unspecified_bool_type;
    266     operator unspecified_bool_type() const {
    267         return fObj ? &SkRefPtr::fObj : NULL;
    268     }
    269 
    270 private:
    271     T* fObj;
    272 };
    273 
    274 #endif
    275