diff options
Diffstat (limited to 'third_party/cld/base/callback.h')
-rw-r--r-- | third_party/cld/base/callback.h | 308 |
1 files changed, 308 insertions, 0 deletions
diff --git a/third_party/cld/base/callback.h b/third_party/cld/base/callback.h new file mode 100644 index 0000000..d4f4644 --- /dev/null +++ b/third_party/cld/base/callback.h @@ -0,0 +1,308 @@ +// Copyright (c) 2006-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. + +// Callback classes provides a generic interface for classes requiring +// callback from other classes. +// We support callbacks with 0, 1, 2, 3, and 4 arguments. +// Closure -- provides "void Run()" +// Callback1<T1> -- provides "void Run(T1)" +// Callback2<T1,T2> -- provides "void Run(T1, T2)" +// Callback3<T1,T2,T3> -- provides "void Run(T1, T2, T3)" +// Callback4<T1,T2,T3,T4> -- provides "void Run(T1, T2, T3, T4)" +// +// In addition, ResultCallback classes provide a generic interface for +// callbacks that return a value. +// ResultCallback<R> -- provides "R Run()" +// ResultCallback1<R,T1> -- provides "R Run(T1)" +// ResultCallback2<R,T1,T2> -- provides "R Run(T1, T2)" +// ResultCallback3<R,T1,T2,T3> -- provides "R Run(T1, T2, T3)" +// ResultCallback4<R,T1,T2,T3,T4> -- provides "R Run(T1, T2, T3, T4)" + +// We provide a convenient mechanism, NewCallback, for generating one of these +// callbacks given an object pointer, a pointer to a member +// function with the appropriate signature in that object's class, +// and some optional arguments that can be bound into the callback +// object. The mechanism also works with just a function pointer. +// +// Note: there are two types of arguments passed to the callback method: +// * "pre-bound arguments" - supplied when the callback object is created +// * "call-time arguments" - supplied when the callback object is invoked +// +// These two types correspond to "early binding" and "late +// binding". An argument whose value is known when the callback is +// created ("early") can be pre-bound (a.k.a. "Curried"), You can +// combine pre-bound and call-time arguments in different ways. For +// example, invoking a callback with 3 pre-bound arguments and 1 +// call-time argument will have the same effect as invoking a callback +// with 2 pre-bound arguments and 2 call-time arguments, or 4 +// pre-bound arguments and no call-time arguments. This last case is +// often useful; a callback with no call-time arguments is a Closure; +// these are used in many places in the Google libraries, e.g., "done" +// closures. See the examples below. +// +// WARNING: In the current implementation (or perhaps with the current +// compiler) NewCallback() is pickier about the types of pre-bound arguments +// than you might expect. The types must match exactly, rather than merely +// being compatible. +// For example, if you pre-bind an argument with the "const" specifier, +// make sure that the actual parameter passed to NewCallback also has the +// const specifier. If you don't you'll get an error about +// passing a your function "as argument 1 of NewCallback(void (*)())". +// Using a method or function that has reference arguments among its pre-bound +// arguments may not always work. +// +// Examples: +// +// void Call0(Closure* cb) { cb->Run(); } +// void Call1(Callback1<int>* cb, int a) { cb->Run(a); } +// void Call2(Callback2<int, float>* cb, int a, float f) { cb->Run(a, f); } +// float Call3(ResultCallback1<float, int>* cb, int a) { return cb->Run(a); } +// +// class Foo { +// public: +// void A(int a); +// void B(int a, float f); +// void C(const char* label, int a, float f); +// float D(int a); +// }; +// void F0(int a); +// void F1(int a, float f); +// void F2(const char *label, int a, float f); +// float F3(int a); +// float v; +// +// // Run stuff immediately +// // calling a method +// Foo* foo = new Foo; +// +// NewCallback(foo, &Foo::A) ->Run(10); // 0 [pre-bound] + 1 [call-time] +// == NewCallback(foo, &Foo::A, 10) ->Run(); // 1 + 0 +// == foo->A(10); +// +// NewCallback(foo, &Foo::B) ->Run(10, 3.0f); // 0 + 2 +// == NewCallback(foo, &Foo::B, 10) ->Run(3.0f); // 1 + 1 +// == NewCallback(foo, &Foo::B, 10, 3.0f) ->Run(); // 2 + 0 +// == foo->B(10, 3.0f); +// +// NewCallback(foo, &Foo::C) ->Run("Y", 10, 3.0f); // 0 + 3 +// == NewCallback(foo, &Foo::C, "Y") ->Run(10, 3.0f); // 1 + 2 +// == NewCallback(foo, &Foo::C, "Y", 10) ->Run(3.0f); // 2 + 1 +// == NewCallback(foo, &Foo::C, "Y", 10, 3.0f) ->Run(); // 3 + 0 +// == foo->C("Y", 10, 3.0f); +// +// v = NewCallback(foo, &Foo::D) ->Run(10); == v = foo->D(10) +// +// // calling a function +// NewCallback(F0) ->Run(10); // == F0(10) // 0 + 1 +// NewCallback(F0, 10) ->Run(); // == F0(10) // 1 + 0 +// NewCallback(F1) ->Run(10, 3.0f); // == F1(10, 3.0f) +// NewCallback(F2, "X") ->Run(10, 3.0f); // == F2("X", 10, 3.0f) +// NewCallback(F2, "Y") ->Run(10, 3.0f); // == F2("Y", 10, 3.0f) +// v = NewCallback(F3) ->Run(10); // == v = F3(10) +// +// +// // Pass callback object to somebody else, who runs it. +// // Calling a method: +// Call1(NewCallback(foo, &Foo::A), 10); // 0 + 1 +// == Call0(NewCallback(foo, &Foo::A, 10) ); // 1 + 0 +// == foo->A(10) +// +// Call2(NewCallback(foo, &Foo::B), 10, 3.0f); // 0 + 2 +// == Call1(NewCallback(foo, &Foo::B, 10), 3.0f); // 1 + 1 +// == Call0(NewCallback(foo, &Foo::B, 10, 30.f) ); // 2 + 0 +// == foo->B(10, 3.0f) +// +// Call2(NewCallback(foo, &Foo::C, "X"), 10, 3.0f); == foo->C("X", 10, 3.0f) +// Call2(NewCallback(foo, &Foo::C, "Y"), 10, 3.0f); == foo->C("Y", 10, 3.0f) +// +// // Calling a function: +// Call1(NewCallback(F0), 10); // 0 + 1 +// == Call0(NewCallback(F0, 10) ); // 1 + 0 +// == F0(10); +// +// Call2(NewCallback(F1), 10, 3.0f); // == F1(10, 3.0f) +// Call2(NewCallback(F2, "X"), 10, 3.0f); // == F2("X", 10, 3.0f) +// Call2(NewCallback(F2, "Y"), 10, 3.0f); // == F2("Y", 10, 3.0f) +// v = Call3(NewCallback(F3), 10); // == v = F3(10) +// +// Example of a "done" closure: +// +// SelectServer ss; +// Closure* done = NewCallback(&ss, &SelectServer::MakeLoopExit); +// ProcessMyControlFlow(..., done); +// ss.Loop(); +// ... +// +// The following WILL NOT WORK: +// NewCallback(F2, (char *) "Y") ->Run(10, 3.0f); +// It gets the error: +// passing `void (*)(const char *, int, float)' as argument 1 of +// `NewCallback(void (*)())' +// The problem is that "char *" is not an _exact_ match for +// "const char *", even though it's normally a legal implicit +// conversion. +// +// +// The callback objects generated by NewCallback are self-deleting: +// i.e., they call the member function, and then delete themselves. +// If you want a callback that does not delete itself every time +// it runs, use "NewPermanentCallback" instead of "NewCallback". +// +// All the callback/closure classes also provide +// virtual void CheckIsRepeatable() const; +// It crashes if (we know for sure that) the callback's Run method +// can not be called an arbitrary number of times (including 0). +// It crashes for all NewCallback() generated callbacks, +// does not crash for NewPermanentCallback() generated callbacks, +// and although by default it does not crash for all callback-derived classes, +// for these new types of callbacks, the callback writer is encouraged to +// redefine this method appropriately. +// +// CAVEAT: Interfaces that accept callback pointers should clearly document +// if they might call Run methods of those callbacks multiple times +// (and use "c->CheckIsRepeatable();" as an active precondition check), +// or if they call the callbacks exactly once or potentially not at all, +// as well as if they take ownership of the passed callbacks +// (i.e. might manually deallocate them without calling their Run methods). +// The clients can then provide properly allocated and behaving callbacks +// (e.g. choose between NewCallback, NewPermanentCallback, or a custom object). +// Obviously, one should also be careful to ensure that the data a callback +// points to and needs for its Run method is still live when +// the Run method might be called. +// +// MOTIVATION FOR CALLBACK OBJECTS +// ------------------------------- +// It frees service providers from depending on service requestors by +// calling a generic callback other than a callback which depends on +// the service requestor (typically its member function). As a +// result, service provider classes can be developed independently. +// +// Typical usage: Suppose class A wants class B to do something and +// notify A when it is done. As part of the notification, it wants +// to be given a boolean that says what happened. +// +// class A { +// public: +// void RequestService(B* server) { +// ... +// server->StartService(NewCallback(this, &A::ServiceDone), other_args)); +// // the new callback deletes itself after it runs +// } +// void ServiceDone(bool status) {...} +// }; +// +// Class B { +// public: +// void StartService(Callback1<bool>* cb, other_args) : cb_(cb) { ...} +// void FinishService(bool result) { ...; cb_->Run(result); } +// private: +// Callback1<bool>* cb_; +// }; +// +// As can be seen, B is completely independent of A. (Of course, they +// have to agree on callback data type.) +// +// The result of NewCallback() is thread-compatible. The result of +// NewPermanentCallback() is thread-safe if the call its Run() method +// represents is thread-safe and thread-compatible otherwise. +// +// Other modules associated with callbacks may be found in //util/callback +// +// USING CALLBACKS WITH TRACECONTEXT +// --------------------------------- +// Callbacks generated by NewCallback() automatically propagate trace +// context. Callbacks generated by NewPermanentCallback() do not. For +// manually-derived subclasses of Closure and CallbackN, you may decide +// to propagate TraceContext as follows. +// +// struct MyClosure : public Closure { +// MyClosure() +// : Closure(TraceContext::THREAD) { } +// +// void Run() { +// TraceContext *tc = TraceContext::Thread(); +// tc->Swap(&trace_context_); +// DoMyOperation() +// tc->Swap(&trace_context_); +// delete this; +// } +// }; + +#ifndef _CALLBACK_H_ +#define _CALLBACK_H_ + +#include <functional> + +// The actual callback classes and various NewCallback() implementations +// are automatically generated by base/generate-callback-specializations.py. +// We include that output here. +#include "base/callback-specializations.h" + +// A new barrier closure executes another closure after it has been +// invoked N times, and then deletes itself. +// +// If "N" is zero, the supplied closure is executed immediately. +// Barrier closures are thread-safe. They use an atomic operation to +// guarantee a correct count. +// +// REQUIRES N >= 0. +extern Closure* NewBarrierClosure(int N, Closure* done_closure); + +// Function that does nothing; can be used to make new no-op closures: +// NewCallback(&DoNothing) +// NewPermanentCallback(&DoNothing) +// This is a replacement for the formerly available TheNoopClosure() primitive. +extern void DoNothing(); + +// AutoClosureRunner executes a closure upon deletion. This class +// is similar to scoped_ptr: it is typically stack-allocated and can be +// used to perform some type of cleanup upon exiting a block. +// +// Note: use of AutoClosureRunner with Closures that must be executed at +// specific points is discouraged, since the point at which the Closure +// executes is not explicitly marked. For example, consider a Closure +// that should execute after a mutex has been released. The following +// code looks correct, but executes the Closure too early (before release): +// { +// MutexLock l(...); +// AutoClosureRunner r(run_after_unlock); +// ... +// } +// AutoClosureRunner is primarily intended for cleanup operations that +// are relatively independent from other code. +// +// The Reset() method replaces the callback with a new callback. The new +// callback can be supplied as NULL to disable the AutoClosureRunner. This is +// intended as part of a strategy to execute a callback at all exit points of a +// method except where Reset() was called. This method must be used only with +// non-permanent callbacks. The Release() method disables and returns the +// callback, instead of deleting it. +class AutoClosureRunner { + private: + Closure* closure_; + public: + explicit AutoClosureRunner(Closure* c) : closure_(c) {} + ~AutoClosureRunner() { if (closure_) closure_->Run(); } + void Reset(Closure *c) { delete closure_; closure_ = c; } + Closure* Release() { Closure* c = closure_; closure_ = NULL; return c; } + private: + DISALLOW_EVIL_CONSTRUCTORS(AutoClosureRunner); +}; + +// DeletePointerClosure can be used to create a closure that calls delete +// on a pointer. Here is an example: +// +// thread->Add(DeletePointerClosure(expensive_to_delete)); +// +template<typename T> +void DeletePointer(T* p) { + delete p; +} + +template<typename T> +Closure* DeletePointerClosure(T* p) { + return NewCallback(&DeletePointer<T>, p); +} + +#endif /* _CALLBACK_H_ */ |