Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef BASE_MEMORY_PASS_SCOPED_PTR_H_ | |
| 6 #define BASE_MEMORY_PASS_SCOPED_PTR_H_ | |
| 7 #pragma once | |
| 8 | |
| 9 #include <stddef.h> | |
| 10 | |
| 11 #include "base/compiler_specific.h" | |
| 12 #include "base/logging.h" | |
| 13 #include "base/memory/scoped_ptr.h" | |
| 14 #include "base/gtest_prod_util.h" | |
| 15 | |
| 16 namespace base { | |
| 17 | |
| 18 // Forward Decls for friending. | |
| 19 template <typename T> class PassScopedPtr; | |
| 20 | |
| 21 namespace subtle { | |
| 22 template <typename T> class PassScopedPtrAnchor; | |
| 23 } // namespace subtle | |
| 24 | |
| 25 namespace internal { | |
| 26 // TODO(ajwong): Refactor the InvokerN specialization method so that we don't | |
| 27 // need 1 friend for each arity. | |
| 28 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 29 struct Invoker1; | |
| 30 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 31 struct Invoker2; | |
| 32 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 33 struct Invoker3; | |
| 34 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 35 struct Invoker4; | |
| 36 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 37 struct Invoker5; | |
| 38 template <typename T> PassScopedPtr<T> Unwrap( | |
| 39 subtle::PassScopedPtrAnchor<T>& o); | |
| 40 } // namespace internal | |
| 41 | |
| 42 namespace subtle { | |
| 43 | |
| 44 // The TransientPassScopedPtr<> is a PassScopedPtr with destructive copy | |
| 45 // semantics. It is meant only to be used as a return type and should never | |
| 46 // show up in signatures. Instead use the PassScopedPtr<>::ReturnType | |
| 47 // typedef. | |
| 48 template <typename T> | |
| 49 class TransientPassScopedPtr { | |
| 50 public: | |
| 51 ~TransientPassScopedPtr() { | |
| 52 delete ptr_; | |
| 53 } | |
| 54 | |
| 55 TransientPassScopedPtr(const TransientPassScopedPtr& o) { | |
| 56 TransientPassScopedPtr& other = const_cast<TransientPassScopedPtr&>(o); | |
| 57 ptr_ = other.ptr_; | |
| 58 other.ptr_ = NULL; | |
| 59 } | |
| 60 | |
| 61 void ToScopedPtr(scoped_ptr<T>* scoped) { | |
| 62 scoped->reset(Release()); | |
| 63 } | |
| 64 | |
| 65 private: | |
| 66 friend class PassScopedPtr<T>; | |
| 67 friend class PassScopedPtrAnchor<T>; | |
| 68 | |
| 69 explicit TransientPassScopedPtr(T* ptr) : ptr_(ptr) {} | |
| 70 | |
| 71 T* Release() { | |
| 72 T* ret_val = ptr_; | |
| 73 ptr_ = NULL; | |
| 74 return ret_val; | |
| 75 } | |
| 76 | |
| 77 T* ptr_; | |
| 78 }; | |
| 79 | |
| 80 // When a PassScopedPtr<> is created based off of the Anchor Type, deleting the | |
| 81 // PassScopedPtr<> will not delete the pointee. This is used in base::Bind() so | |
| 82 // that a Callback<> with a PassScopedPtr<> only gains ownership of the pointee | |
| 83 // if it explicitly calls Pass(). | |
| 84 template <typename T> | |
| 85 class PassScopedPtrAnchor { | |
| 86 public: | |
| 87 PassScopedPtrAnchor(const TransientPassScopedPtr<T>& interstitial) | |
| 88 : is_valid_(true), | |
| 89 interstitial_(interstitial) { | |
| 90 } | |
| 91 | |
| 92 T* Release() { | |
| 93 CHECK(is_valid_) << "Anchor already used."; | |
| 94 is_valid_ = false; | |
| 95 return interstitial_.Release(); | |
| 96 } | |
| 97 | |
| 98 bool is_valid() { return is_valid_; } | |
| 99 | |
| 100 private: | |
| 101 bool is_valid_; | |
| 102 TransientPassScopedPtr<T> interstitial_; | |
| 103 }; | |
| 104 | |
| 105 } // namespace subtle | |
| 106 | |
| 107 // PassScopedPtr is a container class that is targeted specifically at | |
| 108 // transfering ownership across function calls. It should only be used as | |
| 109 // a parameter type. If a function is returning ownership, it should use | |
| 110 // PassScopedPtr<T>::ReturnType. All other situations should prefer | |
| 111 // scoped_ptr. | |
| 112 // | |
| 113 // To help prevent unwanted usage, the public interface of this class is | |
| 114 // intentionally featureless lacking overrides for ->, or easy retrieval to | |
| 115 // the underlying pointer. In particular, only 2 operations are allowed for | |
| 116 // the class: | |
| 117 // | |
| 118 // 1) Calling Pass() to transfer ownership to another PassScopedPtr. | |
| 119 // 2) Calling ToScopedPtr() to transfer ownership to a scoped_ptr. | |
| 120 // | |
| 121 // Each of these methods may only be called once on a PassScopedPtr. A second | |
| 122 // invocation will cause a CHECK(). | |
| 123 // | |
| 124 // This class is not thread safe. If passing across threads, external | |
| 125 // synchronization must be used. One exception is that it is safe to use | |
| 126 // with base::Bind() to pass through threads via a PostTask because the | |
| 127 // PostTask's mutex will enforce the correct synchronization as long as | |
| 128 // that only one thread may invoke Run() on the resulting base::Callback(). | |
| 129 // | |
| 130 // In the case that the resulting base::Callback<> is executed multiple times | |
| 131 // it will be given the same logical PassScopedPtr as the argument. | |
| 132 // Ownership of the underlying pointer is kept with the base::Callback until | |
| 133 // Pass() or ToScopedPtr() is executed during one of these calls. After this, | |
| 134 // ownership is passed, and subsequent calls will get a PassScopedPtr where | |
| 135 // is_valid() returns false. This makes the transfer of ownership _out_ of | |
| 136 // a base::Callback's bound argument explicit. | |
| 137 template <class T> | |
| 138 class PassScopedPtr { | |
|
levin
2011/11/02 00:51:30
It feels like it should be pass_scoped_ptr (since
awong
2011/11/11 00:21:58
Yeah...but then we have WeakPtr<>. scoped_ptr<> i
| |
| 139 public: | |
| 140 explicit PassScopedPtr(T* ptr) | |
| 141 : type_(TYPE_RAW) { | |
| 142 value_.raw_ptr = ptr; | |
| 143 } | |
| 144 | |
| 145 typedef subtle::TransientPassScopedPtr<T> ReturnType; | |
| 146 | |
| 147 PassScopedPtr(const ReturnType& interstitial) | |
| 148 : type_(TYPE_RAW) { | |
| 149 value_.raw_ptr = const_cast<ReturnType&>(interstitial).Release(); | |
| 150 } | |
| 151 | |
| 152 // TODO(ajwong): Make this private and friend InvokerStorage<>. | |
| 153 explicit PassScopedPtr(subtle::PassScopedPtrAnchor<T>* anchor) { | |
| 154 if (anchor->is_valid()) { | |
| 155 type_ = TYPE_ANCHORED; | |
| 156 value_.anchor_ptr = anchor; | |
| 157 } else { | |
| 158 type_ = TYPE_INVALID; | |
| 159 value_.anchor_ptr = NULL; | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 // Destructor. If there is a T object, delete it. | |
| 164 // We don't need to test value_.raw_ptr == NULL because C++ does that for us. | |
| 165 ~PassScopedPtr() { | |
| 166 if (type_ == TYPE_RAW) { | |
| 167 enum { type_must_be_complete = sizeof(T) }; | |
| 168 delete value_.raw_ptr; | |
| 169 } | |
| 170 } | |
| 171 | |
| 172 // Returns true if this object can be copied, or ToScopedPtr() can be called. | |
| 173 bool is_valid() const { return type_ != TYPE_INVALID; } | |
| 174 | |
| 175 void ToScopedPtr(scoped_ptr<T>* scoped) { | |
| 176 scoped->reset(Release()); | |
| 177 } | |
| 178 | |
| 179 ReturnType Pass() { | |
| 180 return ReturnType(Release()); | |
| 181 } | |
| 182 | |
| 183 private: | |
| 184 FRIEND_TEST(PassScopedPtrTest, BasicMethods); | |
| 185 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 186 friend struct internal::Invoker1; | |
| 187 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 188 friend struct internal::Invoker2; | |
| 189 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 190 friend struct internal::Invoker3; | |
| 191 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 192 friend struct internal::Invoker4; | |
| 193 template <bool IsWeak, typename StorageType, typename NormalizedSig> | |
| 194 friend struct internal::Invoker5; | |
| 195 | |
| 196 friend PassScopedPtr<T> internal::Unwrap<T>( | |
| 197 subtle::PassScopedPtrAnchor<T>& o); | |
| 198 | |
| 199 enum Type { | |
| 200 TYPE_INVALID, | |
| 201 TYPE_RAW, | |
| 202 TYPE_ANCHORED, | |
| 203 }; | |
| 204 | |
| 205 T* Release() { | |
| 206 CHECK(type_ != TYPE_INVALID) << "Pointer already used."; | |
|
levin
2011/11/02 00:51:30
DCHECK?
(Are all Chromium check's debug only?)
awong
2011/11/11 00:21:58
I actually prefer CHECK. Otherwise, we're actuall
| |
| 207 | |
| 208 T* ret_val = NULL; | |
| 209 if (type_ == TYPE_RAW) { | |
| 210 ret_val = value_.raw_ptr; | |
| 211 value_.raw_ptr = NULL; | |
| 212 } else { | |
| 213 ret_val = value_.anchor_ptr->Release(); | |
| 214 } | |
| 215 | |
| 216 type_ = TYPE_INVALID; | |
| 217 return ret_val; | |
| 218 } | |
| 219 | |
| 220 // Only used by base::Bind() which we know will be carefully written to | |
| 221 // only invoke this when constructing temporaries during argument forwarding. | |
| 222 // | |
| 223 // TODO(ajwong): Can we make it so this isn't a const&? | |
| 224 PassScopedPtr(const PassScopedPtr& o) | |
| 225 : type_(o.type_) { | |
| 226 PassScopedPtr& other = const_cast<PassScopedPtr&>(o); | |
| 227 if (other.type_ == TYPE_RAW) { | |
| 228 value_.raw_ptr = other.value_.raw_ptr; | |
| 229 other.value_.raw_ptr = NULL; | |
| 230 other.type_ = TYPE_INVALID; | |
|
levin
2011/11/02 00:51:30
Perhaps just hoist other.type_ = TYPE_INVALID out
awong
2011/11/11 00:21:58
Good idea. Done.
| |
| 231 } else if (other.type_ == TYPE_ANCHORED) { | |
| 232 value_.anchor_ptr = other.value_.anchor_ptr; | |
| 233 other.value_.anchor_ptr = NULL; | |
| 234 other.type_ = TYPE_INVALID; | |
| 235 } else if (other.type_ == TYPE_INVALID) { | |
| 236 value_.raw_ptr = NULL; | |
| 237 } | |
| 238 } | |
| 239 | |
| 240 // Is set after ToScopedPtr() is called. After this, subsequent calls to | |
| 241 // ToScopedPtr() will fail. This ensures that ToScopedPtr() is only ever | |
| 242 // called once per object. | |
| 243 Type type_; | |
| 244 | |
| 245 // The actual value that is carried. | |
| 246 union { | |
| 247 T* raw_ptr; | |
| 248 subtle::PassScopedPtrAnchor<T>* anchor_ptr; | |
| 249 } value_; | |
| 250 | |
| 251 // Forbid comparison of PassScopedPtr types. If U != T, it totally doesn't | |
| 252 // make sense, and if U == T, it still doesn't make sense because you should | |
| 253 // never have the same object owned by two different PassScopedPtr. | |
| 254 template <class U> bool operator==(const PassScopedPtr<U>& rhs) const; | |
| 255 template <class U> bool operator!=(const PassScopedPtr<U>& rhs) const; | |
| 256 | |
| 257 // Forbid the assignment operator. | |
| 258 template <class U> | |
| 259 const PassScopedPtr<U>& operator=(const PassScopedPtr<U>& rhs) const; | |
| 260 }; | |
| 261 | |
| 262 template <typename T> | |
| 263 typename PassScopedPtr<T>::ReturnType MakePassScopedPtr(T* ptr) { | |
| 264 return PassScopedPtr<T>(ptr).Pass(); | |
| 265 } | |
| 266 | |
| 267 } // namespace base | |
| 268 | |
| 269 #endif // BASE_MEMORY_PASS_SCOPED_PTR_H_ | |
| OLD | NEW |