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

Unified 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: Anchroed PassOwnPtr with Bind. Created 9 years, 2 months 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 side-by-side diff with in-line comments
Download patch
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_

Powered by Google App Engine
This is Rietveld 408576698