Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef SKIA_EXT_REFPTR_H_ | 5 #ifndef SKIA_EXT_REFPTR_H_ |
| 6 #define SKIA_EXT_REFPTR_H_ | 6 #define SKIA_EXT_REFPTR_H_ |
| 7 | 7 |
| 8 #include "base/basictypes.h" | |
| 8 #include "third_party/skia/include/core/SkRefCnt.h" | 9 #include "third_party/skia/include/core/SkRefCnt.h" |
| 9 | 10 |
| 10 namespace skia { | 11 namespace skia { |
| 11 | 12 |
| 12 // When creating/receiving a ref-counted pointer from Skia, wrap that pointer in | 13 // When creating/receiving a ref-counted pointer from Skia, wrap that pointer in |
| 13 // this class to avoid dealing with the ref-counting and prevent leaks/crashes | 14 // this class to avoid dealing with the ref-counting and prevent leaks/crashes |
| 14 // due to ref-counting bugs. | 15 // due to ref-counting bugs. |
| 15 // | 16 // |
| 16 // Example of creating a new SkShader* and setting it on a SkPaint: | 17 // Example of creating a new SkShader* and setting it on a SkPaint: |
| 17 // skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::Create()); | 18 // skia::RefPtr<SkShader> shader = skia::AdoptRef(SkGradientShader::Create()); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 37 // | 38 // |
| 38 // skia::RefPtr<SkShader> shader = skia::SharePtr(paint.getShader()); | 39 // skia::RefPtr<SkShader> shader = skia::SharePtr(paint.getShader()); |
| 39 // | 40 // |
| 40 // Never call ref() or unref() on the underlying ref-counted pointer. If you | 41 // Never call ref() or unref() on the underlying ref-counted pointer. If you |
| 41 // AdoptRef() the raw pointer immediately into a skia::RefPtr and always work | 42 // AdoptRef() the raw pointer immediately into a skia::RefPtr and always work |
| 42 // with skia::RefPtr instances instead, the ref-counting will be taken care of | 43 // with skia::RefPtr instances instead, the ref-counting will be taken care of |
| 43 // for you. | 44 // for you. |
| 44 template<typename T> | 45 template<typename T> |
| 45 class RefPtr { | 46 class RefPtr { |
| 46 public: | 47 public: |
| 47 RefPtr() : ptr_(NULL) {} | 48 RefPtr() : ptr_(NULL) { |
| 49 #ifndef NDEBUG | |
| 50 inside_receive_and_adopt_ref_ = false; | |
| 51 #endif | |
| 52 } | |
| 48 | 53 |
| 49 RefPtr(const RefPtr& other) | 54 RefPtr(const RefPtr& other) |
| 50 : ptr_(other.get()) { | 55 : ptr_(other.get()) { |
| 51 SkSafeRef(ptr_); | 56 SkSafeRef(ptr_); |
| 57 #ifndef NDEBUG | |
| 58 inside_receive_and_adopt_ref_ = false; | |
| 59 #endif | |
| 52 } | 60 } |
| 53 | 61 |
| 54 template<typename U> | 62 template<typename U> |
| 55 RefPtr(const RefPtr<U>& other) | 63 RefPtr(const RefPtr<U>& other) |
| 56 : ptr_(other.get()) { | 64 : ptr_(other.get()) { |
| 57 SkSafeRef(ptr_); | 65 SkSafeRef(ptr_); |
| 66 #ifndef NDEBUG | |
| 67 inside_receive_and_adopt_ref_ = false; | |
| 68 #endif | |
| 58 } | 69 } |
| 59 | 70 |
| 60 ~RefPtr() { | 71 ~RefPtr() { |
| 72 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 61 clear(); | 73 clear(); |
| 62 } | 74 } |
| 63 | 75 |
| 64 RefPtr& operator=(const RefPtr& other) { | 76 RefPtr& operator=(const RefPtr& other) { |
| 77 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 65 SkRefCnt_SafeAssign(ptr_, other.get()); | 78 SkRefCnt_SafeAssign(ptr_, other.get()); |
| 66 return *this; | 79 return *this; |
| 67 } | 80 } |
| 68 | 81 |
| 69 template<typename U> | 82 template<typename U> |
| 70 RefPtr& operator=(const RefPtr<U>& other) { | 83 RefPtr& operator=(const RefPtr<U>& other) { |
| 84 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 71 SkRefCnt_SafeAssign(ptr_, other.get()); | 85 SkRefCnt_SafeAssign(ptr_, other.get()); |
| 72 return *this; | 86 return *this; |
| 73 } | 87 } |
| 74 | 88 |
| 75 void clear() { | 89 void clear() { |
| 90 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 76 T* to_unref = ptr_; | 91 T* to_unref = ptr_; |
| 77 ptr_ = NULL; | 92 ptr_ = NULL; |
| 78 SkSafeUnref(to_unref); | 93 SkSafeUnref(to_unref); |
| 79 } | 94 } |
| 80 | 95 |
| 81 T* get() const { return ptr_; } | 96 T* get() const { |
| 82 T& operator*() const { return *ptr_; } | 97 ShouldNotBeInsideReceiveAndAdoptRef(); |
| 83 T* operator->() const { return ptr_; } | 98 return ptr_; |
| 99 } | |
| 100 T& operator*() const { | |
| 101 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 102 return *ptr_; | |
| 103 } | |
| 104 T* operator->() const { | |
| 105 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 106 return ptr_; | |
| 107 } | |
| 84 | 108 |
| 85 typedef T* RefPtr::*unspecified_bool_type; | 109 typedef T* RefPtr::*unspecified_bool_type; |
| 86 operator unspecified_bool_type() const { | 110 operator unspecified_bool_type() const { |
| 111 ShouldNotBeInsideReceiveAndAdoptRef(); | |
| 87 return ptr_ ? &RefPtr::ptr_ : NULL; | 112 return ptr_ ? &RefPtr::ptr_ : NULL; |
| 88 } | 113 } |
| 89 | 114 |
| 115 class Receiver { | |
| 116 public: | |
| 117 ~Receiver() { | |
| 118 refptr_->ShouldBeEmpty(); | |
| 119 refptr_->ptr_ = ptr_; | |
| 120 refptr_->inside_receive_and_adopt_ref_ = false; | |
| 121 } | |
| 122 | |
| 123 operator T**() { return &ptr_; } | |
| 124 | |
| 125 private: | |
| 126 friend class RefPtr; | |
| 127 | |
| 128 explicit Receiver(RefPtr* refptr) : refptr_(refptr), ptr_(NULL) { | |
| 129 refptr_->ShouldBeEmpty(); | |
| 130 } | |
| 131 | |
| 132 RefPtr* refptr_; | |
| 133 T* ptr_; | |
| 134 | |
| 135 DISALLOW_COPY_AND_ASSIGN(Receiver); | |
| 136 }; | |
| 137 | |
| 138 // Call this and pass the returned temporary it to a function taking a T** | |
| 139 // argument. The returned temporary will set the original RefPtr to an object | |
| 140 // with an unowned reference. | |
| 141 // NOTE: Do not use this function as part of a subexpression where the RefPtr | |
| 142 // is also used somewhere else. Destructors of temporaries are only run at the | |
| 143 // end of a full expression so the initialization will not be complete and | |
| 144 // the RefPtr will remain empty. | |
|
Stephen White
2013/07/18 15:50:30
Maybe I'm old-fashioned, but I'm wondering if this
danakj
2013/07/18 15:59:36
My own preference would be to never receive someth
awong
2013/07/18 16:00:42
Yes...I agree but there's precedent (bleck). See
| |
| 145 // | |
| 146 // Bad (refptr will be NULL when it is dereffed): | |
| 147 // Foo(refptr.ReceiveAndAdoptRef()) && refptr->Bar(); | |
| 148 // Good: | |
| 149 // bool ok = Foo(refptr.ReceiveAndAdoptRef()); | |
| 150 // ok && refptr->Bar(); | |
| 151 Receiver ReceiveAndAdoptRef() { | |
| 152 #ifndef NDEBUG | |
| 153 inside_receive_and_adopt_ref_ = true; | |
| 154 #endif | |
| 155 return Receiver(this); | |
| 156 } | |
| 157 | |
| 90 private: | 158 private: |
| 91 T* ptr_; | 159 T* ptr_; |
| 92 | 160 |
| 161 #ifndef NDEBUG | |
| 162 bool inside_receive_and_adopt_ref_; | |
| 163 #endif | |
| 164 | |
| 165 inline int ShouldNotBeInsideReceiveAndAdoptRef() const { | |
| 166 #ifndef NDEBUG | |
| 167 if (inside_receive_and_adopt_ref_) { | |
| 168 // Crash. Can't use DCHECK here because blink includes this file. | |
| 169 volatile int* a = NULL; | |
| 170 return *a; | |
| 171 } | |
| 172 #endif | |
| 173 return 0; | |
| 174 } | |
| 175 | |
| 176 inline int ShouldBeEmpty() const { | |
| 177 #ifndef NDEBUG | |
| 178 if (ptr_ != NULL) { | |
| 179 // Crash. Can't use DCHECK here because blink includes this file. | |
| 180 volatile int* a = NULL; | |
| 181 return *a; | |
| 182 } | |
| 183 #endif | |
| 184 return 0; | |
| 185 } | |
| 186 | |
| 93 // This function cannot be public because Skia starts its ref-counted | 187 // This function cannot be public because Skia starts its ref-counted |
| 94 // objects at refcnt=1. This makes it impossible to differentiate | 188 // objects at refcnt=1. This makes it impossible to differentiate |
| 95 // between a newly created object (that doesn't need to be ref'd) or an | 189 // between a newly created object (that doesn't need to be ref'd) or an |
| 96 // already existing object with one owner (that does need to be ref'd so that | 190 // already existing object with one owner (that does need to be ref'd so that |
| 97 // this RefPtr can also manage its lifetime). | 191 // this RefPtr can also manage its lifetime). |
| 98 explicit RefPtr(T* ptr) : ptr_(ptr) {} | 192 explicit RefPtr(T* ptr) : ptr_(ptr) { |
| 193 #ifndef NDEBUG | |
| 194 inside_receive_and_adopt_ref_ = false; | |
| 195 #endif | |
| 196 } | |
| 99 | 197 |
| 100 template<typename U> | 198 template<typename U> |
| 101 friend RefPtr<U> AdoptRef(U* ptr); | 199 friend RefPtr<U> AdoptRef(U* ptr); |
| 102 | 200 |
| 103 template<typename U> | 201 template<typename U> |
| 104 friend RefPtr<U> SharePtr(U* ptr); | 202 friend RefPtr<U> SharePtr(U* ptr); |
| 105 }; | 203 }; |
| 106 | 204 |
| 107 // For objects that have an unowned reference (such as newly created objects). | 205 // For objects that have an unowned reference (such as newly created objects). |
| 108 template<typename T> | 206 template<typename T> |
| 109 RefPtr<T> AdoptRef(T* ptr) { return RefPtr<T>(ptr); } | 207 RefPtr<T> AdoptRef(T* ptr) { return RefPtr<T>(ptr); } |
| 110 | 208 |
| 111 // For objects that are already owned. This doesn't take ownership of existing | 209 // For objects that are already owned. This doesn't take ownership of existing |
| 112 // references and adds a new one. | 210 // references and adds a new one. |
| 113 template<typename T> | 211 template<typename T> |
| 114 RefPtr<T> SharePtr(T* ptr) { return RefPtr<T>(SkSafeRef(ptr)); } | 212 RefPtr<T> SharePtr(T* ptr) { return RefPtr<T>(SkSafeRef(ptr)); } |
| 115 | 213 |
| 116 } // namespace skia | 214 } // namespace skia |
| 117 | 215 |
| 118 #endif // SKIA_EXT_REFPTR_H_ | 216 #endif // SKIA_EXT_REFPTR_H_ |
| OLD | NEW |