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

Unified Diff: base/prebind.h

Issue 6094005: Create "Prebind" a wrapper to tr1::bind. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/base
Patch Set: Remove closure.h and ThunkState Created 9 years, 12 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
« no previous file with comments | « base/message_loop.cc ('k') | base/task.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/prebind.h
diff --git a/base/prebind.h b/base/prebind.h
new file mode 100644
index 0000000000000000000000000000000000000000..489921683cdf497b3859e46342ea311973b2642d
--- /dev/null
+++ b/base/prebind.h
@@ -0,0 +1,402 @@
+// 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_PREBIND_H
+#define BASE_PREBIND_H
+
+#include <tr1/functional>
+
+#include <base/ref_counted.h>
+
+namespace base {
+
+// These are needed to implement a wrapper that disables refcounting on
+// objects used with a Thunk.
+template <typename O>
+class UnretainedWrapper {
+ public:
+ explicit UnretainedWrapper(O* o) : obj_(o) {}
+ O* get() const { return obj_; }
+
+ private:
+ O* obj_;
+};
+
+template <typename O>
+UnretainedWrapper<O> Unretained(O* o) {
+ return UnretainedWrapper<O>(o);
+}
+
+// Invoker is adds a level of indirection into the function call using syntax
+// that will work with either a raw pointer to an object, or a scoped_refptr.
+//
+// This allows us to pass a scoped_refptr into bind for an object we wish to
+// retrain and maintain the same syntax for invoking its methods.
+//
+// O is either a scoped_refptr<T> or T* where T is the target object.
+template <typename O, typename Sig>
+struct Invoker;
+
+template <typename O, typename R, typename T>
+struct Invoker<O, R(T::*)(void)> {
+ static R invoke(R(T::*f)(void), const O& o) {
+ return (o->*f)();
+ }
+};
+
+template <typename O, typename R, typename T, typename A0>
+struct Invoker<O, R(T::*)(A0)> {
+ static R invoke(R(T::*f)(A0), const O& o, const A0& a0) {
+ return (o->*f)(a0);
+ }
+};
+
+template <typename O, typename R, typename T, typename A0, typename A1>
+struct Invoker<O, R(T::*)(A0, A1)> {
+ static R invoke(R(T::*f)(A0, A1), const O& o, const A0& a0, const A1& a1) {
+ return (o->*f)(a0, a1);
+ }
+};
+
+template <typename O, typename R, typename T, typename A0, typename A1,
+ typename A2>
+struct Invoker<O, R(T::*)(A0, A1, A2)> {
+ static R invoke(R(T::*f)(A0, A1, A2), const O& o, const A0& a0, const A1& a1,
+ const A2& a2) {
+ return (o->*f)(a0, a1, a2);
+ }
+};
+
+template <typename O, typename R, typename T, typename A0, typename A1,
+ typename A2, typename A3>
+struct Invoker<O, R(T::*)(A0, A1, A2, A3)> {
+ static R invoke(R(T::*f)(A0, A1, A2, A3), const O& o, const A0& a0,
+ const A1& a1, const A2& a2, const A3& a3) {
+ return (o->*f)(a0, a1, a2, a3);
+ }
+};
+
+template <typename O, typename R, typename T, typename A0, typename A1,
+ typename A2, typename A3, typename A4>
+struct Invoker<O, R(T::*)(A0, A1, A2, A3, A4)> {
+ static R invoke(R(T::*f)(A0, A1, A2, A3, A4), const O& o, const A0& a0,
+ const A1& a1, const A2& a2, const A3& a3, const A4& a4) {
+ return (o->*f)(a0, a1, a2, a3, a4);
+ }
+};
+
+template <typename O>
+struct RetainTraits;
+
+template <typename O>
+struct RetainTraits<O*> {
+ // TODO(ajwong): Do we need the "type" typedef? Can't we just use O* in
+ // prebind since O != T?
+ typedef O type;
+ typedef scoped_refptr<O> prebind_type;
+
+ static O* unwrap(O* o) { return o; }
+ static prebind_type MaybeScopedRefptr(O* o) { return o; }
+};
+
+template <typename O>
+struct RetainTraits<UnretainedWrapper<O> > {
+ typedef O type;
+ typedef O* prebind_type;
+
+ static O* unwrap(const UnretainedWrapper<O>& o) { return o.get(); }
+ static prebind_type MaybeScopedRefptr(O* o) { return o; }
+};
+
+template <typename Sig>
+class Thunk;
+
+// TODO(ajwong): Thunk should have a pointer that can be set to refer to a
+// "tracked" object. This should be set/unset by messageloop when it creates
+// the pending task. That should give nearly equivalent functionality to
+// Task inheriting from Tracked.
+template <typename R>
+class Thunk<R(void)> {
+ public:
+ typedef std::tr1::function<R(void)> ThunkType;
+ ThunkType f_;
+
+ explicit Thunk(ThunkType f) : f_(f) {}
+
+ R operator()(void) {
+ return f_();
+ }
+};
+
+template <typename R, typename A0>
+class Thunk<R(A0)> {
+ public:
+ typedef std::tr1::function<R(A0)> ThunkType;
+ ThunkType f_;
+
+ explicit Thunk(ThunkType f) : f_(f) {}
+
+ R operator()(A0& a0) {
+ return f_(a0);
+ }
+};
+
+template <typename R, typename A0, typename A1>
+class Thunk<R(A0, A1)> {
+ public:
+ typedef std::tr1::function<R(A0,A1)> ThunkType;
+ ThunkType f_;
+ std::tr1::function<void(void)> cleanup_;
+
+ explicit Thunk(ThunkType f) : f_(f) {}
+
+ R operator()(const A0& a0, const A1& a1) {
+ return f_(a0, a1);
+ }
+};
+
+// Note that when declaring these template parameters, the types used in the
+// function signature MUST not be shared with the types used in the arguments.
+// If they are shared, then automatic conversions break. For example, this
+// should work:
+//
+// void foo(double d);
+// function<void(void)> f = Prebind(&foo, 2);
+//
+// However, if you declare the template for prebind as follows:
+//
+// template <typename R, typename P0>
+// function<R(void)> Prebind(R(*)(P0), P0 p0);
+//
+// Then the line invoking Prebind will fail because 2 is an integer, and P0 is
+// locked to be a double. If instead, you declare the template to not tie the
+// function signature directly to the parameters, the compiler will have the
+// flexibility to do the right conversion. Thus, the correct declaration will
+// look like this:
+//
+// template <typename R, typename X0, typename P0>
+// function<R(void)> Prebind(R(*)(X0), P0 p0);
+//
+// The signature uses the type X0, and the argument uses the type P0. There is
+// no directly relationship enforced by the template declaration. Instead, we
+// rely on the compiler to output in an error of P0 is not converatble to X0.
+//
+
+
+// 1 -> 0
+template <typename R, typename X0, typename P0>
+Thunk<R(void)>
+Prebind(R(*f)(X0), P0 p0) {
+ return Thunk<R(void)>(std::tr1::bind(f, p0));
+}
+
+// 2 -> 0
+template <typename R, typename X0, typename X1, typename P0, typename P1>
+Thunk<R(void)>
+Prebind(R(*f)(X0, X1), P0 p0, P1 p1) {
+ return Thunk<R(void)>(std::tr1::bind(f, p0, p1));
+}
+
+// 2 -> 1
+template <typename R, typename X0, typename P0, typename A0>
+Thunk<R(A0)>
+Prebind(R(*f)(X0, A0), P0 p0) {
+ return Thunk<R(A0)>(std::tr1::bind(f, p0, std::tr1::placeholders::_1));
+}
+
+// (curry) 1 -> 0
+template <typename R, typename X0, typename P0>
+Thunk<R(void)>
+Prebind(Thunk<R(X0)> f, P0 p0) {
+ return Thunk<R(void)>(std::tr1::bind(f, p0));
+}
+
+// (curry) 2 -> 0
+template <typename R, typename X0, typename X1, typename P0, typename P1>
+Thunk<R(void)>
+Prebind(Thunk<R(X0, X1)> f, P0 p0, P1 p1) {
+ return Thunk<R(void)>(std::tr1::bind(f, p0, p1));
+}
+
+// (curry) 2 -> 1
+template <typename R, typename X0, typename P0, typename A0>
+Thunk<R(A0)>
+Prebind(Thunk<R(X0, A0)> f, P0 p0) {
+ return Thunk<R(A0)>(std::tr1::bind(f, p0, std::tr1::placeholders::_1));
+}
+
+// Method 0 -> 0
+template <typename R, typename O, typename T>
+Thunk<R(void)>
+Prebind(R(O::*f)(), T t) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
willchan no longer on Chromium 2011/01/05 19:44:09 Here you take T, which may be scoped_refptr<O>, an
+ return Thunk<R(void)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(void)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_)));
willchan no longer on Chromium 2011/01/05 19:44:09 MaybeScopedRefptr() basically always forces using
+}
+
+// Method 1 -> 0
+template <typename R, typename O, typename T, typename X0, typename P0>
+Thunk<R(void)>
+Prebind(R(O::*f)(X0), T t, P0 p0) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+
+ return Thunk<R(void)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(X0)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ p0));
+}
+
+// Method 1 -> 1
+template <typename R, typename O, typename T, typename A0>
+Thunk<R(A0)>
+Prebind(R(O::*f)(A0), T t) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+
+ return Thunk<R(void)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(A0)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ std::tr1::placeholders::_1));
+}
+
+// Method 2 -> 0
+template <typename R, typename O, typename T, typename X0, typename X1,
+ typename P0, typename P1>
+Thunk<R(void)>
+Prebind(R(O::*f)(X0, X1), T t, P0 p0, P1 p1) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+ return Thunk<R(void)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(X0,X1)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ p0,
+ p1));
+}
+
+// Method 2 -> 1
+template <typename R, typename O, typename T, typename X0, typename P0,
+ typename A0>
+Thunk<R(A0)>
+Prebind(R(O::*f)(X0, A0), T t, P0 p0) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+ return Thunk<R(A0)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(X0, A0)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ p0,
+ std::tr1::placeholders::_1));
+}
+
+// Method 2 -> 2
+template <typename R, typename O, typename T, typename A0, typename A1>
+Thunk<R(A0, A1)>
+Prebind(R(O::*f)(A0, A1), T t) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+
+ return Thunk<R(A0, A1)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(A0, A1)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ std::tr1::placeholders::_1,
+ std::tr1::placeholders::_2));
+}
+
+// Method 5 -> 2 ...yeah, I skipped a few...got bored of typing it.
+template <typename R, typename O, typename T,
+ typename X0, typename X1, typename X2,
+ typename P0, typename P1, typename P2,
+ typename A0, typename A1>
+Thunk<R(A0, A1)>
+Prebind(R(O::*f)(X0, X1, X2, A0, A1), T t, P0 p0, P1 p1, P2 p2) {
+ typename RetainTraits<T>::type* object_(RetainTraits<T>::unwrap(t));
+
+ return Thunk<R(A0, A1)>(
+ std::tr1::bind(
+ &Invoker<typename RetainTraits<T>::prebind_type,
+ R(O::*)(X0, X1, X2, A0, A1)>::invoke,
+ f,
+ RetainTraits<T>::MaybeScopedRefptr(object_),
+ p0, p1, p2,
+ std::tr1::placeholders::_1,
+ std::tr1::placeholders::_2));
+}
+
+// Wraps a Thunk to automatically cancel a task when the ThunkCanceller is
+// deleted. This allows a caller to "nop" all outstanding callbacks registered
+// with the ThunkCanceller.
+//
+// Note that if you're also looking at the Closure code, this is nearly
+// identical to ClosureCanceller. In fact, it can be used interchangeably, but
+// I put a forked version here just for completeness.
+class ThunkCanceller {
+ public:
+ ThunkCanceller() : cancel_state_(new CancelState()) {}
+
+ ~ThunkCanceller() {
+ cancel_state_->is_canceled = true;
+ }
+
+ template <typename T>
+ Thunk<void(void)> Wrap(T c) {
+ using std::tr1::bind;
+ return base::Thunk<void(void)>(
+ Prebind(&ThunkCanceller::Run<T>, cancel_state_, c));
+ }
+
+ bool empty() const {
+ // The ThunkCanceller has the only reference, no tasks are outstanding.
+ return cancel_state_->HasOneRef();
+ }
+
+ void RevokeAll() {
+ // Cancel all outstanding, then create a new cancel state so this object may
+ // be reused.
+ cancel_state_->is_canceled = true;
+ cancel_state_ = new CancelState();
+ }
+
+ private:
+ // The ecopedRunnableMethodFactory uses a WeakPtr. This is because it is
+ // actually reimplementing the storage for the task object, so a pointer is
+ // necessary and thus WeakPtr can be overloaded to serve as a flag.
+ //
+ // In this design, it seems overkill to use WeakPtr instead of a simple flag
+ // class (which WeakPtr eventually devolves into anyways).
+ class CancelState : public RefCounted<CancelState> {
+ public:
+ CancelState() : is_canceled(false) {}
+
+ bool is_canceled;
+ };
+
+ template <typename T>
+ static void Run(scoped_refptr<CancelState> cancel_state, T c) {
+ if (!cancel_state->is_canceled) {
+ c();
+ }
+ }
+
+ scoped_refptr<CancelState> cancel_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThunkCanceller);
+};
+
+} // namespace base
+
+#endif // BASE_PREBIND_H
« no previous file with comments | « base/message_loop.cc ('k') | base/task.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698