1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SkRefCnt_DEFINED 18 #define SkRefCnt_DEFINED 19 20 #include "SkThread.h" 21 22 /** \class SkRefCnt 23 24 SkRefCnt is the base class for objects that may be shared by multiple 25 objects. When a new owner wants a reference, it calls ref(). When an owner 26 wants to release its reference, it calls unref(). When the shared object's 27 reference count goes to zero as the result of an unref() call, its (virtual) 28 destructor is called. It is an error for the destructor to be called 29 explicitly (or via the object going out of scope on the stack or calling 30 delete) if getRefCnt() > 1. 31 */ 32 class SK_API SkRefCnt : SkNoncopyable { 33 public: 34 /** Default construct, initializing the reference count to 1. 35 */ 36 SkRefCnt() : fRefCnt(1) {} 37 38 /** Destruct, asserting that the reference count is 1. 39 */ 40 virtual ~SkRefCnt() { SkASSERT(fRefCnt == 1); } 41 42 /** Return the reference count. 43 */ 44 int32_t getRefCnt() const { return fRefCnt; } 45 46 /** Increment the reference count. Must be balanced by a call to unref(). 47 */ 48 void ref() const { 49 SkASSERT(fRefCnt > 0); 50 sk_atomic_inc(&fRefCnt); 51 } 52 53 /** Decrement the reference count. If the reference count is 1 before the 54 decrement, then call delete on the object. Note that if this is the 55 case, then the object needs to have been allocated via new, and not on 56 the stack. 57 */ 58 void unref() const { 59 SkASSERT(fRefCnt > 0); 60 if (sk_atomic_dec(&fRefCnt) == 1) { 61 fRefCnt = 1; // so our destructor won't complain 62 SkDELETE(this); 63 } 64 } 65 66 private: 67 mutable int32_t fRefCnt; 68 }; 69 70 /** 71 * Utility class that simply unref's its argument in the destructor. 72 */ 73 template <typename T> class SkAutoTUnref : SkNoncopyable { 74 public: 75 SkAutoTUnref(T* obj) : fObj(obj) {} 76 ~SkAutoTUnref() { SkSafeUnref(fObj); } 77 78 T* get() const { return fObj; } 79 80 /** 81 * Return the hosted object (which may be null), transferring ownership. 82 * The reference count is not modified, and the internal ptr is set to NULL 83 * so unref() will not be called in our destructor. A subsequent call to 84 * detach() will do nothing and return null. 85 */ 86 T* detach() { 87 T* obj = fObj; 88 fObj = NULL; 89 return obj; 90 } 91 92 private: 93 T* fObj; 94 }; 95 96 class SkAutoUnref : public SkAutoTUnref<SkRefCnt> { 97 public: 98 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {} 99 }; 100 101 /////////////////////////////////////////////////////////////////////////////// 102 103 /** Helper macro to safely assign one SkRefCnt[TS]* to another, checking for 104 null in on each side of the assignment, and ensuring that ref() is called 105 before unref(), in case the two pointers point to the same object. 106 */ 107 #define SkRefCnt_SafeAssign(dst, src) \ 108 do { \ 109 if (src) src->ref(); \ 110 if (dst) dst->unref(); \ 111 dst = src; \ 112 } while (0) 113 114 115 /** Check if the argument is non-null, and if so, call obj->ref() 116 */ 117 template <typename T> static inline void SkSafeRef(T* obj) { 118 if (obj) { 119 obj->ref(); 120 } 121 } 122 123 /** Check if the argument is non-null, and if so, call obj->unref() 124 */ 125 template <typename T> static inline void SkSafeUnref(T* obj) { 126 if (obj) { 127 obj->unref(); 128 } 129 } 130 131 /** Wrapper class for SkRefCnt pointers. This manages ref/unref of a pointer to 132 a SkRefCnt (or subclass) object. 133 */ 134 template <typename T> class SkRefPtr { 135 public: 136 SkRefPtr() : fObj(NULL) {} 137 SkRefPtr(T* obj) : fObj(obj) { SkSafeRef(fObj); } 138 SkRefPtr(const SkRefPtr& o) : fObj(o.fObj) { SkSafeRef(fObj); } 139 ~SkRefPtr() { SkSafeUnref(fObj); } 140 141 SkRefPtr& operator=(const SkRefPtr& rp) { 142 SkRefCnt_SafeAssign(fObj, rp.fObj); 143 return *this; 144 } 145 SkRefPtr& operator=(T* obj) { 146 SkRefCnt_SafeAssign(fObj, obj); 147 return *this; 148 } 149 150 T* get() const { return fObj; } 151 T& operator*() const { return *fObj; } 152 T* operator->() const { return fObj; } 153 154 typedef T* SkRefPtr::*unspecified_bool_type; 155 operator unspecified_bool_type() const { 156 return fObj ? &SkRefPtr::fObj : NULL; 157 } 158 159 private: 160 T* fObj; 161 }; 162 163 #endif 164 165