SkRefCnt.h revision 04640299dc0d71752295a630d58f6160642f3c8e
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
28a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
48a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
78a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com */
88a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
9ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkRefCnt_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkRefCnt_DEFINED
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkThread.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com/** \class SkRefCnt
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt is the base class for objects that may be shared by multiple
18a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    objects. When an existing owner wants to share a reference, it calls ref().
19a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    When an owner wants to release its reference, it calls unref(). When the
20a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    shared object's reference count goes to zero as the result of an unref()
21a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    call, its (virtual) destructor is called. It is an error for the
22a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    destructor to be called explicitly (or via the object going out of scope on
23a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    the stack or calling delete) if getRefCnt() > 1.
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
257ffb1b21abcc7bbed5a0fc711f6dd7b9dbb4f577ctguil@chromium.orgclass SK_API SkRefCnt : SkNoncopyable {
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Default construct, initializing the reference count to 1.
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkRefCnt() : fRefCnt(1) {}
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
31a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    /** Destruct, asserting that the reference count is 1.
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
334c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com    virtual ~SkRefCnt() {
344c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#ifdef SK_DEBUG
354c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com        SkASSERT(fRefCnt == 1);
364c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com        fRefCnt = 0;    // illegal value, to catch us if we reuse after delete
374c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#endif
384c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com    }
398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Return the reference count.
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t getRefCnt() const { return fRefCnt; }
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Increment the reference count. Must be balanced by a call to unref().
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void ref() const {
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fRefCnt > 0);
48a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        sk_atomic_inc(&fRefCnt);  // No barrier required.
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Decrement the reference count. If the reference count is 1 before the
52a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        decrement, then delete the object. Note that if this is the case, then
53a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        the object needs to have been allocated via new, and not on the stack.
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void unref() const {
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fRefCnt > 0);
57a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        // Release barrier (SL/S), if not provided below.
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (sk_atomic_dec(&fRefCnt) == 1) {
59a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            // Aquire barrier (L/SL), if not provided above.
60a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            // Prevents code in dispose from happening before the decrement.
61a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            sk_membar_aquire__after_atomic_dec();
62a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            internal_dispose();
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
667f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    void validate() const {
677f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        SkASSERT(fRefCnt > 0);
687f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
697f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
71a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    /** Called when the ref count goes to 0.
72a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    */
73a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    virtual void internal_dispose() const {
74a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#ifdef SK_DEBUG
75a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        // so our destructor won't complain
76a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        fRefCnt = 1;
77a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#endif
78a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        SkDELETE(this);
79a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    }
80a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    friend class SkWeakRefCnt;
81a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mutable int32_t fRefCnt;
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
857f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
867f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
877f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
887f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    null in on each side of the assignment, and ensuring that ref() is called
897f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    before unref(), in case the two pointers point to the same object.
907f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
917f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com#define SkRefCnt_SafeAssign(dst, src)   \
927f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    do {                                \
937f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (src) src->ref();            \
947f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (dst) dst->unref();          \
957f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        dst = src;                      \
967f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    } while (0)
977f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
987f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
997f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Check if the argument is non-null, and if so, call obj->ref()
1007f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1017f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comtemplate <typename T> static inline void SkSafeRef(T* obj) {
1027f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1037f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->ref();
1047f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1057f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1067f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1077f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Check if the argument is non-null, and if so, call obj->unref()
1087f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1097f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comtemplate <typename T> static inline void SkSafeUnref(T* obj) {
1107f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1117f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->unref();
1127f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1137f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1147f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1157f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
1167f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
117a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com/**
118a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com *  Utility class that simply unref's its argument in the destructor.
119a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com */
120a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.comtemplate <typename T> class SkAutoTUnref : SkNoncopyable {
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
122a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com    explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
123a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    ~SkAutoTUnref() { SkSafeUnref(fObj); }
124a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
125a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* get() const { return fObj; }
126a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
127a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com    void reset(T* obj) {
128a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com        SkSafeUnref(fObj);
129a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com        fObj = obj;
130a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com    }
131a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com
132a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    /**
133a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  Return the hosted object (which may be null), transferring ownership.
134a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  The reference count is not modified, and the internal ptr is set to NULL
135a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  so unref() will not be called in our destructor. A subsequent call to
136a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  detach() will do nothing and return null.
137a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     */
138a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* detach() {
139a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        T* obj = fObj;
140a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        fObj = NULL;
141a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        return obj;
142a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    }
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
144e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    /**
14504640299dc0d71752295a630d58f6160642f3c8ebungeman@google.com     * BlockRef<B> is a type which inherits from B, cannot be created,
146e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     * and makes ref and unref private.
147e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     */
14804640299dc0d71752295a630d58f6160642f3c8ebungeman@google.com    template<typename B> class BlockRef : public B {
149e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    private:
150e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        BlockRef();
151e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        void ref() const;
152e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        void unref() const;
153e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    };
154e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    /**
155e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
156e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  for the user to ref or unref through SkAutoTUnref. Therefore
157e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
158e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
159e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     */
160e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    BlockRef<T> *operator->() const {
161e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        return static_cast<BlockRef<T>*>(fObj);
162e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    }
163f51018d8f954cc644cc875dc1faab386fd6e85e3reed@google.com    operator T*() { return fObj; }
164f51018d8f954cc644cc875dc1faab386fd6e85e3reed@google.com
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
166a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T*  fObj;
167a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com};
168a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
169a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.comclass SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
170a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.compublic:
171a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
1728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1747f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comclass SkAutoRef : SkNoncopyable {
1757f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.compublic:
1767f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
1777f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    ~SkAutoRef() { SkSafeUnref(fObj); }
1787f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comprivate:
1797f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    SkRefCnt* fObj;
1807f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com};
181149e2f6159a797989f6f0fa93ecfaa66cdd55c40reed@android.com
182756f6dd82da298375547cb36955be9ac8574d2dcreed@android.com/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
183756f6dd82da298375547cb36955be9ac8574d2dcreed@android.com    a SkRefCnt (or subclass) object.
184756f6dd82da298375547cb36955be9ac8574d2dcreed@android.com */
185756f6dd82da298375547cb36955be9ac8574d2dcreed@android.comtemplate <typename T> class SkRefPtr {
186b00cd7258c5ccf856c0dc72840e082306251b278reed@android.compublic:
187b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    SkRefPtr() : fObj(NULL) {}
188b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
189b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
190b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    ~SkRefPtr() { SkSafeUnref(fObj); }
191b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com
192b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    SkRefPtr& operator=(const SkRefPtr& rp) {
193b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com        SkRefCnt_SafeAssign(fObj, rp.fObj);
194b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com        return *this;
195b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    }
196b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    SkRefPtr& operator=(T* obj) {
197b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com        SkRefCnt_SafeAssign(fObj, obj);
198b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com        return *this;
199b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    }
200b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com
201b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    T* get() const { return fObj; }
202b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    T& operator*() const { return *fObj; }
203b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    T* operator->() const { return fObj; }
204b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com
205b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    typedef T* SkRefPtr::*unspecified_bool_type;
206ddbf4c85dece1bef3b6c97219187a6b616b66346reed@google.com    operator unspecified_bool_type() const {
207ddbf4c85dece1bef3b6c97219187a6b616b66346reed@google.com        return fObj ? &SkRefPtr::fObj : NULL;
208ddbf4c85dece1bef3b6c97219187a6b616b66346reed@google.com    }
209b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com
210b00cd7258c5ccf856c0dc72840e082306251b278reed@android.comprivate:
211b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com    T* fObj;
212b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com};
213b00cd7258c5ccf856c0dc72840e082306251b278reed@android.com
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
216