blob: 28591920a68ba5dc167f44dd3507c3a5ec783648 [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
13#include "SkThread.h"
robertphillips@google.com977b9c82012-06-05 19:35:09 +000014#include "SkInstCnt.h"
bungeman@google.com91208922012-07-30 15:03:59 +000015#include "SkTemplates.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000016
commit-bot@chromium.org6d2533e2013-10-16 15:15:58 +000017/** \class SkRefCntBase
18
bungeman@google.com10ba0062013-10-25 18:40:24 +000019 SkRefCntBase is the base class for objects that may be shared by multiple
bungeman@google.coma02bc152012-05-16 18:21:56 +000020 objects. When an existing owner wants to share a reference, it calls ref().
21 When an owner wants to release its reference, it calls unref(). When the
22 shared object's reference count goes to zero as the result of an unref()
23 call, its (virtual) destructor is called. It is an error for the
24 destructor to be called explicitly (or via the object going out of scope on
25 the stack or calling delete) if getRefCnt() > 1.
reed@android.com8a1c16f2008-12-17 15:59:43 +000026*/
bungeman@google.com10ba0062013-10-25 18:40:24 +000027class SK_API SkRefCntBase : public SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +000028public:
bungeman@google.com10ba0062013-10-25 18:40:24 +000029 SK_DECLARE_INST_COUNT_ROOT(SkRefCntBase)
robertphillips@google.com977b9c82012-06-05 19:35:09 +000030
reed@android.com8a1c16f2008-12-17 15:59:43 +000031 /** Default construct, initializing the reference count to 1.
32 */
bungeman@google.com10ba0062013-10-25 18:40:24 +000033 SkRefCntBase() : fRefCnt(1) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
bungeman@google.coma02bc152012-05-16 18:21:56 +000035 /** Destruct, asserting that the reference count is 1.
reed@android.com8a1c16f2008-12-17 15:59:43 +000036 */
bungeman@google.com10ba0062013-10-25 18:40:24 +000037 virtual ~SkRefCntBase() {
reed@google.com4c888aa2011-09-12 19:54:12 +000038#ifdef SK_DEBUG
39 SkASSERT(fRefCnt == 1);
40 fRefCnt = 0; // illegal value, to catch us if we reuse after delete
41#endif
42 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000043
bungeman@google.comf64c6842013-07-19 23:18:52 +000044 /** Return the reference count. Use only for debugging. */
reed@android.com8a1c16f2008-12-17 15:59:43 +000045 int32_t getRefCnt() const { return fRefCnt; }
46
bungeman@google.comf64c6842013-07-19 23:18:52 +000047 /** Returns true if the caller is the only owner.
48 * Ensures that all previous owner's actions are complete.
49 */
50 bool unique() const {
51 bool const unique = (1 == fRefCnt);
52 if (unique) {
bungeman@google.comd9947f62013-12-18 15:27:39 +000053 // Acquire barrier (L/SL), if not provided by load of fRefCnt.
bungeman@google.comf64c6842013-07-19 23:18:52 +000054 // Prevents user's 'unique' code from happening before decrements.
55 //TODO: issue the barrier.
56 }
57 return unique;
58 }
59
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 /** Increment the reference count. Must be balanced by a call to unref().
61 */
62 void ref() const {
63 SkASSERT(fRefCnt > 0);
bungeman@google.coma02bc152012-05-16 18:21:56 +000064 sk_atomic_inc(&fRefCnt); // No barrier required.
reed@android.com8a1c16f2008-12-17 15:59:43 +000065 }
66
67 /** Decrement the reference count. If the reference count is 1 before the
bungeman@google.coma02bc152012-05-16 18:21:56 +000068 decrement, then delete the object. Note that if this is the case, then
69 the object needs to have been allocated via new, and not on the stack.
reed@android.com8a1c16f2008-12-17 15:59:43 +000070 */
71 void unref() const {
72 SkASSERT(fRefCnt > 0);
bungeman@google.coma02bc152012-05-16 18:21:56 +000073 // Release barrier (SL/S), if not provided below.
reed@android.com8a1c16f2008-12-17 15:59:43 +000074 if (sk_atomic_dec(&fRefCnt) == 1) {
bungeman@google.comd9947f62013-12-18 15:27:39 +000075 // Acquire barrier (L/SL), if not provided above.
bungeman@google.coma02bc152012-05-16 18:21:56 +000076 // Prevents code in dispose from happening before the decrement.
bungeman@google.comd9947f62013-12-18 15:27:39 +000077 sk_membar_acquire__after_atomic_dec();
bungeman@google.coma02bc152012-05-16 18:21:56 +000078 internal_dispose();
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 }
80 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000081
robertphillips@google.com03087072013-10-02 16:42:21 +000082#ifdef SK_DEBUG
reed@google.com7f6d6d42011-07-15 15:25:22 +000083 void validate() const {
84 SkASSERT(fRefCnt > 0);
85 }
robertphillips@google.com03087072013-10-02 16:42:21 +000086#endif
reed@google.com7f6d6d42011-07-15 15:25:22 +000087
reed@google.comf7943032012-07-23 14:50:38 +000088protected:
89 /**
90 * Allow subclasses to call this if they've overridden internal_dispose
91 * so they can reset fRefCnt before the destructor is called. Should only
92 * be called right before calling through to inherited internal_dispose()
93 * or before calling the destructor.
94 */
95 void internal_dispose_restore_refcnt_to_1() const {
bungeman@google.coma02bc152012-05-16 18:21:56 +000096#ifdef SK_DEBUG
reed@google.comf7943032012-07-23 14:50:38 +000097 SkASSERT(0 == fRefCnt);
bungeman@google.coma02bc152012-05-16 18:21:56 +000098 fRefCnt = 1;
99#endif
reed@google.comf7943032012-07-23 14:50:38 +0000100 }
101
102private:
103 /**
104 * Called when the ref count goes to 0.
105 */
106 virtual void internal_dispose() const {
107 this->internal_dispose_restore_refcnt_to_1();
bungeman@google.coma02bc152012-05-16 18:21:56 +0000108 SkDELETE(this);
109 }
robertphillips@google.com15c0fea2012-06-22 12:41:43 +0000110
bungeman@google.comf64c6842013-07-19 23:18:52 +0000111 // The following friends are those which override internal_dispose()
112 // and conditionally call SkRefCnt::internal_dispose().
113 friend class GrTexture;
bungeman@google.coma02bc152012-05-16 18:21:56 +0000114 friend class SkWeakRefCnt;
115
reed@android.com8a1c16f2008-12-17 15:59:43 +0000116 mutable int32_t fRefCnt;
robertphillips@google.com4d73ac22012-06-13 18:54:08 +0000117
bungeman@google.com10ba0062013-10-25 18:40:24 +0000118 typedef SkNoncopyable INHERITED;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000119};
120
bungeman@google.com10ba0062013-10-25 18:40:24 +0000121#ifdef SK_REF_CNT_MIXIN_INCLUDE
122// It is the responsibility of the following include to define the type SkRefCnt.
123// This SkRefCnt should normally derive from SkRefCntBase.
124#include SK_REF_CNT_MIXIN_INCLUDE
125#else
126class SK_API SkRefCnt : public SkRefCntBase { };
127#endif
128
reed@google.com7f6d6d42011-07-15 15:25:22 +0000129///////////////////////////////////////////////////////////////////////////////
130
131/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
132 null in on each side of the assignment, and ensuring that ref() is called
133 before unref(), in case the two pointers point to the same object.
134 */
135#define SkRefCnt_SafeAssign(dst, src) \
136 do { \
137 if (src) src->ref(); \
138 if (dst) dst->unref(); \
139 dst = src; \
140 } while (0)
141
142
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000143/** Call obj->ref() and return obj. The obj must not be NULL.
reed@google.com7f6d6d42011-07-15 15:25:22 +0000144 */
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000145template <typename T> static inline T* SkRef(T* obj) {
146 SkASSERT(obj);
147 obj->ref();
148 return obj;
149}
150
151/** Check if the argument is non-null, and if so, call obj->ref() and return obj.
152 */
153template <typename T> static inline T* SkSafeRef(T* obj) {
reed@google.com7f6d6d42011-07-15 15:25:22 +0000154 if (obj) {
155 obj->ref();
156 }
bungeman@google.com1fd201b2012-08-22 18:56:56 +0000157 return obj;
reed@google.com7f6d6d42011-07-15 15:25:22 +0000158}
159
160/** Check if the argument is non-null, and if so, call obj->unref()
161 */
162template <typename T> static inline void SkSafeUnref(T* obj) {
163 if (obj) {
164 obj->unref();
165 }
166}
167
commit-bot@chromium.orga4de8c22013-09-09 13:38:37 +0000168template<typename T> static inline void SkSafeSetNull(T*& obj) {
169 if (NULL != obj) {
170 obj->unref();
171 obj = NULL;
172 }
173}
174
reed@google.com7f6d6d42011-07-15 15:25:22 +0000175///////////////////////////////////////////////////////////////////////////////
176
reed@google.coma67573e2011-02-25 18:10:29 +0000177/**
bungeman@google.com91208922012-07-30 15:03:59 +0000178 * Utility class that simply unref's its argument in the destructor.
reed@google.coma67573e2011-02-25 18:10:29 +0000179 */
bungeman@google.com91208922012-07-30 15:03:59 +0000180template <typename T> class SkAutoTUnref : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000181public:
bungeman@google.com91208922012-07-30 15:03:59 +0000182 explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
183 ~SkAutoTUnref() { SkSafeUnref(fObj); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000184
reed@google.coma67573e2011-02-25 18:10:29 +0000185 T* get() const { return fObj; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000186
reed@google.com2863f082013-03-13 21:28:44 +0000187 T* reset(T* obj) {
reed@google.com68d6bb02012-11-27 18:37:52 +0000188 SkSafeUnref(fObj);
189 fObj = obj;
reed@google.com2863f082013-03-13 21:28:44 +0000190 return obj;
bsalomon@google.coma44f7002011-08-09 15:30:41 +0000191 }
192
bsalomon@google.com1dfe88e2012-10-03 13:46:20 +0000193 void swap(SkAutoTUnref* other) {
194 T* tmp = fObj;
195 fObj = other->fObj;
196 other->fObj = tmp;
197 }
198
reed@google.coma67573e2011-02-25 18:10:29 +0000199 /**
200 * Return the hosted object (which may be null), transferring ownership.
201 * The reference count is not modified, and the internal ptr is set to NULL
202 * so unref() will not be called in our destructor. A subsequent call to
203 * detach() will do nothing and return null.
204 */
205 T* detach() {
206 T* obj = fObj;
207 fObj = NULL;
208 return obj;
209 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000210
bungeman@google.come70f7982012-06-01 19:38:19 +0000211 /**
bungeman@google.com6f4cf2a2013-04-16 15:24:31 +0000212 * BlockRef<B> is a type which inherits from B, cannot be created,
213 * cannot be deleted, and makes ref and unref private.
bungeman@google.come70f7982012-06-01 19:38:19 +0000214 */
bungeman@google.com04640292012-06-01 19:47:51 +0000215 template<typename B> class BlockRef : public B {
bungeman@google.come70f7982012-06-01 19:38:19 +0000216 private:
217 BlockRef();
bungeman@google.com6f4cf2a2013-04-16 15:24:31 +0000218 ~BlockRef();
bungeman@google.come70f7982012-06-01 19:38:19 +0000219 void ref() const;
220 void unref() const;
221 };
bsalomon@google.com1448cf82012-07-27 13:27:35 +0000222
bungeman@google.com91208922012-07-30 15:03:59 +0000223 /** If T is const, the type returned from operator-> will also be const. */
224 typedef typename SkTConstType<BlockRef<T>, SkTIsConst<T>::value>::type BlockRefType;
225
226 /**
227 * SkAutoTUnref assumes ownership of the ref. As a result, it is an error
228 * for the user to ref or unref through SkAutoTUnref. Therefore
229 * SkAutoTUnref::operator-> returns BlockRef<T>*. This prevents use of
230 * skAutoTUnrefInstance->ref() and skAutoTUnrefInstance->unref().
231 */
232 BlockRefType *operator->() const {
233 return static_cast<BlockRefType*>(fObj);
234 }
235 operator T*() { return fObj; }
bsalomon@google.com1448cf82012-07-27 13:27:35 +0000236
237private:
bungeman@google.com91208922012-07-30 15:03:59 +0000238 T* fObj;
reed@google.coma67573e2011-02-25 18:10:29 +0000239};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000240// Can't use the #define trick below to guard a bare SkAutoTUnref(...) because it's templated. :(
reed@google.coma67573e2011-02-25 18:10:29 +0000241
242class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
243public:
244 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000246#define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref)
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247
reed@google.com7f6d6d42011-07-15 15:25:22 +0000248class SkAutoRef : SkNoncopyable {
249public:
250 SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
251 ~SkAutoRef() { SkSafeUnref(fObj); }
252private:
253 SkRefCnt* fObj;
254};
commit-bot@chromium.orge61a86c2013-11-18 16:03:59 +0000255#define SkAutoRef(...) SK_REQUIRE_LOCAL_VAR(SkAutoRef)
reed@android.com149e2f62009-05-22 14:39:03 +0000256
robertphillips@google.com2b4e5442013-01-07 00:58:00 +0000257/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
258 a SkRefCnt (or subclass) object.
259 */
260template <typename T> class SkRefPtr {
261public:
262 SkRefPtr() : fObj(NULL) {}
263 SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
264 SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
265 ~SkRefPtr() { SkSafeUnref(fObj); }
266
267 SkRefPtr& operator=(const SkRefPtr& rp) {
268 SkRefCnt_SafeAssign(fObj, rp.fObj);
269 return *this;
270 }
271 SkRefPtr& operator=(T* obj) {
272 SkRefCnt_SafeAssign(fObj, obj);
273 return *this;
274 }
275
276 T* get() const { return fObj; }
277 T& operator*() const { return *fObj; }
278 T* operator->() const { return fObj; }
279
280 typedef T* SkRefPtr::*unspecified_bool_type;
281 operator unspecified_bool_type() const {
282 return fObj ? &SkRefPtr::fObj : NULL;
283 }
284
285private:
286 T* fObj;
287};
288
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289#endif