blob: c718987b517ab4726943f235a9531568489f3ebf [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkRefCnt_DEFINED
11#define SkRefCnt_DEFINED
12
commit-bot@chromium.orgea6e14a2014-02-04 18:00:23 +000013#include "SkDynamicAnnotations.h"
commit-bot@chromium.org86b0de42014-05-28 20:02:17 +000014#include "SkThread.h"
robertphillips@google.com977b9c82012-06-05 19:35:09 +000015#include "SkInstCnt.h"
bungeman@google.com91208922012-07-30 15:03:59 +000016#include "SkTemplates.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000017
commit-bot@chromium.org6d2533e2013-10-16 15:15:58 +000018/** \class SkRefCntBase
19
bungeman@google.com10ba0062013-10-25 18:40:24 +000020 SkRefCntBase is the base class for objects that may be shared by multiple
bungeman@google.coma02bc152012-05-16 18:21:56 +000021 objects. When an existing owner wants to share a reference, it calls ref().
22 When an owner wants to release its reference, it calls unref(). When the
23 shared object's reference count goes to zero as the result of an unref()
24 call, its (virtual) destructor is called. It is an error for the
25 destructor to be called explicitly (or via the object going out of scope on
26 the stack or calling delete) if getRefCnt() > 1.
reed@android.com8a1c16f2008-12-17 15:59:43 +000027*/
commit-bot@chromium.orge3beb6b2014-04-07 19:34:38 +000028class SK_API SkRefCntBase : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +000029public:
bungeman@google.com10ba0062013-10-25 18:40:24 +000030 SK_DECLARE_INST_COUNT_ROOT(SkRefCntBase)
robertphillips@google.com977b9c82012-06-05 19:35:09 +000031
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 /** Default construct, initializing the reference count to 1.
33 */
bungeman@google.com10ba0062013-10-25 18:40:24 +000034 SkRefCntBase() : fRefCnt(1) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000035
bungeman@google.coma02bc152012-05-16 18:21:56 +000036 /** Destruct, asserting that the reference count is 1.
reed@android.com8a1c16f2008-12-17 15:59:43 +000037 */
bungeman@google.com10ba0062013-10-25 18:40:24 +000038 virtual ~SkRefCntBase() {
reed@google.com4c888aa2011-09-12 19:54:12 +000039#ifdef SK_DEBUG
mtkleinb59161f2014-06-18 07:54:47 -070040 SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt);
reed@google.com4c888aa2011-09-12 19:54:12 +000041 fRefCnt = 0; // illegal value, to catch us if we reuse after delete
42#endif
43 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000044
Mike Kleinfa141132014-11-24 16:26:15 -050045//#ifdef SK_DEBUG
bungeman@google.comf64c6842013-07-19 23:18:52 +000046 /** Return the reference count. Use only for debugging. */
reed@android.com8a1c16f2008-12-17 15:59:43 +000047 int32_t getRefCnt() const { return fRefCnt; }
Mike Kleinfa141132014-11-24 16:26:15 -050048//#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000049
commit-bot@chromium.orgea6e14a2014-02-04 18:00:23 +000050 /** May return true if the caller is the only owner.
bungeman@google.comf64c6842013-07-19 23:18:52 +000051 * Ensures that all previous owner's actions are complete.
52 */
53 bool unique() const {
commit-bot@chromium.orgea6e14a2014-02-04 18:00:23 +000054 // We believe we're reading fRefCnt in a safe way here, so we stifle the TSAN warning about
55 // an unproctected read. Generally, don't read fRefCnt, and don't stifle this warning.
bungemana5cf6652014-10-29 12:31:33 -070056 bool const unique = (1 == sk_acquire_load(&fRefCnt));
bungeman@google.comf64c6842013-07-19 23:18:52 +000057 if (unique) {
bungeman@google.comd9947f62013-12-18 15:27:39 +000058 // Acquire barrier (L/SL), if not provided by load of fRefCnt.
bungeman@google.comf64c6842013-07-19 23:18:52 +000059 // Prevents user's 'unique' code from happening before decrements.
bungemana5cf6652014-10-29 12:31:33 -070060 //TODO: issue the barrier only when unique is true
bungeman@google.comf64c6842013-07-19 23:18:52 +000061 }
62 return unique;
63 }
64
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 /** Increment the reference count. Must be balanced by a call to unref().
66 */
67 void ref() const {
commit-bot@chromium.orgf672cea2014-04-27 19:21:51 +000068 SkASSERT(fRefCnt > 0);
bungeman@google.coma02bc152012-05-16 18:21:56 +000069 sk_atomic_inc(&fRefCnt); // No barrier required.
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 }
71
72 /** Decrement the reference count. If the reference count is 1 before the
bungeman@google.coma02bc152012-05-16 18:21:56 +000073 decrement, then delete the object. Note that if this is the case, then
74 the object needs to have been allocated via new, and not on the stack.
reed@android.com8a1c16f2008-12-17 15:59:43 +000075 */
76 void unref() const {
commit-bot@chromium.orgf672cea2014-04-27 19:21:51 +000077 SkASSERT(fRefCnt > 0);
bungeman@google.coma02bc152012-05-16 18:21:56 +000078 // Release barrier (SL/S), if not provided below.
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 if (sk_atomic_dec(&fRefCnt) == 1) {
bungeman@google.comd9947f62013-12-18 15:27:39 +000080 // Acquire barrier (L/SL), if not provided above.
bungeman@google.coma02bc152012-05-16 18:21:56 +000081 // Prevents code in dispose from happening before the decrement.
bungeman@google.comd9947f62013-12-18 15:27:39 +000082 sk_membar_acquire__after_atomic_dec();
bungeman@google.coma02bc152012-05-16 18:21:56 +000083 internal_dispose();
reed@android.com8a1c16f2008-12-17 15:59:43 +000084 }
85 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000086
robertphillips@google.com03087072013-10-02 16:42:21 +000087#ifdef SK_DEBUG
reed@google.com7f6d6d42011-07-15 15:25:22 +000088 void validate() const {
commit-bot@chromium.orgf672cea2014-04-27 19:21:51 +000089 SkASSERT(fRefCnt > 0);
reed@google.com7f6d6d42011-07-15 15:25:22 +000090 }
robertphillips@google.com03087072013-10-02 16:42:21 +000091#endif
reed@google.com7f6d6d42011-07-15 15:25:22 +000092
reed@google.comf7943032012-07-23 14:50:38 +000093protected:
94 /**
95 * Allow subclasses to call this if they've overridden internal_dispose
96 * so they can reset fRefCnt before the destructor is called. Should only
97 * be called right before calling through to inherited internal_dispose()
98 * or before calling the destructor.
99 */
100 void internal_dispose_restore_refcnt_to_1() const {
bungeman@google.coma02bc152012-05-16 18:21:56 +0000101#ifdef SK_DEBUG
reed@google.comf7943032012-07-23 14:50:38 +0000102 SkASSERT(0 == fRefCnt);
bungeman@google.coma02bc152012-05-16 18:21:56 +0000103 fRefCnt = 1;
104#endif
reed@google.comf7943032012-07-23 14:50:38 +0000105 }
106
107private:
108 /**
109 * Called when the ref count goes to 0.
110 */
111 virtual void internal_dispose() const {
112 this->internal_dispose_restore_refcnt_to_1();
bungeman@google.coma02bc152012-05-16 18:21:56 +0000113 SkDELETE(this);
114 }
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000115
bungeman@google.comf64c6842013-07-19 23:18:52 +0000116 // The following friends are those which override internal_dispose()
117 // and conditionally call SkRefCnt::internal_dispose().
bungeman@google.coma02bc152012-05-16 18:21:56 +0000118 friend class SkWeakRefCnt;
119
reed@android.com8a1c16f2008-12-17 15:59:43 +0000120 mutable int32_t fRefCnt;
robertphillips@google.com4d73ac22012-06-13 18:54:08 +0000121
bungeman@google.com10ba0062013-10-25 18:40:24 +0000122 typedef SkNoncopyable INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123};
124
bungeman@google.com10ba0062013-10-25 18:40:24 +0000125#ifdef SK_REF_CNT_MIXIN_INCLUDE
126// It is the responsibility of the following include to define the type SkRefCnt.
127// This SkRefCnt should normally derive from SkRefCntBase.
128#include SK_REF_CNT_MIXIN_INCLUDE
129#else
130class SK_API SkRefCnt : public SkRefCntBase { };
131#endif
132
reed@google.com7f6d6d42011-07-15 15:25:22 +0000133///////////////////////////////////////////////////////////////////////////////
134
135/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
136 null in on each side of the assignment, and ensuring that ref() is called
137 before unref(), in case the two pointers point to the same object.
138 */
139#define SkRefCnt_SafeAssign(dst, src) \
140 do { \
141 if (src) src->ref(); \
142 if (dst) dst->unref(); \
143 dst = src; \
144 } while (0)
145
146
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000147/** Call obj->ref() and return obj. The obj must not be NULL.
reed@google.com7f6d6d42011-07-15 15:25:22 +0000148 */
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000149template <typename T> static inline T* SkRef(T* obj) {
150 SkASSERT(obj);
151 obj->ref();
152 return obj;
153}
154
155/** Check if the argument is non-null, and if so, call obj->ref() and return obj.
156 */
157template <typename T> static inline T* SkSafeRef(T* obj) {
reed@google.com7f6d6d42011-07-15 15:25:22 +0000158 if (obj) {
159 obj->ref();
160 }
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000161 return obj;
reed@google.com7f6d6d42011-07-15 15:25:22 +0000162}
163
164/** Check if the argument is non-null, and if so, call obj->unref()
165 */
166template <typename T> static inline void SkSafeUnref(T* obj) {
167 if (obj) {
168 obj->unref();
169 }
170}
171
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000172template<typename T> static inline void SkSafeSetNull(T*& obj) {
bsalomon49f085d2014-09-05 13:34:00 -0700173 if (obj) {
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000174 obj->unref();
175 obj = NULL;
176 }
177}
178
reed@google.com7f6d6d42011-07-15 15:25:22 +0000179///////////////////////////////////////////////////////////////////////////////
180
reed@google.coma67573e2011-02-25 18:10:29 +0000181/**
bungeman@google.com91208922012-07-30 15:03:59 +0000182 * Utility class that simply unref's its argument in the destructor.
reed@google.coma67573e2011-02-25 18:10:29 +0000183 */
bungeman@google.com91208922012-07-30 15:03:59 +0000184template <typename T> class SkAutoTUnref : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185public:
bungeman@google.com91208922012-07-30 15:03:59 +0000186 explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
187 ~SkAutoTUnref() { SkSafeUnref(fObj); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188
reed@google.coma67573e2011-02-25 18:10:29 +0000189 T* get() const { return fObj; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190
reed@google.com2863f082013-03-13 21:28:44 +0000191 T* reset(T* obj) {
reed@google.com68d6bb02012-11-27 18:37:52 +0000192 SkSafeUnref(fObj);
193 fObj = obj;
reed@google.com2863f082013-03-13 21:28:44 +0000194 return obj;
bsalomon@google.coma44f7002011-08-09 15:30:41 +0000195 }
196
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +0000197 void swap(SkAutoTUnref* other) {
198 T* tmp = fObj;
199 fObj = other->fObj;
200 other->fObj = tmp;
201 }
202
reed@google.coma67573e2011-02-25 18:10:29 +0000203 /**
204 * Return the hosted object (which may be null), transferring ownership.
205 * The reference count is not modified, and the internal ptr is set to NULL
206 * so unref() will not be called in our destructor. A subsequent call to
207 * detach() will do nothing and return null.
208 */
209 T* detach() {
210 T* obj = fObj;
211 fObj = NULL;
212 return obj;
213 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000214
bungeman@google.come70f7982012-06-01 19:38:19 +0000215 /**
bungeman@google.com6f4cf2a2013-04-16 15:24:31 +0000216 * BlockRef<B> is a type which inherits from B, cannot be created,
217 * cannot be deleted, and makes ref and unref private.
bungeman@google.come70f7982012-06-01 19:38:19 +0000218 */
bungeman@google.com04640292012-06-01 19:47:51 +0000219 template<typename B> class BlockRef : public B {
bungeman@google.come70f7982012-06-01 19:38:19 +0000220 private:
221 BlockRef();
bungeman@google.com6f4cf2a2013-04-16 15:24:31 +0000222 ~BlockRef();
bungeman@google.come70f7982012-06-01 19:38:19 +0000223 void ref() const;
224 void unref() const;
225 };
bsalomon@google.com1448cf82012-07-27 13:27:35 +0000226
bungeman@google.com91208922012-07-30 15:03:59 +0000227 /** If T is const, the type returned from operator-> will also be const. */
228 typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType;
229
230 /**
231 * SkAutoTUnref assumes ownership of the ref. As a result, it is an error
232 * for the user to ref or unref through SkAutoTUnref. Therefore
233 * SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
234 * skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
235 */
236 BlockRefType *operator->() const {
237 return static_cast<BlockRefType*>(fObj);
238 }
bungemand71b7572014-09-18 10:55:32 -0700239 operator T*() const { return fObj; }
bsalomon@google.com1448cf82012-07-27 13:27:35 +0000240
241private:
bungeman@google.com91208922012-07-30 15:03:59 +0000242 T* fObj;
reed@google.coma67573e2011-02-25 18:10:29 +0000243};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000244// Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :(
reed@google.coma67573e2011-02-25 18:10:29 +0000245
246class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
247public:
248 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000250#define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251
mtklein08d1fcc2014-11-20 09:18:31 -0800252// This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16.
253// There's only benefit to using this if the deriving class does not otherwise need a vtable.
254template <typename Derived>
255class SkNVRefCnt : SkNoncopyable {
256public:
257 SkNVRefCnt() : fRefCnt(1) {}
reed3c850c52014-11-24 14:13:55 -0800258 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); }
mtklein08d1fcc2014-11-20 09:18:31 -0800259
260 // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same:
261 // - unique() needs acquire when it returns true, and no barrier if it returns false;
262 // - ref() doesn't need any barrier;
263 // - unref() needs a release barrier, and an acquire if it's going to call delete.
264
265 bool unique() const { return 1 == sk_acquire_load(&fRefCnt); }
266 void ref() const { sk_atomic_inc(&fRefCnt); }
reed90d0ff02014-11-24 12:02:31 -0800267 void unref() const {
268 int32_t prevValue = sk_atomic_dec(&fRefCnt);
269 SkASSERT(prevValue >= 1);
270 if (1 == prevValue) {
reed3c850c52014-11-24 14:13:55 -0800271 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's assert
reed90d0ff02014-11-24 12:02:31 -0800272 SkDELETE((const Derived*)this);
273 }
274 }
mtkleind6ab2a82014-11-20 10:07:54 -0800275 void deref() const { this->unref(); } // Chrome prefers to call deref().
Florin Malita844aa332014-11-20 16:56:22 -0500276
mtklein08d1fcc2014-11-20 09:18:31 -0800277private:
278 mutable int32_t fRefCnt;
279};
280
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281#endif