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 |