From 63a822490bb1ac98d4fb8a1e76187ecd3ae5c118 Mon Sep 17 00:00:00 2001 From: "ajwong@chromium.org" Date: Fri, 9 Dec 2011 01:29:38 +0000 Subject: Add Pass(), which implements move semantics, to scoped_ptr, scoped_array, and scoped_ptr_malloc. This modification to the scopers implements the "moveable but not copyable" semantics that were introduced in C++11's unique_ptr<>. With this, is now possible to use scopers as an argument type or a return type. This signifies, in the type system, transfer of ownership into a function or out of a function respectively. Calling, or returning such a function MUST use the temporary resulting from the scoper's Pass() function. You CANNOT just pass the scoper by copy as there is still no copy constructor or assignment operator; trying to do so will yield a compilation error. This distinction makes it possible to avoid the implicit ownership transfer issues of auto_ptr, but still allow us to have compiler enforced ownership transfer. Also adds a Passed() helper that allows using a scoper with Bind(). BUG=96118 TEST=new unittests Review URL: http://codereview.chromium.org/8774032 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113722 0039d316-1c4b-4281-b951-d872f2087c98 --- base/bind_helpers.h | 152 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 121 insertions(+), 31 deletions(-) (limited to 'base/bind_helpers.h') diff --git a/base/bind_helpers.h b/base/bind_helpers.h index 6e0f8fe..df8cf82 100644 --- a/base/bind_helpers.h +++ b/base/bind_helpers.h @@ -6,19 +6,29 @@ // can be used specify the refcounting and reference semantics of arguments // that are bound by the Bind() function in base/bind.h. // -// The public functions are base::Unretained(), base::Owned(), -// base::ConstRef(), and base::IgnoreReturn(). +// The public functions are base::Unretained(), base::Owned(), bass::Passed(), +// base::ConstRef(), and base::IgnoreResult(). // // Unretained() allows Bind() to bind a non-refcounted class, and to disable // refcounting on arguments that are refcounted objects. +// // Owned() transfers ownership of an object to the Callback resulting from // bind; the object will be deleted when the Callback is deleted. +// +// Passed() is for transferring movable-but-not-copyable types (eg. scoped_ptr) +// through a Callback. Logically, this signifies a destructive transfer of +// the state of the argument into the target function. Invoking +// Callback::Run() twice on a Callback that was created with a Passed() +// argument will CHECK() because the first invocation would have already +// transferred ownership to the target function. +// // ConstRef() allows binding a constant reference to an argument rather // than a copy. -// IgnoreReturn() is used to adapt a 0-argument Callback with a return type to -// a Closure. This is useful if you need to PostTask with a function that has -// a return value that you don't care about. // +// IgnoreResult() is used to adapt a function or Callback with a return type to +// one with a void return. This is most useful if you have a function with, +// say, a pesky ignorable bool return that you want to use with PostTask or +// something else that expect a Callback with a void return. // // EXAMPLE OF Unretained(): // @@ -75,13 +85,45 @@ // its bound callbacks. // // -// EXAMPLE OF IgnoreReturn(): +// EXAMPLE OF IgnoreResult(): // // int DoSomething(int arg) { cout << arg << endl; } -// Callback cb = Bind(&DoSomething, 1); -// Closure c = IgnoreReturn(cb); // Prints "1" -// or -// ml->PostTask(FROM_HERE, IgnoreReturn(cb)); // Prints "1" on |ml| +// +// // Assign to a Callback with a void return type. +// Callback cb = Bind(IgnoreResult(&DoSomething)); +// cb->Run(1); // Prints "1". +// +// // Prints "1" on |ml|. +// ml->PostTask(FROM_HERE, Bind(IgnoreResult(&DoSomething), 1); +// +// +// EXAMPLE OF Passed(): +// +// void TakesOwnership(scoped_ptr arg) { } +// scoped_ptr CreateFoo() { return scoped_ptr(new Foo()); } +// +// scoped_ptr f(new Foo()); +// +// // |cb| is given ownership of Foo(). |f| is now NULL. +// // You can use f.Pass() in place of &f, but it's more verbose. +// Closure cb = Bind(&TakesOwnership, Passed(&f)); +// +// // Run was never called so |cb| still owns Foo() and deletes +// // it on Reset(). +// cb.Reset(); +// +// // |cb| is given a new Foo created by CreateFoo(). +// cb = Bind(&TakesOwnership, Passed(CreateFoo())); +// +// // |arg| in TakesOwnership() is given ownership of Foo(). |cb| +// // no longer owns Foo() and, if reset, would not delete Foo(). +// cb.Run(); // Foo() is now transferred to |arg| and deleted. +// cb.Run(); // This CHECK()s since Foo() already been used once. +// +// Passed() is particularly useful with PostTask() when you are transferring +// ownership of an argument into a task, but don't necessarily know if the +// task will always be executed. This can happen if the task is cancellable +// or if it is posted to a MessageLoopProxy. #ifndef BASE_BIND_HELPERS_H_ #define BASE_BIND_HELPERS_H_ @@ -287,6 +329,45 @@ class OwnedWrapper { mutable T* ptr_; }; +// PassedWrapper is a copyable adapter for a scoper that ignores const. +// +// It is needed to get around the fact that Bind() takes a const reference to +// all its arguments. Because Bind() takes a const reference to avoid +// unnecessary copies, it is incompatible with movable-but-not-copyable +// types; doing a destructive "move" of the type into Bind() would violate +// the const correctness. +// +// This conundrum cannot be solved without either C++11 rvalue references or +// a O(2^n) blowup of Bind() templates to handle each combination of regular +// types and movable-but-not-copyable types. Thus we introduce a wrapper type +// that is copyable to transmit the correct type information down into +// BindState<>. Ignoring const in this type makes sense because it is only +// created when we are explicitly trying to do a destructive move. +// +// Two notes: +// 1) PassedWrapper supports any type that has a "Pass()" function. +// This is intentional. The whitelisting of which specific types we +// support is maintained by CallbackParamTraits<>. +// 2) is_valid_ is distinct from NULL because it is valid to bind a "NULL" +// scoper to a Callback and allow the Callback to execute once. +template +class PassedWrapper { + public: + explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {} + PassedWrapper(const PassedWrapper& other) + : is_valid_(other.is_valid_), scoper_(other.scoper_.Pass()) { + } + T Pass() const { + CHECK(is_valid_); + is_valid_ = false; + return scoper_.Pass(); + } + + private: + mutable bool is_valid_; + mutable T scoper_; +}; + // Unwrap the stored parameters for the wrappers above. template struct UnwrapTraits { @@ -330,9 +411,17 @@ struct UnwrapTraits > { } }; +template +struct UnwrapTraits > { + typedef T ForwardType; + static T Unwrap(PassedWrapper& o) { + return o.Pass(); + } +}; + // Utility for handling different refcounting semantics in the Bind() // function. -template +template struct MaybeRefcount; template @@ -348,21 +437,15 @@ struct MaybeRefcount { }; template -struct MaybeRefcount { - static void AddRef(T* o) { o->AddRef(); } - static void Release(T* o) { o->Release(); } -}; - -template -struct MaybeRefcount > { - static void AddRef(const UnretainedWrapper&) {} - static void Release(const UnretainedWrapper&) {} +struct MaybeRefcount { + static void AddRef(const T&) {} + static void Release(const T&) {} }; template -struct MaybeRefcount > { - static void AddRef(const OwnedWrapper&) {} - static void Release(const OwnedWrapper&) {} +struct MaybeRefcount { + static void AddRef(T* o) { o->AddRef(); } + static void Release(T* o) { o->Release(); } }; // No need to additionally AddRef() and Release() since we are storing a @@ -379,19 +462,13 @@ struct MaybeRefcount { static void Release(const T* o) { o->Release(); } }; -template -struct MaybeRefcount > { - static void AddRef(const WeakPtr&) {} - static void Release(const WeakPtr&) {} -}; - template void VoidReturnAdapter(Callback callback) { callback.Run(); } // IsWeakMethod is a helper that determine if we are binding a WeakPtr<> to a -// method. It is unsed internally by Bind() to select the correct +// method. It is used internally by Bind() to select the correct // InvokeHelper that will no-op itself in the event the WeakPtr<> for // the target object is invalidated. // @@ -422,6 +499,20 @@ static inline internal::OwnedWrapper Owned(T* o) { return internal::OwnedWrapper(o); } +// We offer 2 syntaxes for calling Passed(). The first takes a temporary and +// is best suited for use with the return value of a function. The second +// takes a pointer to the scoper and is just syntactic sugar to avoid having +// to write Passed(scoper.Pass()). +template +static inline internal::PassedWrapper Passed(T scoper) { + return internal::PassedWrapper(scoper.Pass()); +} +template +static inline internal::PassedWrapper Passed(T* scoper) { + return internal::PassedWrapper(scoper->Pass()); +} + +// -- DEPRECATED -- Use IgnoreResult instead. template static inline Closure IgnoreReturn(Callback callback) { return Bind(&internal::VoidReturnAdapter, callback); @@ -438,7 +529,6 @@ IgnoreResult(const Callback& data) { return internal::IgnoreResultHelper >(data); } - } // namespace base #endif // BASE_BIND_HELPERS_H_ -- cgit v1.1