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
13ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org#include "SkDynamicAnnotations.h"
1486b0de4745a8a8317b54f23878498633b9210a8fcommit-bot@chromium.org#include "SkThread.h"
15977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#include "SkInstCnt.h"
1691208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com#include "SkTemplates.h"
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
186d2533ebd2ad5168d08f5a83e681881c0d533949commit-bot@chromium.org/** \class SkRefCntBase
196d2533ebd2ad5168d08f5a83e681881c0d533949commit-bot@chromium.org
2010ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    SkRefCntBase is the base class for objects that may be shared by multiple
21a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    objects. When an existing owner wants to share a reference, it calls ref().
22a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    When an owner wants to release its reference, it calls unref(). When the
23a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    shared object's reference count goes to zero as the result of an unref()
24a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    call, its (virtual) destructor is called. It is an error for the
25a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    destructor to be called explicitly (or via the object going out of scope on
26a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    the stack or calling delete) if getRefCnt() > 1.
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
28e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.orgclass SK_API SkRefCntBase : SkNoncopyable {
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
3010ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    SK_DECLARE_INST_COUNT_ROOT(SkRefCntBase)
31977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Default construct, initializing the reference count to 1.
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3410ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    SkRefCntBase() : fRefCnt(1) {}
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
36a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    /** Destruct, asserting that the reference count is 1.
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3810ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    virtual ~SkRefCntBase() {
394c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#ifdef SK_DEBUG
40b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein        SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
414c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com        fRefCnt = 0;    // illegal value, to catch us if we reuse after delete
424c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#endif
434c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com    }
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
45f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    /** Return the reference count. Use only for debugging. */
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t getRefCnt() const { return fRefCnt; }
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
48ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org    /** May return true if the caller is the only owner.
49f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com     *  Ensures that all previous owner's actions are complete.
50f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com     */
51f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    bool unique() const {
52ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org        // We believe we're reading fRefCnt in a safe way here, so we stifle the TSAN warning about
53ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org        // an unproctected read.  Generally, don't read fRefCnt, and don't stifle this warning.
54ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org        bool const unique = (1 == SK_ANNOTATE_UNPROTECTED_READ(fRefCnt));
55f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        if (unique) {
56d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            // Acquire barrier (L/SL), if not provided by load of fRefCnt.
57f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com            // Prevents user's 'unique' code from happening before decrements.
58f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com            //TODO: issue the barrier.
59f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        }
60f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        return unique;
61f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    }
62f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Increment the reference count. Must be balanced by a call to unref().
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void ref() const {
66f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
67a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        sk_atomic_inc(&fRefCnt);  // No barrier required.
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Decrement the reference count. If the reference count is 1 before the
71a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        decrement, then delete the object. Note that if this is the case, then
72a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        the object needs to have been allocated via new, and not on the stack.
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void unref() const {
75f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
76a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        // Release barrier (SL/S), if not provided below.
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (sk_atomic_dec(&fRefCnt) == 1) {
78d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            // Acquire barrier (L/SL), if not provided above.
79a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            // Prevents code in dispose from happening before the decrement.
80d9947f605a335363b0a0541d6d8cb7a7113ed788bungeman@google.com            sk_membar_acquire__after_atomic_dec();
81a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com            internal_dispose();
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8503087072483378a43f7b3f7a47944614187275ebrobertphillips@google.com#ifdef SK_DEBUG
867f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    void validate() const {
87f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
887f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
8903087072483378a43f7b3f7a47944614187275ebrobertphillips@google.com#endif
907f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
91f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprotected:
92f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
93f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Allow subclasses to call this if they've overridden internal_dispose
94f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  so they can reset fRefCnt before the destructor is called. Should only
95f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  be called right before calling through to inherited internal_dispose()
96f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  or before calling the destructor.
97f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
98f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    void internal_dispose_restore_refcnt_to_1() const {
99a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#ifdef SK_DEBUG
100f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkASSERT(0 == fRefCnt);
101a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        fRefCnt = 1;
102a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#endif
103f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    }
104f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com
105f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprivate:
106f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
107f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Called when the ref count goes to 0.
108f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
109f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    virtual void internal_dispose() const {
110f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        this->internal_dispose_restore_refcnt_to_1();
111a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        SkDELETE(this);
112a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    }
11315c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
114f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    // The following friends are those which override internal_dispose()
115f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    // and conditionally call SkRefCnt::internal_dispose().
116a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    friend class SkWeakRefCnt;
117a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mutable int32_t fRefCnt;
1194d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com
12010ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    typedef SkNoncopyable INHERITED;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12310ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#ifdef SK_REF_CNT_MIXIN_INCLUDE
12410ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com// It is the responsibility of the following include to define the type SkRefCnt.
12510ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com// This SkRefCnt should normally derive from SkRefCntBase.
12610ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#include SK_REF_CNT_MIXIN_INCLUDE
12710ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#else
12810ba006631a0c350aa2bcba188a60404869607c8bungeman@google.comclass SK_API SkRefCnt : public SkRefCntBase { };
12910ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#endif
13010ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com
1317f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
1327f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1337f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
1347f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    null in on each side of the assignment, and ensuring that ref() is called
1357f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    before unref(), in case the two pointers point to the same object.
1367f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1377f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com#define SkRefCnt_SafeAssign(dst, src)   \
1387f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    do {                                \
1397f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (src) src->ref();            \
1407f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (dst) dst->unref();          \
1417f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        dst = src;                      \
1427f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    } while (0)
1437f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1447f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1451fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com/** Call obj->ref() and return obj. The obj must not be NULL.
1467f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1471fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.comtemplate <typename T> static inline T* SkRef(T* obj) {
1481fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    SkASSERT(obj);
1491fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    obj->ref();
1501fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    return obj;
1511fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com}
1521fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com
1531fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com/** Check if the argument is non-null, and if so, call obj->ref() and return obj.
1541fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com */
1551fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.comtemplate <typename T> static inline T* SkSafeRef(T* obj) {
1567f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1577f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->ref();
1587f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1591fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    return obj;
1607f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1617f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1627f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Check if the argument is non-null, and if so, call obj->unref()
1637f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1647f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comtemplate <typename T> static inline void SkSafeUnref(T* obj) {
1657f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1667f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->unref();
1677f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1687f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1697f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
170a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.orgtemplate<typename T> static inline void SkSafeSetNull(T*& obj) {
17149f085dddff10473b6ebf832a974288300224e60bsalomon    if (obj) {
172a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org        obj->unref();
173a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org        obj = NULL;
174a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org    }
175a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org}
176a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org
1777f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
1787f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
179a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com/**
18091208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com *  Utility class that simply unref's its argument in the destructor.
181a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com */
18291208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.comtemplate <typename T> class SkAutoTUnref : SkNoncopyable {
1838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
18491208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
18591208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    ~SkAutoTUnref() { SkSafeUnref(fObj); }
186a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
187a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* get() const { return fObj; }
188a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
1892863f082f2524ebae9e69f382b50065189912b47reed@google.com    T* reset(T* obj) {
19068d6bb0c119141b0c8637d0b1b3c8b73c7026933reed@google.com        SkSafeUnref(fObj);
19168d6bb0c119141b0c8637d0b1b3c8b73c7026933reed@google.com        fObj = obj;
1922863f082f2524ebae9e69f382b50065189912b47reed@google.com        return obj;
193a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com    }
194a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com
1951dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com    void swap(SkAutoTUnref* other) {
1961dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        T* tmp = fObj;
1971dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        fObj = other->fObj;
1981dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        other->fObj = tmp;
1991dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com    }
2001dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com
201a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    /**
202a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  Return the hosted object (which may be null), transferring ownership.
203a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  The reference count is not modified, and the internal ptr is set to NULL
204a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  so unref() will not be called in our destructor. A subsequent call to
205a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  detach() will do nothing and return null.
206a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     */
207a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* detach() {
208a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        T* obj = fObj;
209a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        fObj = NULL;
210a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        return obj;
211a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    }
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
213e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    /**
2146f4cf2a19553b69d5bb10c5cd1005706a9fc6e22bungeman@google.com     *  BlockRef<B> is a type which inherits from B, cannot be created,
2156f4cf2a19553b69d5bb10c5cd1005706a9fc6e22bungeman@google.com     *  cannot be deleted, and makes ref and unref private.
216e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     */
21704640299dc0d71752295a630d58f6160642f3c8ebungeman@google.com    template<typename B> class BlockRef : public B {
218e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    private:
219e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        BlockRef();
2206f4cf2a19553b69d5bb10c5cd1005706a9fc6e22bungeman@google.com        ~BlockRef();
221e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        void ref() const;
222e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com        void unref() const;
223e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    };
2241448cf8cb6c6cd4866f7c71bf32ad6bca5d683d1bsalomon@google.com
22591208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    /** If T is const, the type returned from operator-> will also be const. */
22691208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType;
2271448cf8cb6c6cd4866f7c71bf32ad6bca5d683d1bsalomon@google.com
228e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    /**
229e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  SkAutoTUnref assumes ownership of the ref. As a result, it is an error
230e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  for the user to ref or unref through SkAutoTUnref. Therefore
231e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
232e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     *  skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
233e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com     */
23491208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    BlockRefType *operator->() const {
23591208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com        return static_cast<BlockRefType*>(fObj);
236e70f798ebca1a66f0b568fa46065ebbad9a13b2fbungeman@google.com    }
237d71b75757335393d9643a5b7a0f2769b6ba52fb6bungeman    operator T*() const { return fObj; }
2381448cf8cb6c6cd4866f7c71bf32ad6bca5d683d1bsalomon@google.com
23991208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.comprivate:
24091208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    T*  fObj;
241a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com};
242e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org// Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :(
243a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
244a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.comclass SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
245a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.compublic:
246a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
2478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
248e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref)
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
251