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

Unified Diff: base/bind_helpers.h

Issue 8774032: Add Pass(), which implements move semantics, to scoped_ptr, scoped_array, and scoped_ptr_malloc. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix comments, make Passed() support temporaries, fix unbound argument forwarding, add more tests. Created 9 years 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 | « no previous file | base/bind_internal.h » ('j') | base/callback_internal.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/bind_helpers.h
diff --git a/base/bind_helpers.h b/base/bind_helpers.h
index 6e0f8fe72742a06f7875d5f73a4b9e0ec97f6c45..151e9816fd04a7dbcf710bc27cf36dffb43602c8 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 transfering moveable-but-not-copyable types (eg. scoped_ptr)
willchan no longer on Chromium 2011/12/07 16:24:34 s/transfering/transferring/ s/moveable/movable/
awong 2011/12/08 21:04:10 Done.
+// 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
+// transfered ownership to the target function.
willchan no longer on Chromium 2011/12/07 16:24:34 s/transfered/transferred/
awong 2011/12/08 21:04:10 Done.
+//
// 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<int(void)> 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<void(int)> 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<Foo> arg) { }
+// scoped_ptr<Foo> CreateFoo() { return scoped_ptr<Foo>(new Foo()); }
+//
+// scoped_ptr<Foo> 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 longers owns Foo() and, if reset, would not delete Foo().
+// cb.Run(); // Foo() is now transfered to |arg| and deleted.
willchan no longer on Chromium 2011/12/07 16:24:34 s/transfered/transferred/
awong 2011/12/08 21:04:10 Done.
+// cb.Run(); // This CHECK()s since Foo() already been used once.
willchan no longer on Chromium 2011/12/07 16:24:34 Is there actually a CHECK somewhere? Or does it SI
awong 2011/12/08 21:04:10 Yep. There's a distinction between initializing P
+//
+// Passed() is particularly useful with PostTask() when you are transfering
+// 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_
@@ -90,6 +132,7 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
willchan no longer on Chromium 2011/12/07 16:24:34 This isn't necessary is it?
awong 2011/12/08 21:04:10 Not anymore. Removed.
#include "base/memory/weak_ptr.h"
#include "base/template_util.h"
@@ -287,6 +330,38 @@ 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 moveable-but-not-copyable
willchan no longer on Chromium 2011/12/07 16:24:34 s/moveable/movable/
awong 2011/12/08 21:04:10 Done.
+// types; doing a destructive "move" of the type into Bind() would violate
+// the const correctness.
+//
+// This connundrum 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 moveable-but-not-copyable types. Thus we introduce a wrapper type
willchan no longer on Chromium 2011/12/07 16:24:34 s/moveable/movable/
awong 2011/12/08 21:04:10 Done.
+// that is copyable to transmit the get the correct type information down into
willchan no longer on Chromium 2011/12/07 16:24:34 transmit the get the correct type?
awong 2011/12/08 21:04:10 Done.
+// BindState<>. Ignoring const in this type makes sense because it is only
+// created when we are explicitly trying to do a destructive move.
+template <typename T>
+class PassedWrapper {
+ public:
+ explicit PassedWrapper(T scoper) : is_valid_(true), scoper_(scoper.Pass()) {}
willchan no longer on Chromium 2011/12/07 16:24:34 Does this work for anything with Pass() defined? D
awong 2011/12/08 21:04:10 It works for anything with Pass(). I think this i
+ 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 <typename T>
struct UnwrapTraits {
@@ -330,9 +405,17 @@ struct UnwrapTraits<OwnedWrapper<T> > {
}
};
+template <typename T>
+struct UnwrapTraits<PassedWrapper<T> > {
+ typedef T ForwardType;
+ static T Unwrap(PassedWrapper<T>& o) {
+ return o.Pass();
+ }
+};
+
// Utility for handling different refcounting semantics in the Bind()
// function.
-template <bool, typename T>
+template <bool is_method, typename T>
struct MaybeRefcount;
template <typename T>
@@ -348,21 +431,15 @@ struct MaybeRefcount<false, T[n]> {
};
template <typename T>
-struct MaybeRefcount<true, T*> {
- static void AddRef(T* o) { o->AddRef(); }
- static void Release(T* o) { o->Release(); }
-};
-
-template <typename T>
-struct MaybeRefcount<true, UnretainedWrapper<T> > {
- static void AddRef(const UnretainedWrapper<T>&) {}
- static void Release(const UnretainedWrapper<T>&) {}
+struct MaybeRefcount<true, T> {
+ static void AddRef(const T&) {}
+ static void Release(const T&) {}
};
template <typename T>
-struct MaybeRefcount<true, OwnedWrapper<T> > {
- static void AddRef(const OwnedWrapper<T>&) {}
- static void Release(const OwnedWrapper<T>&) {}
+struct MaybeRefcount<true, T*> {
+ 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,12 +456,6 @@ struct MaybeRefcount<true, const T*> {
static void Release(const T* o) { o->Release(); }
};
-template <typename T>
-struct MaybeRefcount<true, WeakPtr<T> > {
- static void AddRef(const WeakPtr<T>&) {}
- static void Release(const WeakPtr<T>&) {}
-};
-
template <typename R>
void VoidReturnAdapter(Callback<R(void)> callback) {
callback.Run();
@@ -422,6 +493,20 @@ static inline internal::OwnedWrapper<T> Owned(T* o) {
return internal::OwnedWrapper<T>(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 <typename T>
+static inline internal::PassedWrapper<T> Passed(T scoper) {
+ return internal::PassedWrapper<T>(scoper.Pass());
+}
+template <typename T>
+static inline internal::PassedWrapper<T> Passed(T* scoper) {
+ return internal::PassedWrapper<T>(scoper->Pass());
+}
+
+// -- DEPRECATED -- Use IgnoreResult instead.
template <typename R>
static inline Closure IgnoreReturn(Callback<R(void)> callback) {
return Bind(&internal::VoidReturnAdapter<R>, callback);
@@ -438,7 +523,6 @@ IgnoreResult(const Callback<T>& data) {
return internal::IgnoreResultHelper<Callback<T> >(data);
}
-
} // namespace base
#endif // BASE_BIND_HELPERS_H_
« no previous file with comments | « no previous file | base/bind_internal.h » ('j') | base/callback_internal.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698