Skia
2DGraphicsLibrary
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SkRefCnt.h
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 "../private/SkTLogic.h"
12 #include "SkTypes.h"
13 #include <atomic>
14 #include <functional>
15 #include <memory>
16 #include <type_traits>
17 #include <utility>
18 
29 class SK_API SkRefCntBase : SkNoncopyable {
30 public:
33  SkRefCntBase() : fRefCnt(1) {}
34 
37  virtual ~SkRefCntBase() {
38 #ifdef SK_DEBUG
39  SkASSERTF(getRefCnt() == 1, "fRefCnt was %d", getRefCnt());
40  // illegal value, to catch us if we reuse after delete
41  fRefCnt.store(0, std::memory_order_relaxed);
42 #endif
43  }
44 
45 #ifdef SK_DEBUG
46 
47  int32_t getRefCnt() const {
48  return fRefCnt.load(std::memory_order_relaxed);
49  }
50 
51  void validate() const {
52  SkASSERT(getRefCnt() > 0);
53  }
54 #endif
55 
59  bool unique() const {
60  if (1 == fRefCnt.load(std::memory_order_acquire)) {
61  // The acquire barrier is only really needed if we return true. It
62  // prevents code conditioned on the result of unique() from running
63  // until previous owners are all totally done calling unref().
64  return true;
65  }
66  return false;
67  }
68 
71  void ref() const {
72  SkASSERT(getRefCnt() > 0);
73  // No barrier required.
74  (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed);
75  }
76 
81  void unref() const {
82  SkASSERT(getRefCnt() > 0);
83  // A release here acts in place of all releases we "should" have been doing in ref().
84  if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
85  // Like unique(), the acquire is only needed on success, to make sure
86  // code in internal_dispose() doesn't happen before the decrement.
87  this->internal_dispose();
88  }
89  }
90 
91 protected:
98  SkASSERT(0 == getRefCnt());
99  fRefCnt.store(1, std::memory_order_relaxed);
100  }
101 
102 private:
106  virtual void internal_dispose() const {
107  this->internal_dispose_restore_refcnt_to_1();
108  delete this;
109  }
110 
111  // The following friends are those which override internal_dispose()
112  // and conditionally call SkRefCnt::internal_dispose().
113  friend class SkWeakRefCnt;
114 
115  mutable std::atomic<int32_t> fRefCnt;
116 
117  typedef SkNoncopyable INHERITED;
118 };
119 
120 #ifdef SK_REF_CNT_MIXIN_INCLUDE
121 // It is the responsibility of the following include to define the type SkRefCnt.
122 // This SkRefCnt should normally derive from SkRefCntBase.
123 #include SK_REF_CNT_MIXIN_INCLUDE
124 #else
125 class SK_API SkRefCnt : public SkRefCntBase {
126  // "#include SK_REF_CNT_MIXIN_INCLUDE" doesn't work with this build system.
127  #if defined(GOOGLE3)
128  public:
129  void deref() const { this->unref(); }
130  #endif
131 };
132 #endif
133 
135 
141 #if defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
142 // This version heuristically detects data races, since those otherwise result
143 // in redundant reference count decrements, which are exceedingly
144 // difficult to debug.
145 
146 #define SkRefCnt_SafeAssign(dst, src) \
147  do { \
148  typedef typename std::remove_reference<decltype(dst)>::type \
149  SkRefCntPtrT; \
150  SkRefCntPtrT old_dst = *const_cast<SkRefCntPtrT volatile *>(&dst); \
151  if (src) src->ref(); \
152  if (old_dst) old_dst->unref(); \
153  if (old_dst != *const_cast<SkRefCntPtrT volatile *>(&dst)) { \
154  SkDebugf("Detected racing Skia calls at %s:%d\n", \
155  __FILE__, __LINE__); \
156  } \
157  dst = src; \
158  } while (0)
159 
160 #else /* !SK_BUILD_FOR_ANDROID_FRAMEWORK */
161 
162 #define SkRefCnt_SafeAssign(dst, src) \
163  do { \
164  if (src) src->ref(); \
165  if (dst) dst->unref(); \
166  dst = src; \
167  } while (0)
168 
169 #endif
170 
171 
174 template <typename T> static inline T* SkRef(T* obj) {
175  SkASSERT(obj);
176  obj->ref();
177  return obj;
178 }
179 
182 template <typename T> static inline T* SkSafeRef(T* obj) {
183  if (obj) {
184  obj->ref();
185  }
186  return obj;
187 }
188 
191 template <typename T> static inline void SkSafeUnref(T* obj) {
192  if (obj) {
193  obj->unref();
194  }
195 }
196 
197 template<typename T> static inline void SkSafeSetNull(T*& obj) {
198  if (obj) {
199  obj->unref();
200  obj = nullptr;
201  }
202 }
203 
205 
206 // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead of 8 or 16.
207 // There's only benefit to using this if the deriving class does not otherwise need a vtable.
208 template <typename Derived>
209 class SkNVRefCnt : SkNoncopyable {
210 public:
211  SkNVRefCnt() : fRefCnt(1) {}
212  ~SkNVRefCnt() { SkASSERTF(1 == getRefCnt(), "NVRefCnt was %d", getRefCnt()); }
213 
214  // Implementation is pretty much the same as SkRefCntBase. All required barriers are the same:
215  // - unique() needs acquire when it returns true, and no barrier if it returns false;
216  // - ref() doesn't need any barrier;
217  // - unref() needs a release barrier, and an acquire if it's going to call delete.
218 
219  bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); }
220  void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); }
221  void unref() const {
222  if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) {
223  // restore the 1 for our destructor's assert
224  SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed));
225  delete (const Derived*)this;
226  }
227  }
228  void deref() const { this->unref(); }
229 
230 private:
231  mutable std::atomic<int32_t> fRefCnt;
232  int32_t getRefCnt() const {
233  return fRefCnt.load(std::memory_order_relaxed);
234  }
235 };
236 
238 
246 template <typename T> class sk_sp {
249 public:
250  using element_type = T;
251 
252  constexpr sk_sp() : fPtr(nullptr) {}
253  constexpr sk_sp(std::nullptr_t) : fPtr(nullptr) {}
254 
259  sk_sp(const sk_sp<T>& that) : fPtr(SkSafeRef(that.get())) {}
260  template <typename U, typename = skstd::enable_if_t<std::is_convertible<U*, T*>::value>>
261  sk_sp(const sk_sp<U>& that) : fPtr(SkSafeRef(that.get())) {}
262 
268  sk_sp(sk_sp<T>&& that) : fPtr(that.release()) {}
269  template <typename U, typename = skstd::enable_if_t<std::is_convertible<U*, T*>::value>>
270  sk_sp(sk_sp<U>&& that) : fPtr(that.release()) {}
271 
276  explicit sk_sp(T* obj) : fPtr(obj) {}
277 
281  ~sk_sp() {
282  SkSafeUnref(fPtr);
283  SkDEBUGCODE(fPtr = nullptr);
284  }
285 
286  sk_sp<T>& operator=(std::nullptr_t) { this->reset(); return *this; }
287 
293  sk_sp<T>& operator=(const sk_sp<T>& that) {
294  this->reset(SkSafeRef(that.get()));
295  return *this;
296  }
297  template <typename U, typename = skstd::enable_if_t<std::is_convertible<U*, T*>::value>>
298  sk_sp<T>& operator=(const sk_sp<U>& that) {
299  this->reset(SkSafeRef(that.get()));
300  return *this;
301  }
302 
309  this->reset(that.release());
310  return *this;
311  }
312  template <typename U, typename = skstd::enable_if_t<std::is_convertible<U*, T*>::value>>
313  sk_sp<T>& operator=(sk_sp<U>&& that) {
314  this->reset(that.release());
315  return *this;
316  }
317 
318  T& operator*() const {
319  SkASSERT(this->get() != nullptr);
320  return *this->get();
321  }
322 
323  // MSVC 2013 does not work correctly with explicit operator bool.
324  // https://chromium-cpp.appspot.com/#core-blacklist
325  // When explicit operator bool can be used, remove operator! and operator unspecified_bool_type.
326  //explicit operator bool() const { return this->get() != nullptr; }
327  operator unspecified_bool_type() const { return this->get() ? &sk_sp::fPtr : nullptr; }
328  bool operator!() const { return this->get() == nullptr; }
329 
330  T* get() const { return fPtr; }
331  T* operator->() const { return fPtr; }
332 
337  void reset(T* ptr = nullptr) {
338  // Calling fPtr->unref() may call this->~() or this->reset(T*).
339  // http://wg21.cmeerw.net/lwg/issue998
340  // http://wg21.cmeerw.net/lwg/issue2262
341  T* oldPtr = fPtr;
342  fPtr = ptr;
343  SkSafeUnref(oldPtr);
344  }
345 
351  T* SK_WARN_UNUSED_RESULT release() {
352  T* ptr = fPtr;
353  fPtr = nullptr;
354  return ptr;
355  }
356 
357  void swap(sk_sp<T>& that) /*noexcept*/ {
358  using std::swap;
359  swap(fPtr, that.fPtr);
360  }
361 
362 private:
363  T* fPtr;
364 };
365 
366 template <typename T> inline void swap(sk_sp<T>& a, sk_sp<T>& b) /*noexcept*/ {
367  a.swap(b);
368 }
369 
370 template <typename T, typename U> inline bool operator==(const sk_sp<T>& a, const sk_sp<U>& b) {
371  return a.get() == b.get();
372 }
373 template <typename T> inline bool operator==(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ {
374  return !a;
375 }
376 template <typename T> inline bool operator==(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ {
377  return !b;
378 }
379 
380 template <typename T, typename U> inline bool operator!=(const sk_sp<T>& a, const sk_sp<U>& b) {
381  return a.get() != b.get();
382 }
383 template <typename T> inline bool operator!=(const sk_sp<T>& a, std::nullptr_t) /*noexcept*/ {
384  return static_cast<bool>(a);
385 }
386 template <typename T> inline bool operator!=(std::nullptr_t, const sk_sp<T>& b) /*noexcept*/ {
387  return static_cast<bool>(b);
388 }
389 
390 template <typename T, typename U> inline bool operator<(const sk_sp<T>& a, const sk_sp<U>& b) {
391  // Provide defined total order on sk_sp.
392  // http://wg21.cmeerw.net/lwg/issue1297
393  // http://wg21.cmeerw.net/lwg/issue1401 .
394  return std::less<skstd::common_type_t<T*, U*>>()(a.get(), b.get());
395 }
396 template <typename T> inline bool operator<(const sk_sp<T>& a, std::nullptr_t) {
397  return std::less<T*>()(a.get(), nullptr);
398 }
399 template <typename T> inline bool operator<(std::nullptr_t, const sk_sp<T>& b) {
400  return std::less<T*>()(nullptr, b.get());
401 }
402 
403 template <typename T, typename U> inline bool operator<=(const sk_sp<T>& a, const sk_sp<U>& b) {
404  return !(b < a);
405 }
406 template <typename T> inline bool operator<=(const sk_sp<T>& a, std::nullptr_t) {
407  return !(nullptr < a);
408 }
409 template <typename T> inline bool operator<=(std::nullptr_t, const sk_sp<T>& b) {
410  return !(b < nullptr);
411 }
412 
413 template <typename T, typename U> inline bool operator>(const sk_sp<T>& a, const sk_sp<U>& b) {
414  return b < a;
415 }
416 template <typename T> inline bool operator>(const sk_sp<T>& a, std::nullptr_t) {
417  return nullptr < a;
418 }
419 template <typename T> inline bool operator>(std::nullptr_t, const sk_sp<T>& b) {
420  return b < nullptr;
421 }
422 
423 template <typename T, typename U> inline bool operator>=(const sk_sp<T>& a, const sk_sp<U>& b) {
424  return !(a < b);
425 }
426 template <typename T> inline bool operator>=(const sk_sp<T>& a, std::nullptr_t) {
427  return !(a < nullptr);
428 }
429 template <typename T> inline bool operator>=(std::nullptr_t, const sk_sp<T>& b) {
430  return !(nullptr < b);
431 }
432 
433 template <typename T, typename... Args>
434 sk_sp<T> sk_make_sp(Args&&... args) {
435  return sk_sp<T>(new T(std::forward<Args>(args)...));
436 }
437 
438 /*
439  * Returns a sk_sp wrapping the provided ptr AND calls ref on it (if not null).
440  *
441  * This is different than the semantics of the constructor for sk_sp, which just wraps the ptr,
442  * effectively "adopting" it.
443  */
444 template <typename T> sk_sp<T> sk_ref_sp(T* obj) {
445  return sk_sp<T>(SkSafeRef(obj));
446 }
447 
448 #endif
T *SK_WARN_UNUSED_RESULT release()
Return the bare pointer, and set the internal object pointer to nullptr.
Definition: SkRefCnt.h:351
void reset(T *ptr=nullptr)
Adopt the new bare pointer, and call unref() on any previously held object (if not null)...
Definition: SkRefCnt.h:337
sk_sp(T *obj)
Adopt the bare pointer into the newly created sk_sp.
Definition: SkRefCnt.h:276
void internal_dispose_restore_refcnt_to_1() const
Allow subclasses to call this if they've overridden internal_dispose so they can reset fRefCnt before...
Definition: SkRefCnt.h:97
int32_t getRefCnt() const
Return the reference count.
Definition: SkRefCnt.h:47
Definition: SkRefCnt.h:125
sk_sp< T > & operator=(sk_sp< T > &&that)
Move the underlying object from the argument to the sk_sp.
Definition: SkRefCnt.h:308
void unref() const
Decrement the reference count.
Definition: SkRefCnt.h:81
bool unique() const
May return true if the caller is the only owner.
Definition: SkRefCnt.h:59
void ref() const
Increment the reference count.
Definition: SkRefCnt.h:71
sk_sp(sk_sp< T > &&that)
Move the underlying object from the argument to the newly created sk_sp.
Definition: SkRefCnt.h:268
Shared pointer class to wrap classes that support a ref()/unref() interface.
Definition: SkRefCnt.h:246
Definition: GrShaderCaps.h:20
GrShaderCaps *sk_sp::* unspecified_bool_type
Supports safe bool idiom.
Definition: SkRefCnt.h:248
SkRefCntBase()
Default construct, initializing the reference count to 1.
Definition: SkRefCnt.h:33
sk_sp(const sk_sp< T > &that)
Shares the underlying object by calling ref(), so that both the argument and the newly created sk_sp ...
Definition: SkRefCnt.h:259
virtual void internal_dispose() const
Called when the ref count goes to 0.
Definition: SkRefCnt.h:106
virtual ~SkRefCntBase()
Destruct, asserting that the reference count is 1.
Definition: SkRefCnt.h:37
~sk_sp()
Calls unref() on the underlying object pointer.
Definition: SkRefCnt.h:281
SkRefCntBase is the base class for objects that may be shared by multiple objects.
Definition: SkRefCnt.h:29
Definition: SkRefCnt.h:209
sk_sp< T > & operator=(const sk_sp< T > &that)
Shares the underlying object referenced by the argument by calling ref() on it.
Definition: SkRefCnt.h:293