1// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_CALLBACK_OLD_H_
6#define BASE_CALLBACK_OLD_H_
7#pragma once
8
9#include "base/memory/raw_scoped_refptr_mismatch_checker.h"
10#include "base/tuple.h"
11
12// Callback --------------------------------------------------------------------
13//
14// A Callback is like a Task but with unbound parameters. It is basically an
15// object-oriented function pointer.
16//
17// Callbacks are designed to work with Tuples.  A set of helper functions and
18// classes is provided to hide the Tuple details from the consumer.  Client
19// code will generally work with the CallbackRunner base class, which merely
20// provides a Run method and is returned by the New* functions. This allows
21// users to not care which type of class implements the callback, only that it
22// has a certain number and type of arguments.
23//
24// The implementation of this is done by CallbackImpl, which inherits
25// CallbackStorage to store the data. This allows the storage of the data
26// (requiring the class type T) to be hidden from users, who will want to call
27// this regardless of the implementor's type T.
28//
29// Note that callbacks currently have no facility for cancelling or abandoning
30// them. We currently handle this at a higher level for cases where this is
31// necessary. The pointer in a callback must remain valid until the callback
32// is made.
33//
34// Like Task, the callback executor is responsible for deleting the callback
35// pointer once the callback has executed.
36//
37// Example client usage:
38//   void Object::DoStuff(int, string);
39//   Callback2<int, string>::Type* callback =
40//       NewCallback(obj, &Object::DoStuff);
41//   callback->Run(5, string("hello"));
42//   delete callback;
43// or, equivalently, using tuples directly:
44//   CallbackRunner<Tuple2<int, string> >* callback =
45//       NewCallback(obj, &Object::DoStuff);
46//   callback->RunWithParams(MakeTuple(5, string("hello")));
47//
48// There is also a 0-args version that returns a value.  Example:
49//   int Object::GetNextInt();
50//   CallbackWithReturnValue<int>::Type* callback =
51//       NewCallbackWithReturnValue(obj, &Object::GetNextInt);
52//   int next_int = callback->Run();
53//   delete callback;
54
55// Base for all Callbacks that handles storage of the pointers.
56template <class T, typename Method>
57class CallbackStorage {
58 public:
59  CallbackStorage(T* obj, Method meth) : obj_(obj), meth_(meth) {
60  }
61
62 protected:
63  T* obj_;
64  Method meth_;
65};
66
67// Interface that is exposed to the consumer, that does the actual calling
68// of the method.
69template <typename Params>
70class CallbackRunner {
71 public:
72  typedef Params TupleType;
73
74  virtual ~CallbackRunner() {}
75  virtual void RunWithParams(const Params& params) = 0;
76
77  // Convenience functions so callers don't have to deal with Tuples.
78  inline void Run() {
79    RunWithParams(Tuple0());
80  }
81
82  template <typename Arg1>
83  inline void Run(const Arg1& a) {
84    RunWithParams(Params(a));
85  }
86
87  template <typename Arg1, typename Arg2>
88  inline void Run(const Arg1& a, const Arg2& b) {
89    RunWithParams(Params(a, b));
90  }
91
92  template <typename Arg1, typename Arg2, typename Arg3>
93  inline void Run(const Arg1& a, const Arg2& b, const Arg3& c) {
94    RunWithParams(Params(a, b, c));
95  }
96
97  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
98  inline void Run(const Arg1& a, const Arg2& b, const Arg3& c, const Arg4& d) {
99    RunWithParams(Params(a, b, c, d));
100  }
101
102  template <typename Arg1, typename Arg2, typename Arg3,
103            typename Arg4, typename Arg5>
104  inline void Run(const Arg1& a, const Arg2& b, const Arg3& c,
105                  const Arg4& d, const Arg5& e) {
106    RunWithParams(Params(a, b, c, d, e));
107  }
108};
109
110template <class T, typename Method, typename Params>
111class CallbackImpl : public CallbackStorage<T, Method>,
112                     public CallbackRunner<Params> {
113 public:
114  CallbackImpl(T* obj, Method meth) : CallbackStorage<T, Method>(obj, meth) {
115  }
116  virtual void RunWithParams(const Params& params) {
117    // use "this->" to force C++ to look inside our templatized base class; see
118    // Effective C++, 3rd Ed, item 43, p210 for details.
119    DispatchToMethod(this->obj_, this->meth_, params);
120  }
121};
122
123// 0-arg implementation
124struct Callback0 {
125  typedef CallbackRunner<Tuple0> Type;
126};
127
128template <class T>
129typename Callback0::Type* NewCallback(T* object, void (T::*method)()) {
130  return new CallbackImpl<T, void (T::*)(), Tuple0 >(object, method);
131}
132
133// 1-arg implementation
134template <typename Arg1>
135struct Callback1 {
136  typedef CallbackRunner<Tuple1<Arg1> > Type;
137};
138
139template <class T, typename Arg1>
140typename Callback1<Arg1>::Type* NewCallback(T* object,
141                                            void (T::*method)(Arg1)) {
142  return new CallbackImpl<T, void (T::*)(Arg1), Tuple1<Arg1> >(object, method);
143}
144
145// 2-arg implementation
146template <typename Arg1, typename Arg2>
147struct Callback2 {
148  typedef CallbackRunner<Tuple2<Arg1, Arg2> > Type;
149};
150
151template <class T, typename Arg1, typename Arg2>
152typename Callback2<Arg1, Arg2>::Type* NewCallback(
153    T* object,
154    void (T::*method)(Arg1, Arg2)) {
155  return new CallbackImpl<T, void (T::*)(Arg1, Arg2),
156      Tuple2<Arg1, Arg2> >(object, method);
157}
158
159// 3-arg implementation
160template <typename Arg1, typename Arg2, typename Arg3>
161struct Callback3 {
162  typedef CallbackRunner<Tuple3<Arg1, Arg2, Arg3> > Type;
163};
164
165template <class T, typename Arg1, typename Arg2, typename Arg3>
166typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
167    T* object,
168    void (T::*method)(Arg1, Arg2, Arg3)) {
169  return new CallbackImpl<T,  void (T::*)(Arg1, Arg2, Arg3),
170      Tuple3<Arg1, Arg2, Arg3> >(object, method);
171}
172
173// 4-arg implementation
174template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
175struct Callback4 {
176  typedef CallbackRunner<Tuple4<Arg1, Arg2, Arg3, Arg4> > Type;
177};
178
179template <class T, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
180typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
181    T* object,
182    void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
183  return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4),
184      Tuple4<Arg1, Arg2, Arg3, Arg4> >(object, method);
185}
186
187// 5-arg implementation
188template <typename Arg1, typename Arg2, typename Arg3,
189          typename Arg4, typename Arg5>
190struct Callback5 {
191  typedef CallbackRunner<Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> > Type;
192};
193
194template <class T, typename Arg1, typename Arg2,
195          typename Arg3, typename Arg4, typename Arg5>
196typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
197    T* object,
198    void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
199  return new CallbackImpl<T, void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
200      Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(object, method);
201}
202
203// An UnboundMethod is a wrapper for a method where the actual object is
204// provided at Run dispatch time.
205template <class T, class Method, class Params>
206class UnboundMethod {
207 public:
208  UnboundMethod(Method m, const Params& p) : m_(m), p_(p) {
209    COMPILE_ASSERT(
210        (base::internal::ParamsUseScopedRefptrCorrectly<Params>::value),
211        badunboundmethodparams);
212  }
213  void Run(T* obj) const {
214    DispatchToMethod(obj, m_, p_);
215  }
216 private:
217  Method m_;
218  Params p_;
219};
220
221// Return value implementation with no args.
222template <typename ReturnValue>
223struct CallbackWithReturnValue {
224  class Type {
225   public:
226    virtual ~Type() {}
227    virtual ReturnValue Run() = 0;
228  };
229};
230
231template <class T, typename Method, typename ReturnValue>
232class CallbackWithReturnValueImpl
233    : public CallbackStorage<T, Method>,
234      public CallbackWithReturnValue<ReturnValue>::Type {
235 public:
236  CallbackWithReturnValueImpl(T* obj, Method meth)
237      : CallbackStorage<T, Method>(obj, meth) {}
238
239  virtual ReturnValue Run() {
240    return (this->obj_->*(this->meth_))();
241  }
242
243 protected:
244  virtual ~CallbackWithReturnValueImpl() {}
245};
246
247template <class T, typename ReturnValue>
248typename CallbackWithReturnValue<ReturnValue>::Type*
249NewCallbackWithReturnValue(T* object, ReturnValue (T::*method)()) {
250  return new CallbackWithReturnValueImpl<T, ReturnValue (T::*)(), ReturnValue>(
251      object, method);
252}
253
254#endif  // BASE_CALLBACK_OLD_H_
255