blob: 4c9376b44a5335dd929dad10fe4086962a229d11 [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"
14
15/** \class SkRefCnt
16
17 SkRefCnt is the base class for objects that may be shared by multiple
18 objects. When a new owner wants a reference, it calls ref(). When an owner
19 wants to release its reference, it calls unref(). When the shared object's
20 reference count goes to zero as the result of an unref() call, its (virtual)
21 destructor is called. It is an error for the destructor to be called
22 explicitly (or via the object going out of scope on the stack or calling
23 delete) if getRefCnt() > 1.
24*/
ctguil@chromium.org7ffb1b22011-03-15 21:27:08 +000025class SK_API SkRefCnt : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +000026public:
27 /** Default construct, initializing the reference count to 1.
28 */
29 SkRefCnt() : fRefCnt(1) {}
30
31 /** Destruct, asserting that the reference count is 1.
32 */
33 virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); }
34
35 /** Return the reference count.
36 */
37 int32_t getRefCnt() const { return fRefCnt; }
38
39 /** Increment the reference count. Must be balanced by a call to unref().
40 */
41 void ref() const {
42 SkASSERT(fRefCnt > 0);
43 sk_atomic_inc(&fRefCnt);
44 }
45
46 /** Decrement the reference count. If the reference count is 1 before the
47 decrement, then call delete on the object. Note that if this is the
48 case, then the object needs to have been allocated via new, and not on
49 the stack.
50 */
51 void unref() const {
52 SkASSERT(fRefCnt > 0);
53 if (sk_atomic_dec(&fRefCnt) == 1) {
54 fRefCnt = 1; // so our destructor won't complain
55 SkDELETE(this);
56 }
57 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000058
reed@google.com7f6d6d42011-07-15 15:25:22 +000059 void validate() const {
60 SkASSERT(fRefCnt > 0);
61 }
62
reed@android.com8a1c16f2008-12-17 15:59:43 +000063private:
64 mutable int32_t fRefCnt;
65};
66
reed@google.com7f6d6d42011-07-15 15:25:22 +000067///////////////////////////////////////////////////////////////////////////////
68
69/** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for
70 null in on each side of the assignment, and ensuring that ref() is called
71 before unref(), in case the two pointers point to the same object.
72 */
73#define SkRefCnt_SafeAssign(dst, src) \
74 do { \
75 if (src) src->ref(); \
76 if (dst) dst->unref(); \
77 dst = src; \
78 } while (0)
79
80
81/** Check if the argument is non-null, and if so, call obj->ref()
82 */
83template <typename T> static inline void SkSafeRef(T* obj) {
84 if (obj) {
85 obj->ref();
86 }
87}
88
89/** Check if the argument is non-null, and if so, call obj->unref()
90 */
91template <typename T> static inline void SkSafeUnref(T* obj) {
92 if (obj) {
93 obj->unref();
94 }
95}
96
97///////////////////////////////////////////////////////////////////////////////
98
reed@google.coma67573e2011-02-25 18:10:29 +000099/**
100 * Utility class that simply unref's its argument in the destructor.
101 */
102template <typename T> class SkAutoTUnref : SkNoncopyable {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103public:
bsalomon@google.coma44f7002011-08-09 15:30:41 +0000104 explicit SkAutoTUnref(T* obj = NULL) : fObj(obj) {}
reed@google.coma67573e2011-02-25 18:10:29 +0000105 ~SkAutoTUnref() { SkSafeUnref(fObj); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000106
reed@google.coma67573e2011-02-25 18:10:29 +0000107 T* get() const { return fObj; }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000108
bsalomon@google.coma44f7002011-08-09 15:30:41 +0000109 void reset(T* obj) {
110 SkSafeUnref(fObj);
111 fObj = obj;
112 }
113
reed@google.coma67573e2011-02-25 18:10:29 +0000114 /**
115 * Return the hosted object (which may be null), transferring ownership.
116 * The reference count is not modified, and the internal ptr is set to NULL
117 * so unref() will not be called in our destructor. A subsequent call to
118 * detach() will do nothing and return null.
119 */
120 T* detach() {
121 T* obj = fObj;
122 fObj = NULL;
123 return obj;
124 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000125
126private:
reed@google.coma67573e2011-02-25 18:10:29 +0000127 T* fObj;
128};
129
130class SkAutoUnref : public SkAutoTUnref<SkRefCnt> {
131public:
132 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {}
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133};
134
reed@google.com7f6d6d42011-07-15 15:25:22 +0000135class SkAutoRef : SkNoncopyable {
136public:
137 SkAutoRef(SkRefCnt* obj) : fObj(obj) { SkSafeRef(obj); }
138 ~SkAutoRef() { SkSafeUnref(fObj); }
139private:
140 SkRefCnt* fObj;
141};
reed@android.com149e2f62009-05-22 14:39:03 +0000142
reed@android.com756f6dd2010-04-16 20:56:00 +0000143/** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to
144 a SkRefCnt (or subclass) object.
145 */
146template <typename T> class SkRefPtr {
reed@android.comb00cd722010-04-16 20:35:47 +0000147public:
148 SkRefPtr() : fObj(NULL) {}
149 SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); }
150 SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); }
151 ~SkRefPtr() { SkSafeUnref(fObj); }
152
153 SkRefPtr& operator=(const SkRefPtr& rp) {
154 SkRefCnt_SafeAssign(fObj, rp.fObj);
155 return *this;
156 }
157 SkRefPtr& operator=(T* obj) {
158 SkRefCnt_SafeAssign(fObj, obj);
159 return *this;
160 }
161
reed@android.comb00cd722010-04-16 20:35:47 +0000162 T* get() const { return fObj; }
163 T& operator*() const { return *fObj; }
164 T* operator->() const { return fObj; }
reed@android.comb00cd722010-04-16 20:35:47 +0000165
166 typedef T* SkRefPtr::*unspecified_bool_type;
reed@google.comddbf4c82011-03-08 16:06:06 +0000167 operator unspecified_bool_type() const {
168 return fObj ? &SkRefPtr::fObj : NULL;
169 }
reed@android.comb00cd722010-04-16 20:35:47 +0000170
171private:
172 T* fObj;
173};
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175#endif
176