| 1 | /* | 
|---|
| 2 | * Copyright 2006 The Android Open Source Project | 
|---|
| 3 | * | 
|---|
| 4 | * Use of this source code is governed by a BSD-style license that can be | 
|---|
| 5 | * found in the LICENSE file. | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef SkRefCnt_DEFINED | 
|---|
| 9 | #define SkRefCnt_DEFINED | 
|---|
| 10 |  | 
|---|
| 11 | #include "include/core/SkTypes.h" | 
|---|
| 12 |  | 
|---|
| 13 | #include <atomic>       // std::atomic, std::memory_order_* | 
|---|
| 14 | #include <cstddef>      // std::nullptr_t | 
|---|
| 15 | #include <iosfwd>       // std::basic_ostream | 
|---|
| 16 | #include <memory>       // TODO: unused | 
|---|
| 17 | #include <type_traits>  // std::enable_if, std::is_convertible | 
|---|
| 18 | #include <utility>      // std::forward, std::swap | 
|---|
| 19 |  | 
|---|
| 20 | /** \class SkRefCntBase | 
|---|
| 21 |  | 
|---|
| 22 | SkRefCntBase is the base class for objects that may be shared by multiple | 
|---|
| 23 | objects. When an existing owner wants to share a reference, it calls ref(). | 
|---|
| 24 | When an owner wants to release its reference, it calls unref(). When the | 
|---|
| 25 | shared object's reference count goes to zero as the result of an unref() | 
|---|
| 26 | call, its (virtual) destructor is called. It is an error for the | 
|---|
| 27 | destructor to be called explicitly (or via the object going out of scope on | 
|---|
| 28 | the stack or calling delete) if getRefCnt() > 1. | 
|---|
| 29 | */ | 
|---|
| 30 | class SK_API SkRefCntBase { | 
|---|
| 31 | public: | 
|---|
| 32 | /** Default construct, initializing the reference count to 1. | 
|---|
| 33 | */ | 
|---|
| 34 | SkRefCntBase() : fRefCnt(1) {} | 
|---|
| 35 |  | 
|---|
| 36 | /** Destruct, asserting that the reference count is 1. | 
|---|
| 37 | */ | 
|---|
| 38 | virtual ~SkRefCntBase() { | 
|---|
| 39 | #ifdef SK_DEBUG | 
|---|
| 40 | SkASSERTF(this->getRefCnt() == 1, "fRefCnt was %d", this->getRefCnt()); | 
|---|
| 41 | // illegal value, to catch us if we reuse after delete | 
|---|
| 42 | fRefCnt.store(0, std::memory_order_relaxed); | 
|---|
| 43 | #endif | 
|---|
| 44 | } | 
|---|
| 45 |  | 
|---|
| 46 | /** May return true if the caller is the only owner. | 
|---|
| 47 | *  Ensures that all previous owner's actions are complete. | 
|---|
| 48 | */ | 
|---|
| 49 | bool unique() const { | 
|---|
| 50 | if (1 == fRefCnt.load(std::memory_order_acquire)) { | 
|---|
| 51 | // The acquire barrier is only really needed if we return true.  It | 
|---|
| 52 | // prevents code conditioned on the result of unique() from running | 
|---|
| 53 | // until previous owners are all totally done calling unref(). | 
|---|
| 54 | return true; | 
|---|
| 55 | } | 
|---|
| 56 | return false; | 
|---|
| 57 | } | 
|---|
| 58 |  | 
|---|
| 59 | /** Increment the reference count. Must be balanced by a call to unref(). | 
|---|
| 60 | */ | 
|---|
| 61 | void ref() const { | 
|---|
| 62 | SkASSERT(this->getRefCnt() > 0); | 
|---|
| 63 | // No barrier required. | 
|---|
| 64 | (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); | 
|---|
| 65 | } | 
|---|
| 66 |  | 
|---|
| 67 | /** Decrement the reference count. If the reference count is 1 before the | 
|---|
| 68 | 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. | 
|---|
| 70 | */ | 
|---|
| 71 | void unref() const { | 
|---|
| 72 | SkASSERT(this->getRefCnt() > 0); | 
|---|
| 73 | // A release here acts in place of all releases we "should" have been doing in ref(). | 
|---|
| 74 | if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { | 
|---|
| 75 | // Like unique(), the acquire is only needed on success, to make sure | 
|---|
| 76 | // code in internal_dispose() doesn't happen before the decrement. | 
|---|
| 77 | this->internal_dispose(); | 
|---|
| 78 | } | 
|---|
| 79 | } | 
|---|
| 80 |  | 
|---|
| 81 | private: | 
|---|
| 82 |  | 
|---|
| 83 | #ifdef SK_DEBUG | 
|---|
| 84 | /** Return the reference count. Use only for debugging. */ | 
|---|
| 85 | int32_t getRefCnt() const { | 
|---|
| 86 | return fRefCnt.load(std::memory_order_relaxed); | 
|---|
| 87 | } | 
|---|
| 88 | #endif | 
|---|
| 89 |  | 
|---|
| 90 | /** | 
|---|
| 91 | *  Called when the ref count goes to 0. | 
|---|
| 92 | */ | 
|---|
| 93 | virtual void internal_dispose() const { | 
|---|
| 94 | #ifdef SK_DEBUG | 
|---|
| 95 | SkASSERT(0 == this->getRefCnt()); | 
|---|
| 96 | fRefCnt.store(1, std::memory_order_relaxed); | 
|---|
| 97 | #endif | 
|---|
| 98 | delete this; | 
|---|
| 99 | } | 
|---|
| 100 |  | 
|---|
| 101 | // The following friends are those which override internal_dispose() | 
|---|
| 102 | // and conditionally call SkRefCnt::internal_dispose(). | 
|---|
| 103 | friend class SkWeakRefCnt; | 
|---|
| 104 |  | 
|---|
| 105 | mutable std::atomic<int32_t> fRefCnt; | 
|---|
| 106 |  | 
|---|
| 107 | SkRefCntBase(SkRefCntBase&&) = delete; | 
|---|
| 108 | SkRefCntBase(const SkRefCntBase&) = delete; | 
|---|
| 109 | SkRefCntBase& operator=(SkRefCntBase&&) = delete; | 
|---|
| 110 | SkRefCntBase& operator=(const SkRefCntBase&) = delete; | 
|---|
| 111 | }; | 
|---|
| 112 |  | 
|---|
| 113 | #ifdef SK_REF_CNT_MIXIN_INCLUDE | 
|---|
| 114 | // It is the responsibility of the following include to define the type SkRefCnt. | 
|---|
| 115 | // This SkRefCnt should normally derive from SkRefCntBase. | 
|---|
| 116 | #include SK_REF_CNT_MIXIN_INCLUDE | 
|---|
| 117 | #else | 
|---|
| 118 | class SK_API SkRefCnt : public SkRefCntBase { | 
|---|
| 119 | // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system. | 
|---|
| 120 | #if defined(SK_BUILD_FOR_GOOGLE3) | 
|---|
| 121 | public: | 
|---|
| 122 | void deref() const { this->unref(); } | 
|---|
| 123 | #endif | 
|---|
| 124 | }; | 
|---|
| 125 | #endif | 
|---|
| 126 |  | 
|---|
| 127 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 128 |  | 
|---|
| 129 | /** Call obj->ref() and return obj. The obj must not be nullptr. | 
|---|
| 130 | */ | 
|---|
| 131 | template <typename T> static inline T* SkRef(T* obj) { | 
|---|
| 132 | SkASSERT(obj); | 
|---|
| 133 | obj->ref(); | 
|---|
| 134 | return obj; | 
|---|
| 135 | } | 
|---|
| 136 |  | 
|---|
| 137 | /** Check if the argument is non-null, and if so, call obj->ref() and return obj. | 
|---|
| 138 | */ | 
|---|
| 139 | template <typename T> static inline T* SkSafeRef(T* obj) { | 
|---|
| 140 | if (obj) { | 
|---|
| 141 | obj->ref(); | 
|---|
| 142 | } | 
|---|
| 143 | return obj; | 
|---|
| 144 | } | 
|---|
| 145 |  | 
|---|
| 146 | /** Check if the argument is non-null, and if so, call obj->unref() | 
|---|
| 147 | */ | 
|---|
| 148 | template <typename T> static inline void SkSafeUnref(T* obj) { | 
|---|
| 149 | if (obj) { | 
|---|
| 150 | obj->unref(); | 
|---|
| 151 | } | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| 155 |  | 
|---|
| 156 | // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16. | 
|---|
| 157 | // There's only benefit to using this if the deriving class does not otherwise need a vtable. | 
|---|
| 158 | template <typename Derived> | 
|---|
| 159 | class SkNVRefCnt { | 
|---|
| 160 | public: | 
|---|
| 161 | SkNVRefCnt() : fRefCnt(1) {} | 
|---|
| 162 | ~SkNVRefCnt() { | 
|---|
| 163 | #ifdef SK_DEBUG | 
|---|
| 164 | int rc = fRefCnt.load(std::memory_order_relaxed); | 
|---|
| 165 | SkASSERTF(rc == 1, "NVRefCnt was %d", rc); | 
|---|
| 166 | #endif | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same: | 
|---|
| 170 | //   - unique() needs acquire when it returns true, and no barrier if it returns false; | 
|---|
| 171 | //   - ref() doesn't need any barrier; | 
|---|
| 172 | //   - unref() needs a release barrier, and an acquire if it's going to call delete. | 
|---|
| 173 |  | 
|---|
| 174 | bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); } | 
|---|
| 175 | void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } | 
|---|
| 176 | void  unref() const { | 
|---|
| 177 | if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { | 
|---|
| 178 | // restore the 1 for our destructor's assert | 
|---|
| 179 | SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed)); | 
|---|
| 180 | delete (const Derived*)this; | 
|---|
| 181 | } | 
|---|
| 182 | } | 
|---|
| 183 | void  deref() const { this->unref(); } | 
|---|
| 184 |  | 
|---|
| 185 | // This must be used with caution. It is only valid to call this when 'threadIsolatedTestCnt' | 
|---|
| 186 | // refs are known to be isolated to the current thread. That is, it is known that there are at | 
|---|
| 187 | // least 'threadIsolatedTestCnt' refs for which no other thread may make a balancing unref() | 
|---|
| 188 | // call. Assuming the contract is followed, if this returns false then no other thread has | 
|---|
| 189 | // ownership of this. If it returns true then another thread *may* have ownership. | 
|---|
| 190 | bool refCntGreaterThan(int32_t threadIsolatedTestCnt) const { | 
|---|
| 191 | int cnt = fRefCnt.load(std::memory_order_acquire); | 
|---|
| 192 | // If this fails then the above contract has been violated. | 
|---|
| 193 | SkASSERT(cnt >= threadIsolatedTestCnt); | 
|---|
| 194 | return cnt > threadIsolatedTestCnt; | 
|---|
| 195 | } | 
|---|
| 196 |  | 
|---|
| 197 | private: | 
|---|
| 198 | mutable std::atomic<int32_t> fRefCnt; | 
|---|
| 199 |  | 
|---|
| 200 | SkNVRefCnt(SkNVRefCnt&&) = delete; | 
|---|
| 201 | SkNVRefCnt(const SkNVRefCnt&) = delete; | 
|---|
| 202 | SkNVRefCnt& operator=(SkNVRefCnt&&) = delete; | 
|---|
| 203 | SkNVRefCnt& operator=(const SkNVRefCnt&) = delete; | 
|---|
| 204 | }; | 
|---|
| 205 |  | 
|---|
| 206 | /////////////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| 207 |  | 
|---|
| 208 | /** | 
|---|
| 209 | *  Shared pointer class to wrap classes that support a ref()/unref() interface. | 
|---|
| 210 | * | 
|---|
| 211 | *  This can be used for classes inheriting from SkRefCnt, but it also works for other | 
|---|
| 212 | *  classes that match the interface, but have different internal choices: e.g. the hosted class | 
|---|
| 213 | *  may have its ref/unref be thread-safe, but that is not assumed/imposed by sk_sp. | 
|---|
| 214 | */ | 
|---|
| 215 | template <typename T> class sk_sp { | 
|---|
| 216 | public: | 
|---|
| 217 | using element_type = T; | 
|---|
| 218 |  | 
|---|
| 219 | constexpr sk_sp() : fPtr(nullptr) {} | 
|---|
| 220 | constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {} | 
|---|
| 221 |  | 
|---|
| 222 | /** | 
|---|
| 223 | *  Shares the underlying object by calling ref(), so that both the argument and the newly | 
|---|
| 224 | *  created sk_sp both have a reference to it. | 
|---|
| 225 | */ | 
|---|
| 226 | sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {} | 
|---|
| 227 | template <typename U, | 
|---|
| 228 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | 
|---|
| 229 | sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {} | 
|---|
| 230 |  | 
|---|
| 231 | /** | 
|---|
| 232 | *  Move the underlying object from the argument to the newly created sk_sp. Afterwards only | 
|---|
| 233 | *  the new sk_sp will have a reference to the object, and the argument will point to null. | 
|---|
| 234 | *  No call to ref() or unref() will be made. | 
|---|
| 235 | */ | 
|---|
| 236 | sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {} | 
|---|
| 237 | template <typename U, | 
|---|
| 238 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | 
|---|
| 239 | sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {} | 
|---|
| 240 |  | 
|---|
| 241 | /** | 
|---|
| 242 | *  Adopt the bare pointer into the newly created sk_sp. | 
|---|
| 243 | *  No call to ref() or unref() will be made. | 
|---|
| 244 | */ | 
|---|
| 245 | explicit sk_sp(T* obj) : fPtr(obj) {} | 
|---|
| 246 |  | 
|---|
| 247 | /** | 
|---|
| 248 | *  Calls unref() on the underlying object pointer. | 
|---|
| 249 | */ | 
|---|
| 250 | ~sk_sp() { | 
|---|
| 251 | SkSafeUnref(fPtr); | 
|---|
| 252 | SkDEBUGCODE(fPtr = nullptr); | 
|---|
| 253 | } | 
|---|
| 254 |  | 
|---|
| 255 | sk_sp<T>& operator=(std::nullptr_t) { this->reset(); return *this; } | 
|---|
| 256 |  | 
|---|
| 257 | /** | 
|---|
| 258 | *  Shares the underlying object referenced by the argument by calling ref() on it. If this | 
|---|
| 259 | *  sk_sp previously had a reference to an object (i.e. not null) it will call unref() on that | 
|---|
| 260 | *  object. | 
|---|
| 261 | */ | 
|---|
| 262 | sk_sp<T>& operator=(const sk_sp<T>& that) { | 
|---|
| 263 | if (this != &that) { | 
|---|
| 264 | this->reset(SkSafeRef(that.get())); | 
|---|
| 265 | } | 
|---|
| 266 | return *this; | 
|---|
| 267 | } | 
|---|
| 268 | template <typename U, | 
|---|
| 269 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | 
|---|
| 270 | sk_sp<T>& operator=(const sk_sp<U>& that) { | 
|---|
| 271 | this->reset(SkSafeRef(that.get())); | 
|---|
| 272 | return *this; | 
|---|
| 273 | } | 
|---|
| 274 |  | 
|---|
| 275 | /** | 
|---|
| 276 | *  Move the underlying object from the argument to the sk_sp. If the sk_sp previously held | 
|---|
| 277 | *  a reference to another object, unref() will be called on that object. No call to ref() | 
|---|
| 278 | *  will be made. | 
|---|
| 279 | */ | 
|---|
| 280 | sk_sp<T>& operator=(sk_sp<T>&& that) { | 
|---|
| 281 | this->reset(that.release()); | 
|---|
| 282 | return *this; | 
|---|
| 283 | } | 
|---|
| 284 | template <typename U, | 
|---|
| 285 | typename = typename std::enable_if<std::is_convertible<U*, T*>::value>::type> | 
|---|
| 286 | sk_sp<T>& operator=(sk_sp<U>&& that) { | 
|---|
| 287 | this->reset(that.release()); | 
|---|
| 288 | return *this; | 
|---|
| 289 | } | 
|---|
| 290 |  | 
|---|
| 291 | T& operator*() const { | 
|---|
| 292 | SkASSERT(this->get() != nullptr); | 
|---|
| 293 | return *this->get(); | 
|---|
| 294 | } | 
|---|
| 295 |  | 
|---|
| 296 | explicit operator bool() const { return this->get() != nullptr; } | 
|---|
| 297 |  | 
|---|
| 298 | T* get() const { return fPtr; } | 
|---|
| 299 | T* operator->() const { return fPtr; } | 
|---|
| 300 |  | 
|---|
| 301 | /** | 
|---|
| 302 | *  Adopt the new bare pointer, and call unref() on any previously held object (if not null). | 
|---|
| 303 | *  No call to ref() will be made. | 
|---|
| 304 | */ | 
|---|
| 305 | void reset(T* ptr = nullptr) { | 
|---|
| 306 | // Calling fPtr->unref() may call this->~() or this->reset(T*). | 
|---|
| 307 | // http://wg21.cmeerw.net/lwg/issue998 | 
|---|
| 308 | // http://wg21.cmeerw.net/lwg/issue2262 | 
|---|
| 309 | T* oldPtr = fPtr; | 
|---|
| 310 | fPtr = ptr; | 
|---|
| 311 | SkSafeUnref(oldPtr); | 
|---|
| 312 | } | 
|---|
| 313 |  | 
|---|
| 314 | /** | 
|---|
| 315 | *  Return the bare pointer, and set the internal object pointer to nullptr. | 
|---|
| 316 | *  The caller must assume ownership of the object, and manage its reference count directly. | 
|---|
| 317 | *  No call to unref() will be made. | 
|---|
| 318 | */ | 
|---|
| 319 | T* SK_WARN_UNUSED_RESULT release() { | 
|---|
| 320 | T* ptr = fPtr; | 
|---|
| 321 | fPtr = nullptr; | 
|---|
| 322 | return ptr; | 
|---|
| 323 | } | 
|---|
| 324 |  | 
|---|
| 325 | void swap(sk_sp<T>& that) /*noexcept*/ { | 
|---|
| 326 | using std::swap; | 
|---|
| 327 | swap(fPtr, that.fPtr); | 
|---|
| 328 | } | 
|---|
| 329 |  | 
|---|
| 330 | private: | 
|---|
| 331 | T*  fPtr; | 
|---|
| 332 | }; | 
|---|
| 333 |  | 
|---|
| 334 | template <typename T> inline void swap(sk_sp<T>& a, sk_sp<T>& b) /*noexcept*/ { | 
|---|
| 335 | a.swap(b); | 
|---|
| 336 | } | 
|---|
| 337 |  | 
|---|
| 338 | template <typename T, typename U> inline bool operator==(const sk_sp<T>& a, const sk_sp<U>& b) { | 
|---|
| 339 | return a.get() == b.get(); | 
|---|
| 340 | } | 
|---|
| 341 | template <typename T> inline bool operator==(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ { | 
|---|
| 342 | return !a; | 
|---|
| 343 | } | 
|---|
| 344 | template <typename T> inline bool operator==(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ { | 
|---|
| 345 | return !b; | 
|---|
| 346 | } | 
|---|
| 347 |  | 
|---|
| 348 | template <typename T, typename U> inline bool operator!=(const sk_sp<T>& a, const sk_sp<U>& b) { | 
|---|
| 349 | return a.get() != b.get(); | 
|---|
| 350 | } | 
|---|
| 351 | template <typename T> inline bool operator!=(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ { | 
|---|
| 352 | return static_cast<bool>(a); | 
|---|
| 353 | } | 
|---|
| 354 | template <typename T> inline bool operator!=(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ { | 
|---|
| 355 | return static_cast<bool>(b); | 
|---|
| 356 | } | 
|---|
| 357 |  | 
|---|
| 358 | template <typename C, typename CT, typename T> | 
|---|
| 359 | auto operator<<(std::basic_ostream<C, CT>& os, const sk_sp<T>& sp) -> decltype(os << sp.get()) { | 
|---|
| 360 | return os << sp.get(); | 
|---|
| 361 | } | 
|---|
| 362 |  | 
|---|
| 363 | template <typename T, typename... Args> | 
|---|
| 364 | sk_sp<T> sk_make_sp(Args&&... args) { | 
|---|
| 365 | return sk_sp<T>(new T(std::forward<Args>(args)...)); | 
|---|
| 366 | } | 
|---|
| 367 |  | 
|---|
| 368 | /* | 
|---|
| 369 | *  Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null). | 
|---|
| 370 | * | 
|---|
| 371 | *  This is different than the semantics of the constructor for sk_sp, which just wraps the ptr, | 
|---|
| 372 | *  effectively "adopting" it. | 
|---|
| 373 | */ | 
|---|
| 374 | template <typename T> sk_sp<T> sk_ref_sp(T* obj) { | 
|---|
| 375 | return sk_sp<T>(SkSafeRef(obj)); | 
|---|
| 376 | } | 
|---|
| 377 |  | 
|---|
| 378 | template <typename T> sk_sp<T> sk_ref_sp(const T* obj) { | 
|---|
| 379 | return sk_sp<T>(const_cast<T*>(SkSafeRef(obj))); | 
|---|
| 380 | } | 
|---|
| 381 |  | 
|---|
| 382 | #endif | 
|---|
| 383 |  | 
|---|