Index: base/memory/pass_scoped_ptr.h |
diff --git a/base/memory/pass_scoped_ptr.h b/base/memory/pass_scoped_ptr.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7df30ce14794e376f760870089788e361b262540 |
--- /dev/null |
+++ b/base/memory/pass_scoped_ptr.h |
@@ -0,0 +1,269 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef BASE_MEMORY_PASS_SCOPED_PTR_H_ |
+#define BASE_MEMORY_PASS_SCOPED_PTR_H_ |
+#pragma once |
+ |
+#include <stddef.h> |
+ |
+#include "base/compiler_specific.h" |
+#include "base/logging.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/gtest_prod_util.h" |
+ |
+namespace base { |
+ |
+// Forward Decls for friending. |
+template <typename T> class PassScopedPtr; |
+ |
+namespace subtle { |
+template <typename T> class PassScopedPtrAnchor; |
+} // namespace subtle |
+ |
+namespace internal { |
+// TODO(ajwong): Refactor the InvokerN specialization method so that we don't |
+// need 1 friend for each arity. |
+template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+struct Invoker1; |
+template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+struct Invoker2; |
+template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+struct Invoker3; |
+template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+struct Invoker4; |
+template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+struct Invoker5; |
+template <typename T> PassScopedPtr<T> Unwrap( |
+ subtle::PassScopedPtrAnchor<T>& o); |
+} // namespace internal |
+ |
+namespace subtle { |
+ |
+// The TransientPassScopedPtr<> is a PassScopedPtr with destructive copy |
+// semantics. It is meant only to be used as a return type and should never |
+// show up in signatures. Instead use the PassScopedPtr<>::ReturnType |
+// typedef. |
+template <typename T> |
+class TransientPassScopedPtr { |
+ public: |
+ ~TransientPassScopedPtr() { |
+ delete ptr_; |
+ } |
+ |
+ TransientPassScopedPtr(const TransientPassScopedPtr& o) { |
+ TransientPassScopedPtr& other = const_cast<TransientPassScopedPtr&>(o); |
+ ptr_ = other.ptr_; |
+ other.ptr_ = NULL; |
+ } |
+ |
+ void ToScopedPtr(scoped_ptr<T>* scoped) { |
+ scoped->reset(Release()); |
+ } |
+ |
+ private: |
+ friend class PassScopedPtr<T>; |
+ friend class PassScopedPtrAnchor<T>; |
+ |
+ explicit TransientPassScopedPtr(T* ptr) : ptr_(ptr) {} |
+ |
+ T* Release() { |
+ T* ret_val = ptr_; |
+ ptr_ = NULL; |
+ return ret_val; |
+ } |
+ |
+ T* ptr_; |
+}; |
+ |
+// When a PassScopedPtr<> is created based off of the Anchor Type, deleting the |
+// PassScopedPtr<> will not delete the pointee. This is used in base::Bind() so |
+// that a Callback<> with a PassScopedPtr<> only gains ownership of the pointee |
+// if it explicitly calls Pass(). |
+template <typename T> |
+class PassScopedPtrAnchor { |
+ public: |
+ PassScopedPtrAnchor(const TransientPassScopedPtr<T>& interstitial) |
+ : is_valid_(true), |
+ interstitial_(interstitial) { |
+ } |
+ |
+ T* Release() { |
+ CHECK(is_valid_) << "Anchor already used."; |
+ is_valid_ = false; |
+ return interstitial_.Release(); |
+ } |
+ |
+ bool is_valid() { return is_valid_; } |
+ |
+ private: |
+ bool is_valid_; |
+ TransientPassScopedPtr<T> interstitial_; |
+}; |
+ |
+} // namespace subtle |
+ |
+// PassScopedPtr is a container class that is targeted specifically at |
+// transfering ownership across function calls. It should only be used as |
+// a parameter type. If a function is returning ownership, it should use |
+// PassScopedPtr<T>::ReturnType. All other situations should prefer |
+// scoped_ptr. |
+// |
+// To help prevent unwanted usage, the public interface of this class is |
+// intentionally featureless lacking overrides for ->, or easy retrieval to |
+// the underlying pointer. In particular, only 2 operations are allowed for |
+// the class: |
+// |
+// 1) Calling Pass() to transfer ownership to another PassScopedPtr. |
+// 2) Calling ToScopedPtr() to transfer ownership to a scoped_ptr. |
+// |
+// Each of these methods may only be called once on a PassScopedPtr. A second |
+// invocation will cause a CHECK(). |
+// |
+// This class is not thread safe. If passing across threads, external |
+// synchronization must be used. One exception is that it is safe to use |
+// with base::Bind() to pass through threads via a PostTask because the |
+// PostTask's mutex will enforce the correct synchronization as long as |
+// that only one thread may invoke Run() on the resulting base::Callback(). |
+// |
+// In the case that the resulting base::Callback<> is executed multiple times |
+// it will be given the same logical PassScopedPtr as the argument. |
+// Ownership of the underlying pointer is kept with the base::Callback until |
+// Pass() or ToScopedPtr() is executed during one of these calls. After this, |
+// ownership is passed, and subsequent calls will get a PassScopedPtr where |
+// is_valid() returns false. This makes the transfer of ownership _out_ of |
+// a base::Callback's bound argument explicit. |
+template <class T> |
+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
|
+ public: |
+ explicit PassScopedPtr(T* ptr) |
+ : type_(TYPE_RAW) { |
+ value_.raw_ptr = ptr; |
+ } |
+ |
+ typedef subtle::TransientPassScopedPtr<T> ReturnType; |
+ |
+ PassScopedPtr(const ReturnType& interstitial) |
+ : type_(TYPE_RAW) { |
+ value_.raw_ptr = const_cast<ReturnType&>(interstitial).Release(); |
+ } |
+ |
+ // TODO(ajwong): Make this private and friend InvokerStorage<>. |
+ explicit PassScopedPtr(subtle::PassScopedPtrAnchor<T>* anchor) { |
+ if (anchor->is_valid()) { |
+ type_ = TYPE_ANCHORED; |
+ value_.anchor_ptr = anchor; |
+ } else { |
+ type_ = TYPE_INVALID; |
+ value_.anchor_ptr = NULL; |
+ } |
+ } |
+ |
+ // Destructor. If there is a T object, delete it. |
+ // We don't need to test value_.raw_ptr == NULL because C++ does that for us. |
+ ~PassScopedPtr() { |
+ if (type_ == TYPE_RAW) { |
+ enum { type_must_be_complete = sizeof(T) }; |
+ delete value_.raw_ptr; |
+ } |
+ } |
+ |
+ // Returns true if this object can be copied, or ToScopedPtr() can be called. |
+ bool is_valid() const { return type_ != TYPE_INVALID; } |
+ |
+ void ToScopedPtr(scoped_ptr<T>* scoped) { |
+ scoped->reset(Release()); |
+ } |
+ |
+ ReturnType Pass() { |
+ return ReturnType(Release()); |
+ } |
+ |
+ private: |
+ FRIEND_TEST(PassScopedPtrTest, BasicMethods); |
+ template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+ friend struct internal::Invoker1; |
+ template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+ friend struct internal::Invoker2; |
+ template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+ friend struct internal::Invoker3; |
+ template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+ friend struct internal::Invoker4; |
+ template <bool IsWeak, typename StorageType, typename NormalizedSig> |
+ friend struct internal::Invoker5; |
+ |
+ friend PassScopedPtr<T> internal::Unwrap<T>( |
+ subtle::PassScopedPtrAnchor<T>& o); |
+ |
+ enum Type { |
+ TYPE_INVALID, |
+ TYPE_RAW, |
+ TYPE_ANCHORED, |
+ }; |
+ |
+ T* Release() { |
+ 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
|
+ |
+ T* ret_val = NULL; |
+ if (type_ == TYPE_RAW) { |
+ ret_val = value_.raw_ptr; |
+ value_.raw_ptr = NULL; |
+ } else { |
+ ret_val = value_.anchor_ptr->Release(); |
+ } |
+ |
+ type_ = TYPE_INVALID; |
+ return ret_val; |
+ } |
+ |
+ // Only used by base::Bind() which we know will be carefully written to |
+ // only invoke this when constructing temporaries during argument forwarding. |
+ // |
+ // TODO(ajwong): Can we make it so this isn't a const&? |
+ PassScopedPtr(const PassScopedPtr& o) |
+ : type_(o.type_) { |
+ PassScopedPtr& other = const_cast<PassScopedPtr&>(o); |
+ if (other.type_ == TYPE_RAW) { |
+ value_.raw_ptr = other.value_.raw_ptr; |
+ other.value_.raw_ptr = NULL; |
+ 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.
|
+ } else if (other.type_ == TYPE_ANCHORED) { |
+ value_.anchor_ptr = other.value_.anchor_ptr; |
+ other.value_.anchor_ptr = NULL; |
+ other.type_ = TYPE_INVALID; |
+ } else if (other.type_ == TYPE_INVALID) { |
+ value_.raw_ptr = NULL; |
+ } |
+ } |
+ |
+ // Is set after ToScopedPtr() is called. After this, subsequent calls to |
+ // ToScopedPtr() will fail. This ensures that ToScopedPtr() is only ever |
+ // called once per object. |
+ Type type_; |
+ |
+ // The actual value that is carried. |
+ union { |
+ T* raw_ptr; |
+ subtle::PassScopedPtrAnchor<T>* anchor_ptr; |
+ } value_; |
+ |
+ // Forbid comparison of PassScopedPtr types. If U != T, it totally doesn't |
+ // make sense, and if U == T, it still doesn't make sense because you should |
+ // never have the same object owned by two different PassScopedPtr. |
+ template <class U> bool operator==(const PassScopedPtr<U>& rhs) const; |
+ template <class U> bool operator!=(const PassScopedPtr<U>& rhs) const; |
+ |
+ // Forbid the assignment operator. |
+ template <class U> |
+ const PassScopedPtr<U>& operator=(const PassScopedPtr<U>& rhs) const; |
+}; |
+ |
+template <typename T> |
+typename PassScopedPtr<T>::ReturnType MakePassScopedPtr(T* ptr) { |
+ return PassScopedPtr<T>(ptr).Pass(); |
+} |
+ |
+} // namespace base |
+ |
+#endif // BASE_MEMORY_PASS_SCOPED_PTR_H_ |