Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(143)

Side by Side Diff: base/memory/pass_scoped_ptr.h

Issue 8224026: Add a PassScopedPtr into base/memory. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Anchroed PassOwnPtr with Bind. Created 9 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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_
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698