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// ScopedCallbackFactory helps in cases where you wish to allocate a Callback
6// (see base/callback.h), but need to prevent any pending callbacks from
7// executing when your object gets destroyed.
8//
9// EXAMPLE:
10//
11//  void GatherDataAsynchronously(Callback1<Data>::Type* callback);
12//
13//  class MyClass {
14//   public:
15//    MyClass() : factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
16//    }
17//
18//    void Process() {
19//      GatherDataAsynchronously(factory_.NewCallback(&MyClass::GotData));
20//    }
21//
22//   private:
23//    void GotData(const Data& data) {
24//      ...
25//    }
26//
27//    base::ScopedCallbackFactory<MyClass> factory_;
28//  };
29//
30// In the above example, the Process function calls GatherDataAsynchronously to
31// kick off some asynchronous processing that upon completion will notify a
32// callback.  If in the meantime, the MyClass instance is destroyed, when the
33// callback runs, it will notice that the MyClass instance is dead, and it will
34// avoid calling the GotData method.
35
36#ifndef BASE_MEMORY_SCOPED_CALLBACK_FACTORY_H_
37#define BASE_MEMORY_SCOPED_CALLBACK_FACTORY_H_
38
39#include "base/callback.h"
40#include "base/memory/weak_ptr.h"
41
42namespace base {
43
44template <class T>
45class ScopedCallbackFactory {
46 public:
47  explicit ScopedCallbackFactory(T* obj) : weak_factory_(obj) {
48  }
49
50  typename Callback0::Type* NewCallback(
51      void (T::*method)()) {
52    return new CallbackImpl<void (T::*)(), Tuple0 >(
53        weak_factory_.GetWeakPtr(), method);
54  }
55
56  template <typename Arg1>
57  typename Callback1<Arg1>::Type* NewCallback(
58      void (T::*method)(Arg1)) {
59    return new CallbackImpl<void (T::*)(Arg1), Tuple1<Arg1> >(
60        weak_factory_.GetWeakPtr(), method);
61  }
62
63  template <typename Arg1, typename Arg2>
64  typename Callback2<Arg1, Arg2>::Type* NewCallback(
65      void (T::*method)(Arg1, Arg2)) {
66    return new CallbackImpl<void (T::*)(Arg1, Arg2), Tuple2<Arg1, Arg2> >(
67        weak_factory_.GetWeakPtr(), method);
68  }
69
70  template <typename Arg1, typename Arg2, typename Arg3>
71  typename Callback3<Arg1, Arg2, Arg3>::Type* NewCallback(
72      void (T::*method)(Arg1, Arg2, Arg3)) {
73    return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3),
74                            Tuple3<Arg1, Arg2, Arg3> >(
75        weak_factory_.GetWeakPtr(), method);
76  }
77
78  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4>
79  typename Callback4<Arg1, Arg2, Arg3, Arg4>::Type* NewCallback(
80      void (T::*method)(Arg1, Arg2, Arg3, Arg4)) {
81    return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4),
82                            Tuple4<Arg1, Arg2, Arg3, Arg4> >(
83        weak_factory_.GetWeakPtr(), method);
84  }
85
86  template <typename Arg1, typename Arg2, typename Arg3, typename Arg4,
87            typename Arg5>
88  typename Callback5<Arg1, Arg2, Arg3, Arg4, Arg5>::Type* NewCallback(
89      void (T::*method)(Arg1, Arg2, Arg3, Arg4, Arg5)) {
90    return new CallbackImpl<void (T::*)(Arg1, Arg2, Arg3, Arg4, Arg5),
91                            Tuple5<Arg1, Arg2, Arg3, Arg4, Arg5> >(
92        weak_factory_.GetWeakPtr(), method);
93  }
94
95  void RevokeAll() { weak_factory_.InvalidateWeakPtrs(); }
96  bool HasPendingCallbacks() const { return weak_factory_.HasWeakPtrs(); }
97
98 private:
99  template <typename Method>
100  class CallbackStorage {
101   public:
102    CallbackStorage(const WeakPtr<T>& obj, Method meth)
103        : obj_(obj),
104          meth_(meth) {
105    }
106
107   protected:
108    WeakPtr<T> obj_;
109    Method meth_;
110  };
111
112  template <typename Method, typename Params>
113  class CallbackImpl : public CallbackStorage<Method>,
114                       public CallbackRunner<Params> {
115   public:
116    CallbackImpl(const WeakPtr<T>& obj, Method meth)
117        : CallbackStorage<Method>(obj, meth) {
118    }
119    virtual void RunWithParams(const Params& params) {
120      // Use "this->" to force C++ to look inside our templatized base class;
121      // see Effective C++, 3rd Ed, item 43, p210 for details.
122      if (!this->obj_)
123        return;
124      DispatchToMethod(this->obj_.get(), this->meth_, params);
125    }
126  };
127
128  WeakPtrFactory<T> weak_factory_;
129};
130
131}  // namespace base
132
133#endif  // BASE_MEMORY_SCOPED_CALLBACK_FACTORY_H_
134