| 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..1adc4367fd3af3017b56d2bc75f02784003a188a
|
| --- /dev/null
|
| +++ b/base/memory/pass_scoped_ptr.h
|
| @@ -0,0 +1,211 @@
|
| +// 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;
|
| +template <typename T> PassScopedPtr<T> MakePassScopedPtr(T* ptr);
|
| +
|
| +namespace internal {
|
| +template <bool IsWeakCall, typename ReturnType, typename Runnable,
|
| + typename ArgsType>
|
| +struct InvokeHelper;
|
| +} // namespace internal
|
| +
|
| +namespace subtle {
|
| +
|
| +// 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:
|
| + explicit PassScopedPtrAnchor(PassScopedPtr<T> ptr)
|
| + : ptr_(ptr.Pass()) {
|
| + }
|
| +
|
| + PassScopedPtrAnchor(const PassScopedPtrAnchor& other)
|
| + : ptr_(const_cast<PassScopedPtrAnchor&>(other).ptr_.Pass()){
|
| + }
|
| +
|
| + T* Release() {
|
| + return ptr_.Release();
|
| + }
|
| +
|
| + bool is_valid() { return ptr_.is_valid(); }
|
| +
|
| + private:
|
| + PassScopedPtr<T> ptr_;
|
| +};
|
| +
|
| +} // 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, and the parameter type must be a const reference. If
|
| +// a function is returning ownership, it should use
|
| +// PassScopedPtr<T>. 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 3 operations are allowed for
|
| +// the class:
|
| +//
|
| +// 1) Calling Pass() to transfer ownership to another PassScopedPtr.
|
| +// 2) Calling PassForBind() to transfer ownership to a Bind() call.
|
| +// 3) 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 {
|
| + public:
|
| + // 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) const {
|
| + scoped->reset(Release());
|
| + }
|
| +
|
| + PassScopedPtr Pass() {
|
| + return PassScopedPtr(MoveProxy(*this));
|
| + }
|
| +
|
| + // Only to be used in conjunction with a Bind() call.
|
| + subtle::PassScopedPtrAnchor<T> PassForBind() {
|
| + return subtle::PassScopedPtrAnchor<T>(Pass());
|
| + }
|
| +
|
| + // ==== Begin implementation of Move semantics in C++03.
|
| + //
|
| + // http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Move_Constructor
|
| + private:
|
| + struct MoveProxy {
|
| + explicit MoveProxy(PassScopedPtr& obj) : obj_(obj) {}
|
| + PassScopedPtr& obj_;
|
| + };
|
| + // Important that this does NOT take a const PassScopedPtr&.
|
| + PassScopedPtr(PassScopedPtr& other) {}
|
| + public:
|
| + operator MoveProxy() {
|
| + return MoveProxy(*this);
|
| + }
|
| + PassScopedPtr(MoveProxy proxy) : type_(TYPE_RAW) {
|
| + value_.raw_ptr = proxy.obj_.Release();
|
| + }
|
| + // ==== End implementation of Move semantics in C++03.
|
| +
|
| + private:
|
| + FRIEND_TEST(PassScopedPtrTest, AnchorBehavior);
|
| + FRIEND_TEST(PassScopedPtrTest, BasicMethods);
|
| + template <bool IsWeakCall, typename ReturnType, typename Runnable,
|
| + typename ArgsType>
|
| + friend struct internal::InvokeHelper;
|
| + friend PassScopedPtr MakePassScopedPtr<T>(T* ptr);
|
| + friend class subtle::PassScopedPtrAnchor<T>;
|
| +
|
| + enum Type {
|
| + TYPE_INVALID,
|
| + TYPE_RAW,
|
| + TYPE_ANCHORED,
|
| + };
|
| +
|
| + explicit PassScopedPtr(T* ptr)
|
| + : type_(TYPE_RAW) {
|
| + value_.raw_ptr = ptr;
|
| + }
|
| +
|
| + PassScopedPtr(subtle::PassScopedPtrAnchor<T>* anchor) {
|
| + if (anchor->is_valid()) {
|
| + type_ = TYPE_ANCHORED;
|
| + value_.anchor_ptr = anchor;
|
| + } else {
|
| + type_ = TYPE_INVALID;
|
| + value_.anchor_ptr = NULL;
|
| + }
|
| + }
|
| +
|
| + T* Release() const {
|
| + // Make sure pointer has not been used already.
|
| + CHECK(type_ != TYPE_INVALID);
|
| +
|
| + 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;
|
| + }
|
| +
|
| + // 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.
|
| + mutable Type type_;
|
| +
|
| + // The actual value that is carried.
|
| + mutable 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>
|
| +PassScopedPtr<T> MakePassScopedPtr(T* ptr) {
|
| + return PassScopedPtr<T>(ptr).Pass();
|
| +}
|
| +
|
| +} // namespace base
|
| +
|
| +#endif // BASE_MEMORY_PASS_SCOPED_PTR_H_
|
|
|