Roll breakpad a513e85:7caf028 (svn 1384:1385)
[chromium-blink-merge.git] / base / callback_list.h.pump
blobd7f84736c15756851e52a3c256d694f7de7c44b3
1 $$ This is a pump file for generating file templates.  Pump is a python
2 $$ script that is part of the Google Test suite of utilities.  Description
3 $$ can be found here:
4 $$
5 $$ http://code.google.com/p/googletest/wiki/PumpManual
6 $$
8 $$ See comment for MAX_ARITY in base/bind.h.pump.
9 $var MAX_ARITY = 7
11 // Copyright 2013 The Chromium Authors. All rights reserved.
12 // Use of this source code is governed by a BSD-style license that can be
13 // found in the LICENSE file.
15 #ifndef BASE_CALLBACK_LIST_H_
16 #define BASE_CALLBACK_LIST_H_
18 #include <list>
20 #include "base/basictypes.h"
21 #include "base/callback.h"
22 #include "base/callback_internal.h"
23 #include "base/compiler_specific.h"
24 #include "base/logging.h"
25 #include "base/memory/scoped_ptr.h"
27 // OVERVIEW:
29 // A container for a list of callbacks.  Unlike a normal STL vector or list,
30 // this container can be modified during iteration without invalidating the
31 // iterator. It safely handles the case of a callback removing itself
32 // or another callback from the list while callbacks are being run.
34 // TYPICAL USAGE:
36 // class MyWidget {
37 //  public:
38 //   ...
40 //   typedef base::Callback<void(const Foo&)> OnFooCallback;
42 //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
43 //   RegisterCallback(const OnFooCallback& cb) {
44 //     return callback_list_.Add(cb);
45 //   }
47 //  private:
48 //   void NotifyFoo(const Foo& foo) {
49 //      callback_list_.Notify(foo);
50 //   }
52 //   base::CallbackList<void(const Foo&)> callback_list_;
54 //   DISALLOW_COPY_AND_ASSIGN(MyWidget);
55 // };
58 // class MyWidgetListener {
59 //  public:
60 //   MyWidgetListener::MyWidgetListener() {
61 //     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
62 //             base::Bind(&MyWidgetListener::OnFoo, this)));
63 //   }
65 //   MyWidgetListener::~MyWidgetListener() {
66 //      // Subscription gets deleted automatically and will deregister
67 //      // the callback in the process.
68 //   }
70 //  private:
71 //   void OnFoo(const Foo& foo) {
72 //     // Do something.
73 //   }
75 //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
76 //       foo_subscription_;
78 //   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
79 // };
81 namespace base {
83 namespace internal {
85 template <typename CallbackType>
86 class CallbackListBase {
87  public:
88   class Subscription {
89    public:
90     Subscription(CallbackListBase<CallbackType>* list,
91                  typename std::list<CallbackType>::iterator iter)
92         : list_(list),
93           iter_(iter) {
94     }
96     ~Subscription() {
97       if (list_->active_iterator_count_) {
98         iter_->Reset();
99       } else {
100         list_->callbacks_.erase(iter_);
101         if (!list_->removal_callback_.is_null())
102           list_->removal_callback_.Run();
103       }
104     }
106    private:
107     CallbackListBase<CallbackType>* list_;
108     typename std::list<CallbackType>::iterator iter_;
110     DISALLOW_COPY_AND_ASSIGN(Subscription);
111   };
113   // Add a callback to the list. The callback will remain registered until the
114   // returned Subscription is destroyed, which must occur before the
115   // CallbackList is destroyed.
116   scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
117     DCHECK(!cb.is_null());
118     return scoped_ptr<Subscription>(
119         new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
120   }
122   // Sets a callback which will be run when a subscription list is changed.
123   void set_removal_callback(const Closure& callback) {
124     removal_callback_ = callback;
125   }
127   // Returns true if there are no subscriptions. This is only valid to call when
128   // not looping through the list.
129   bool empty() {
130     DCHECK_EQ(0, active_iterator_count_);
131     return callbacks_.empty();
132   }
134  protected:
135   // An iterator class that can be used to access the list of callbacks.
136   class Iterator {
137    public:
138     explicit Iterator(CallbackListBase<CallbackType>* list)
139         : list_(list),
140           list_iter_(list_->callbacks_.begin()) {
141       ++list_->active_iterator_count_;
142     }
144     Iterator(const Iterator& iter)
145         : list_(iter.list_),
146           list_iter_(iter.list_iter_) {
147       ++list_->active_iterator_count_;
148     }
150     ~Iterator() {
151       if (list_ && --list_->active_iterator_count_ == 0) {
152         list_->Compact();
153       }
154     }
156     CallbackType* GetNext() {
157       while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
158         ++list_iter_;
160       CallbackType* cb = NULL;
161       if (list_iter_ != list_->callbacks_.end()) {
162         cb = &(*list_iter_);
163         ++list_iter_;
164       }
165       return cb;
166     }
168    private:
169     CallbackListBase<CallbackType>* list_;
170     typename std::list<CallbackType>::iterator list_iter_;
171   };
173   CallbackListBase() : active_iterator_count_(0) {}
175   ~CallbackListBase() {
176     DCHECK_EQ(0, active_iterator_count_);
177     DCHECK_EQ(0U, callbacks_.size());
178   }
180   // Returns an instance of a CallbackListBase::Iterator which can be used
181   // to run callbacks.
182   Iterator GetIterator() {
183     return Iterator(this);
184   }
186   // Compact the list: remove any entries which were NULLed out during
187   // iteration.
188   void Compact() {
189     typename std::list<CallbackType>::iterator it = callbacks_.begin();
190     bool updated = false;
191     while (it != callbacks_.end()) {
192       if ((*it).is_null()) {
193         updated = true;
194         it = callbacks_.erase(it);
195       } else {
196         ++it;
197       }
199       if (updated && !removal_callback_.is_null())
200         removal_callback_.Run();
201     }
202   }
204  private:
205   std::list<CallbackType> callbacks_;
206   int active_iterator_count_;
207   Closure removal_callback_;
209   DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
212 }  // namespace internal
214 template <typename Sig> class CallbackList;
217 $range ARITY 0..MAX_ARITY
218 $for ARITY [[
219 $range ARG 1..ARITY
221 $if ARITY == 0 [[
222 template <>
223 class CallbackList<void(void)>
224     : public internal::CallbackListBase<Callback<void(void)> > {
225 ]] $else [[
226 template <$for ARG , [[typename A$(ARG)]]>
227 class CallbackList<void($for ARG , [[A$(ARG)]])>
228     : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > {
231  public:
232 $if ARITY == 0 [[
234   typedef Callback<void(void)> CallbackType;
235 ]] $else [[
237   typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType;
241   CallbackList() {}
243   void Notify($for ARG ,
244               [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
245 $if ARITY == 0 [[
247     internal::CallbackListBase<CallbackType>::Iterator it =
248         this->GetIterator();
249 ]] $else [[
251     typename internal::CallbackListBase<CallbackType>::Iterator it =
252         this->GetIterator();
255     CallbackType* cb;
256     while ((cb = it.GetNext()) != NULL) {
257       cb->Run($for ARG , [[a$(ARG)]]);
258     }
259   }
261  private:
262   DISALLOW_COPY_AND_ASSIGN(CallbackList);
266 ]]  $$ for ARITY
267 }  // namespace base
269 #endif  // BASE_CALLBACK_LIST_H_