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 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_ |
OLD | NEW |