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
137b274c78fbeefa3818af68099545f2839c854847mtklein#include "SkAtomics.h"
14977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com#include "SkInstCnt.h"
1591208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com#include "SkTemplates.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
176d2533ebd2ad5168d08f5a83e681881c0d533949commit-bot@chromium.org/** \class SkRefCntBase
186d2533ebd2ad5168d08f5a83e681881c0d533949commit-bot@chromium.org
1910ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    SkRefCntBase is the base class for objects that may be shared by multiple
20a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    objects. When an existing owner wants to share a reference, it calls ref().
21a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    When an owner wants to release its reference, it calls unref(). When the
22a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    shared object's reference count goes to zero as the result of an unref()
23a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    call, its (virtual) destructor is called. It is an error for the
24a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    destructor to be called explicitly (or via the object going out of scope on
25a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    the stack or calling delete) if getRefCnt() > 1.
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com*/
27e3beb6bd7de7fa211681abbb0be58e80b19885e0commit-bot@chromium.orgclass SK_API SkRefCntBase : SkNoncopyable {
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
296f07665768dc84453316e7b2bbd6049576764cb1mtklein    SK_DECLARE_INST_COUNT(SkRefCntBase)
30977b9c8af3ef1b9a2fa2a0037cf3734cf2ba13d9robertphillips@google.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Default construct, initializing the reference count to 1.
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3310ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    SkRefCntBase() : fRefCnt(1) {}
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
35a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    /** Destruct, asserting that the reference count is 1.
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
3710ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    virtual ~SkRefCntBase() {
384c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#ifdef SK_DEBUG
39b59161f0000eb4aca3dcef29f27ffd0fb5a568e5mtklein        SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
404c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com        fRefCnt = 0;    // illegal value, to catch us if we reuse after delete
414c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com#endif
424c888aae25c1f6a420caceec7c42736ba6ddad3dreed@google.com    }
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4421180e26519a23cc69f4673f0b518395fddac57bmtklein#ifdef SK_DEBUG
45f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    /** Return the reference count. Use only for debugging. */
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t getRefCnt() const { return fRefCnt; }
4721180e26519a23cc69f4673f0b518395fddac57bmtklein#endif
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
49ea6e14a3825d6f805527ddfbce4fd6b2bf73a7dfcommit-bot@chromium.org    /** May return true if the caller is the only owner.
50f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com     *  Ensures that all previous owner's actions are complete.
51f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com     */
52f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    bool unique() const {
537b274c78fbeefa3818af68099545f2839c854847mtklein        if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) {
547b274c78fbeefa3818af68099545f2839c854847mtklein            // The acquire barrier is only really needed if we return true.  It
557b274c78fbeefa3818af68099545f2839c854847mtklein            // prevents code conditioned on the result of unique() from running
567b274c78fbeefa3818af68099545f2839c854847mtklein            // until previous owners are all totally done calling unref().
577b274c78fbeefa3818af68099545f2839c854847mtklein            return true;
58f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        }
597b274c78fbeefa3818af68099545f2839c854847mtklein        return false;
60f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    }
61f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Increment the reference count. Must be balanced by a call to unref().
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void ref() const {
65f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
667b274c78fbeefa3818af68099545f2839c854847mtklein        (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed);  // No barrier required.
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /** Decrement the reference count. If the reference count is 1 before the
70a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        decrement, then delete the object. Note that if this is the case, then
71a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        the object needs to have been allocated via new, and not on the stack.
728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void unref() const {
74f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
757b274c78fbeefa3818af68099545f2839c854847mtklein        // A release here acts in place of all releases we "should" have been doing in ref().
767b274c78fbeefa3818af68099545f2839c854847mtklein        if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
777b274c78fbeefa3818af68099545f2839c854847mtklein            // Like unique(), the acquire is only needed on success, to make sure
787b274c78fbeefa3818af68099545f2839c854847mtklein            // code in internal_dispose() doesn't happen before the decrement.
797b274c78fbeefa3818af68099545f2839c854847mtklein            this->internal_dispose();
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
8303087072483378a43f7b3f7a47944614187275ebrobertphillips@google.com#ifdef SK_DEBUG
847f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    void validate() const {
85f672cead70404080a991ebfb86c38316a4589b23commit-bot@chromium.org        SkASSERT(fRefCnt > 0);
867f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
8703087072483378a43f7b3f7a47944614187275ebrobertphillips@google.com#endif
887f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
89f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprotected:
90f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
91f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Allow subclasses to call this if they've overridden internal_dispose
92f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  so they can reset fRefCnt before the destructor is called. Should only
93f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  be called right before calling through to inherited internal_dispose()
94f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  or before calling the destructor.
95f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
96f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    void internal_dispose_restore_refcnt_to_1() const {
97a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#ifdef SK_DEBUG
98f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkASSERT(0 == fRefCnt);
99a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        fRefCnt = 1;
100a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com#endif
101f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    }
102f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com
103f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprivate:
104f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
105f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Called when the ref count goes to 0.
106f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
107f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    virtual void internal_dispose() const {
108f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        this->internal_dispose_restore_refcnt_to_1();
109a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com        SkDELETE(this);
110a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    }
11115c0fea699b25343fe6f49668a5632866e1a0306robertphillips@google.com
112f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    // The following friends are those which override internal_dispose()
113f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com    // and conditionally call SkRefCnt::internal_dispose().
114a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com    friend class SkWeakRefCnt;
115a02bc1519cf49afa31fb38bed097dd5014880d04bungeman@google.com
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mutable int32_t fRefCnt;
1174d73ac22a1b99402fc8cff78a4eb4b27aa8fe019robertphillips@google.com
11810ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com    typedef SkNoncopyable INHERITED;
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
12110ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#ifdef SK_REF_CNT_MIXIN_INCLUDE
12210ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com// It is the responsibility of the following include to define the type SkRefCnt.
12310ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com// This SkRefCnt should normally derive from SkRefCntBase.
12410ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#include SK_REF_CNT_MIXIN_INCLUDE
12510ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#else
12610ba006631a0c350aa2bcba188a60404869607c8bungeman@google.comclass SK_API SkRefCnt : public SkRefCntBase { };
12710ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com#endif
12810ba006631a0c350aa2bcba188a60404869607c8bungeman@google.com
1297f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
1307f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1317f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
1327f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    null in on each side of the assignment, and ensuring that ref() is called
1337f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    before unref(), in case the two pointers point to the same object.
1347f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1357f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com#define SkRefCnt_SafeAssign(dst, src)   \
1367f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    do {                                \
1377f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (src) src->ref();            \
1387f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        if (dst) dst->unref();          \
1397f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        dst = src;                      \
1407f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    } while (0)
1417f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1427f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1431fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com/** Call obj->ref() and return obj. The obj must not be NULL.
1447f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1451fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.comtemplate <typename T> static inline T* SkRef(T* obj) {
1461fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    SkASSERT(obj);
1471fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    obj->ref();
1481fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    return obj;
1491fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com}
1501fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com
1511fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com/** Check if the argument is non-null, and if so, call obj->ref() and return obj.
1521fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com */
1531fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.comtemplate <typename T> static inline T* SkSafeRef(T* obj) {
1547f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1557f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->ref();
1567f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1571fd201b9dfc739b7a615fdc1eb64dbe136e7cf76bungeman@google.com    return obj;
1587f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1597f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
1607f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com/** Check if the argument is non-null, and if so, call obj->unref()
1617f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com */
1627f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.comtemplate <typename T> static inline void SkSafeUnref(T* obj) {
1637f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    if (obj) {
1647f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com        obj->unref();
1657f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com    }
1667f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com}
1677f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
168a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.orgtemplate<typename T> static inline void SkSafeSetNull(T*& obj) {
16949f085dddff10473b6ebf832a974288300224e60bsalomon    if (obj) {
170a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org        obj->unref();
171a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org        obj = NULL;
172a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org    }
173a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org}
174a4de8c257ea0be8ff7081f645249b6afe5c48e7ecommit-bot@chromium.org
1757f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com///////////////////////////////////////////////////////////////////////////////
1767f6d6d4571c0682c81f8508ac4862b2dfea20aecreed@google.com
177a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com/**
17891208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com *  Utility class that simply unref's its argument in the destructor.
179a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com */
18091208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.comtemplate <typename T> class SkAutoTUnref : SkNoncopyable {
1818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
18291208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
18391208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    ~SkAutoTUnref() { SkSafeUnref(fObj); }
184a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
185a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* get() const { return fObj; }
186a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
1872863f082f2524ebae9e69f382b50065189912b47reed@google.com    T* reset(T* obj) {
18868d6bb0c119141b0c8637d0b1b3c8b73c7026933reed@google.com        SkSafeUnref(fObj);
18968d6bb0c119141b0c8637d0b1b3c8b73c7026933reed@google.com        fObj = obj;
1902863f082f2524ebae9e69f382b50065189912b47reed@google.com        return obj;
191a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com    }
192a44f7003e5f9d1353bc9274268fb5302e69fc94absalomon@google.com
1931dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com    void swap(SkAutoTUnref* other) {
1941dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        T* tmp = fObj;
1951dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        fObj = other->fObj;
1961dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com        other->fObj = tmp;
1971dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com    }
1981dfe88e00aeddf20690fd2469fd17e43f670ee3absalomon@google.com
199a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    /**
200a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  Return the hosted object (which may be null), transferring ownership.
201a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  The reference count is not modified, and the internal ptr is set to NULL
202a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  so unref() will not be called in our destructor. A subsequent call to
203a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     *  detach() will do nothing and return null.
204a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com     */
205a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    T* detach() {
206a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        T* obj = fObj;
207a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        fObj = NULL;
208a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com        return obj;
209a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    }
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
21176f5cc6e9e87ff247c3ef1f4b3fb03668db06e2emtklein    T* operator->() const { return fObj; }
212d71b75757335393d9643a5b7a0f2769b6ba52fb6bungeman    operator T*() const { return fObj; }
2131448cf8cb6c6cd4866f7c71bf32ad6bca5d683d1bsalomon@google.com
21491208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.comprivate:
21591208922687a33df1d5253928b8d5d7d4685c7acbungeman@google.com    T*  fObj;
216a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com};
217e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org// Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :(
218a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com
219a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.comclass SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
220a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.compublic:
221a67573e25faa81ea65e6fc368f66d3f0c0a5f189reed@google.com    SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
223e61a86cfa00ea393ecc4a71fca94e1d476a37ecccommit-bot@chromium.org#define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref)
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
22508d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein// This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16.
22608d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein// There's only benefit to using this if the deriving class does not otherwise need a vtable.
22708d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtkleintemplate <typename Derived>
22808d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtkleinclass SkNVRefCnt : SkNoncopyable {
22908d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtkleinpublic:
23008d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    SkNVRefCnt() : fRefCnt(1) {}
2313c850c561fcad1ac35bff4ec2875a40ef2309148reed    ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); }
23208d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein
23308d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same:
23408d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    //   - unique() needs acquire when it returns true, and no barrier if it returns false;
23508d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    //   - ref() doesn't need any barrier;
23608d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    //   - unref() needs a release barrier, and an acquire if it's going to call delete.
23708d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein
2387b274c78fbeefa3818af68099545f2839c854847mtklein    bool unique() const { return 1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire); }
2397b274c78fbeefa3818af68099545f2839c854847mtklein    void    ref() const { (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); }
24090d0ff013bbd8e5295d1517d41cb408e9d9f4d93reed    void  unref() const {
2417b274c78fbeefa3818af68099545f2839c854847mtklein        if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) {
2423c850c561fcad1ac35bff4ec2875a40ef2309148reed            SkDEBUGCODE(fRefCnt = 1;)   // restore the 1 for our destructor's assert
24390d0ff013bbd8e5295d1517d41cb408e9d9f4d93reed            SkDELETE((const Derived*)this);
24490d0ff013bbd8e5295d1517d41cb408e9d9f4d93reed        }
24590d0ff013bbd8e5295d1517d41cb408e9d9f4d93reed    }
2467b274c78fbeefa3818af68099545f2839c854847mtklein    void  deref() const { this->unref(); }
247844aa334a43a95cd83a27d565db1d3370d8dc10cFlorin Malita
24808d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtkleinprivate:
24908d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein    mutable int32_t fRefCnt;
25008d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein};
25108d1fccf6eeec0a9fd5421e59e4d05daccf6e339mtklein
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
253