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

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: Fixed it. 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
« no previous file with comments | « base/callback_internal.h ('k') | base/memory/pass_scoped_ptr_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 template <typename T> PassScopedPtr<T> MakePassScopedPtr(T* ptr);
21
22 namespace internal {
23 template <bool IsWeakCall, typename ReturnType, typename Runnable,
24 typename ArgsType>
25 struct InvokeHelper;
26 } // namespace internal
27
28 namespace subtle {
29
30 // When a PassScopedPtr<> is created based off of the Anchor Type, deleting the
31 // PassScopedPtr<> will not delete the pointee. This is used in base::Bind() so
32 // that a Callback<> with a PassScopedPtr<> only gains ownership of the pointee
33 // if it explicitly calls Pass().
34 template <typename T>
35 class PassScopedPtrAnchor {
36 public:
37 explicit PassScopedPtrAnchor(PassScopedPtr<T> ptr)
38 : ptr_(ptr.Pass()) {
39 }
40
41 PassScopedPtrAnchor(const PassScopedPtrAnchor& other)
42 : ptr_(const_cast<PassScopedPtrAnchor&>(other).ptr_.Pass()){
43 }
44
45 T* Release() {
46 return ptr_.Release();
47 }
48
49 bool is_valid() { return ptr_.is_valid(); }
50
51 private:
52 PassScopedPtr<T> ptr_;
53 };
54
55 } // namespace subtle
56
57 // PassScopedPtr is a container class that is targeted specifically at
58 // transfering ownership across function calls. It should only be used as
59 // a parameter type, and the parameter type must be a const reference. If
60 // a function is returning ownership, it should use
61 // PassScopedPtr<T>. All other situations should prefer
62 // scoped_ptr.
63 //
64 // To help prevent unwanted usage, the public interface of this class is
65 // intentionally featureless lacking overrides for ->, or easy retrieval to
66 // the underlying pointer. In particular, only 3 operations are allowed for
67 // the class:
68 //
69 // 1) Calling Pass() to transfer ownership to another PassScopedPtr.
70 // 2) Calling PassForBind() to transfer ownership to a Bind() call.
71 // 3) Calling ToScopedPtr() to transfer ownership to a scoped_ptr.
72 //
73 // Each of these methods may only be called once on a PassScopedPtr. A second
74 // invocation will cause a CHECK().
75 //
76 // This class is not thread safe. If passing across threads, external
77 // synchronization must be used. One exception is that it is safe to use
78 // with base::Bind() to pass through threads via a PostTask because the
79 // PostTask's mutex will enforce the correct synchronization as long as
80 // that only one thread may invoke Run() on the resulting base::Callback().
81 //
82 // In the case that the resulting base::Callback<> is executed multiple times
83 // it will be given the same logical PassScopedPtr as the argument.
84 // Ownership of the underlying pointer is kept with the base::Callback until
85 // Pass() or ToScopedPtr() is executed during one of these calls. After this,
86 // ownership is passed, and subsequent calls will get a PassScopedPtr where
87 // is_valid() returns false. This makes the transfer of ownership _out_ of
88 // a base::Callback's bound argument explicit.
89 template <class T>
90 class PassScopedPtr {
91 public:
92 // Destructor. If there is a T object, delete it.
93 // We don't need to test value_.raw_ptr == NULL because C++ does that for us.
94 ~PassScopedPtr() {
95 if (type_ == TYPE_RAW) {
96 enum { type_must_be_complete = sizeof(T) };
97 delete value_.raw_ptr;
98 }
99 }
100
101 // Returns true if this object can be copied, or ToScopedPtr() can be called.
102 bool is_valid() const { return type_ != TYPE_INVALID; }
103
104 void ToScopedPtr(scoped_ptr<T>* scoped) const {
105 scoped->reset(Release());
106 }
107
108 PassScopedPtr Pass() {
109 return PassScopedPtr(MoveProxy(*this));
110 }
111
112 // Only to be used in conjunction with a Bind() call.
113 subtle::PassScopedPtrAnchor<T> PassForBind() {
114 return subtle::PassScopedPtrAnchor<T>(Pass());
115 }
116
117 // ==== Begin implementation of Move semantics in C++03.
118 //
119 // http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
120 private:
121 struct MoveProxy {
122 explicit MoveProxy(PassScopedPtr& obj) : obj_(obj) {}
123 PassScopedPtr& obj_;
124 };
125 // Important that this does NOT take a const PassScopedPtr&.
126 PassScopedPtr(PassScopedPtr& other) {}
127 public:
128 operator MoveProxy() {
129 return MoveProxy(*this);
130 }
131 PassScopedPtr(MoveProxy proxy) : type_(TYPE_RAW) {
132 value_.raw_ptr = proxy.obj_.Release();
133 }
134 // ==== End implementation of Move semantics in C++03.
135
136 private:
137 FRIEND_TEST(PassScopedPtrTest, AnchorBehavior);
138 FRIEND_TEST(PassScopedPtrTest, BasicMethods);
139 template <bool IsWeakCall, typename ReturnType, typename Runnable,
140 typename ArgsType>
141 friend struct internal::InvokeHelper;
142 friend PassScopedPtr MakePassScopedPtr<T>(T* ptr);
143 friend class subtle::PassScopedPtrAnchor<T>;
144
145 enum Type {
146 TYPE_INVALID,
147 TYPE_RAW,
148 TYPE_ANCHORED,
149 };
150
151 explicit PassScopedPtr(T* ptr)
152 : type_(TYPE_RAW) {
153 value_.raw_ptr = ptr;
154 }
155
156 PassScopedPtr(subtle::PassScopedPtrAnchor<T>* anchor) {
157 if (anchor->is_valid()) {
158 type_ = TYPE_ANCHORED;
159 value_.anchor_ptr = anchor;
160 } else {
161 type_ = TYPE_INVALID;
162 value_.anchor_ptr = NULL;
163 }
164 }
165
166 T* Release() const {
167 // Make sure pointer has not been used already.
168 CHECK(type_ != TYPE_INVALID);
169
170 T* ret_val = NULL;
171 if (type_ == TYPE_RAW) {
172 ret_val = value_.raw_ptr;
173 value_.raw_ptr = NULL;
174 } else {
175 ret_val = value_.anchor_ptr->Release();
176 }
177
178 type_ = TYPE_INVALID;
179 return ret_val;
180 }
181
182 // Is set after ToScopedPtr() is called. After this, subsequent calls to
183 // ToScopedPtr() will fail. This ensures that ToScopedPtr() is only ever
184 // called once per object.
185 mutable Type type_;
186
187 // The actual value that is carried.
188 mutable union {
189 T* raw_ptr;
190 subtle::PassScopedPtrAnchor<T>* anchor_ptr;
191 } value_;
192
193 // Forbid comparison of PassScopedPtr types. If U != T, it totally doesn't
194 // make sense, and if U == T, it still doesn't make sense because you should
195 // never have the same object owned by two different PassScopedPtr.
196 template <class U> bool operator==(const PassScopedPtr<U>& rhs) const;
197 template <class U> bool operator!=(const PassScopedPtr<U>& rhs) const;
198
199 // Forbid the assignment operator.
200 template <class U>
201 const PassScopedPtr<U>& operator=(const PassScopedPtr<U>& rhs) const;
202 };
203
204 template <typename T>
205 PassScopedPtr<T> MakePassScopedPtr(T* ptr) {
206 return PassScopedPtr<T>(ptr).Pass();
207 }
208
209 } // namespace base
210
211 #endif // BASE_MEMORY_PASS_SCOPED_PTR_H_
OLDNEW
« no previous file with comments | « base/callback_internal.h ('k') | base/memory/pass_scoped_ptr_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698