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

Unified Diff: base/closure.h

Issue 6094005: Create "Prebind" a wrapper to tr1::bind. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/base
Patch Set: Closure example ported to Prebinds Created 10 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 | « base/base.gypi ('k') | base/message_loop.h » ('j') | base/prebind.h » ('J')
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/closure.h
diff --git a/base/closure.h b/base/closure.h
new file mode 100644
index 0000000000000000000000000000000000000000..c720349f6439ff454a2f7d531b9cfd32f896c3d2
--- /dev/null
+++ b/base/closure.h
@@ -0,0 +1,339 @@
+// Copyright (c) 2009 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_CLOSURE_H_
+#define BASE_CLOSURE_H_
+#pragma once
+
+#include <tr1/functional>
+
+#include "base/ref_counted.h"
+#include "base/scoped_ptr.h"
+#include "base/tracked.h"
+
+namespace base {
+
+extern void DoNothing(); // Defined in base/task.h.
+
+// We are trying to mimic value-object semantics of tr1::function in the
+// Closure API. Thus, we need to detach the tracked object, and some other
+// state as a shared state.
+//
+// As is, there are some threadsafety issues, but the general idea should be
+// correct.
+class ClosureState : public RefCountedThreadSafe<ClosureState> {
+ public:
+ // TODO(ajwong): Put these behind an accessor.
+ ::std::tr1::function<void()> release_thunk_;
+
+ explicit ClosureState(tracked_objects::Tracked* tracked)
+ : release_thunk_(&DoNothing),
+ tracked_(tracked) {
+ }
+
+ ~ClosureState() {
+ release_thunk_();
+ }
+
+ tracked_objects::Tracked* tracked() const {
+ return tracked_.get();
+ }
+
+ private:
+ scoped_ptr<tracked_objects::Tracked> tracked_;
+};
+
+
+// These are needed to implement a wrapper that disables refcounting on
+// objects used with a Closure.
+//
+// TODO(ajwong): If we implement this similar to std::tr1::reference_wrapper we
+// can probably simplify the ObjectTraits below and remove one specialization.
+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);
+}
+
+// Note, Closure does not support binding a member function to a reference
+// object. That is, this will not compile:
+//
+// Foo f;
+// Closure c = Closure(&Foo::func, f);
+//
+// You have to pass in a pointer to it.
+//
+// Foo f;
+// Closure c = Closure(&Foo::func, &f);
+//
+// We can make the syntax work out, but it's extra complex and given that we
+// expect Closure's to refcount the member functions they abstract unless
+// explicitly told not to, allowing pass by reference doesn't make much sense.
+class Closure {
+ public:
+
+// --- Traits object defintions --
+// This handle changing the syntax, and refcounting for the various types of
+// parameters that can be passed in.
+
+ template <typename O, bool is_member_function_pointer>
+ struct ObjectTraits;
+
+ // Handle regular pointers.
+ template <typename O>
+ struct ObjectTraits<O*, true> {
+ static O* Unwrap(O* o) {
+ return o;
+ }
+
+ static ::std::tr1::function<void()> RefThunk(O* o) {
willchan no longer on Chromium 2011/01/05 00:30:17 Do we really need to use Thunks here? Is the flex
awong 2011/01/05 03:17:42 Looking at this more, I don't think it's quite tha
willchan no longer on Chromium 2011/01/05 19:44:09 I never said template parameter. I said parameter
+ return ::std::tr1::bind(&O::AddRef, o);
+ }
+ static ::std::tr1::function<void()> ReleaseThunk(O* o) {
+ return ::std::tr1::bind(&O::Release, o);
+ }
+ };
+
+ // If it's not a member function, there is no refcounting, and pass through
+ // the object.
+ template <typename O>
+ struct ObjectTraits<O, false> {
+ static O Unwrap(O o) {
+ return o;
+ }
+
+ static ::std::tr1::function<void()> RefThunk(O o) {
+ return ::std::tr1::bind(&DoNothing);
+ }
+ static ::std::tr1::function<void()> ReleaseThunk(O o) {
+ return ::std::tr1::bind(&DoNothing);
+ }
+ };
+
+ // Object wrapped in Unretained() should not refcount anything, and should
+ // unwrap to a pointer to their type.
+ template <typename O>
+ struct ObjectTraits<UnretainedWrapper<O>, true> {
+ static O* Unwrap(UnretainedWrapper<O> o) {
+ return o.get();
+ }
+
+ static ::std::tr1::function<void()> RefThunk(UnretainedWrapper<O> o) {
+ return ::std::tr1::bind(&DoNothing);
+ }
+
+ static ::std::tr1::function<void()> ReleaseThunk(UnretainedWrapper<O> o) {
+ return ::std::tr1::bind(&DoNothing);
+ }
+ };
+
+
+// ---- Constructors ----
+ template <typename Sig>
+ Closure(Sig f)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ func_ = ::std::tr1::bind(f);
+ state_->release_thunk_ = ::std::tr1::bind(&DoNothing);
+ }
+
+ template <typename Sig, typename A1>
+ Closure(Sig f, A1 a1)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1));
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ template <typename Sig, typename A1, typename A2>
+ Closure(Sig f, A1 a1, A2 a2)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
+ a2);
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ template <typename Sig, typename A1, typename A2, typename A3>
+ Closure(Sig f, A1 a1, A2 a2, A3 a3)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
+ a2,
+ a3);
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ template <typename Sig, typename A1, typename A2, typename A3,
+ typename A4>
+ Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
+ a2,
+ a3,
+ a4);
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ template <typename Sig, typename A1, typename A2, typename A3,
+ typename A4, typename A5>
+ Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
+ a2,
+ a3,
+ a4,
+ a5);
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ template <typename Sig, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6>
+ Closure(Sig f, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ using std::tr1::is_member_function_pointer;
+ func_ = ::std::tr1::bind(
+ f,
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::Unwrap(a1),
+ a2,
+ a3,
+ a4,
+ a5,
+ a6);
+
+ // Handle the refcounting.
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::RefThunk(a1)();
+ state_->release_thunk_ =
+ ObjectTraits<A1, is_member_function_pointer<Sig>::value >::
+ ReleaseThunk(a1);
+ }
+
+ // This is to make Closure mimic tr1::function<void()>'s interface. It could
+ // also just be void Run(), but mimicing the interface allows us to
+ // substitute Closure in whereever tr1::function<void()> could be used in the
+ // tr1 libraries.
+ void operator()() { func_(); }
+
+ tracked_objects::Tracked* tracked() {
+ return state_->tracked();
+ }
+
+ void Cancel() {
+ func_ = ::std::tr1::bind(&DoNothing);
willchan no longer on Chromium 2011/01/05 00:30:17 can't this just be std::tr1::function()?
awong 2011/01/05 03:17:42 That actually asserted. However, I can remove the
willchan no longer on Chromium 2011/01/05 19:44:09 Oh really? Ok, whatever.
+ }
+
+ private:
+ // Don't let us convert from tr1 quickly.
+ Closure(::std::tr1::function<void(void)> f)
+ : state_(new ClosureState(new tracked_objects::Tracked())) {
+ func_ = ::std::tr1::bind(f);
+ }
+
+ // This is the tr1 function pointer.
+ ::std::tr1::function<void()> func_;
+
+ scoped_refptr<ClosureState> state_;
+};
+
+// Wraps a Closure or a tr1::function<void()) to automatically cancel a task
+// when the ClosureCanceller is deleted. This allows a caller to "nop" all
+// outstanding callbacks registered with the ClosureCanceller.
+class ClosureCanceller {
+ public:
+ ClosureCanceller() : cancel_state_(new CancelState()) {}
+
+ ~ClosureCanceller() {
+ cancel_state_->is_canceled = true;
+ }
+
+ template <typename T>
+ Closure Wrap(T c) {
+ using ::std::tr1::bind;
+ return base::Closure(bind(&ClosureCanceller::Run<T>, cancel_state_, c));
+ }
+
+ bool empty() const {
+ // The ClosureCanceller 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 ScopedRunnableMethodFactory 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_;
+};
+
+} // namespace base
+
+#endif // BASE_CLOSURE_H_
« no previous file with comments | « base/base.gypi ('k') | base/message_loop.h » ('j') | base/prebind.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698