Chromium Code Reviews| 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_ |