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

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: Fixed it. Created 9 years, 1 month 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
« no previous file with comments | « base/callback_internal.h ('k') | base/memory/pass_scoped_ptr_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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_
« no previous file with comments | « base/callback_internal.h ('k') | base/memory/pass_scoped_ptr_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698