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