blob: d7f84736c15756851e52a3c256d694f7de7c44b3 [file] [log] [blame]
caitkp@google.com2b10b742013-09-25 22:56:23 +09001$$ 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$$
7
8$$ See comment for MAX_ARITY in base/bind.h.pump.
9$var MAX_ARITY = 7
10
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.
14
caitkp@chromium.org49647322013-09-27 04:20:18 +090015#ifndef BASE_CALLBACK_LIST_H_
16#define BASE_CALLBACK_LIST_H_
caitkp@google.com2b10b742013-09-25 22:56:23 +090017
18#include <list>
19
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"
26
27// OVERVIEW:
28//
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.
33//
34// TYPICAL USAGE:
35//
36// class MyWidget {
37// public:
38// ...
39//
40// typedef base::Callback<void(const Foo&)> OnFooCallback;
41//
caitkp@chromium.org49647322013-09-27 04:20:18 +090042// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
caitkp@google.com2b10b742013-09-25 22:56:23 +090043// RegisterCallback(const OnFooCallback& cb) {
caitkp@chromium.org49647322013-09-27 04:20:18 +090044// return callback_list_.Add(cb);
caitkp@google.com2b10b742013-09-25 22:56:23 +090045// }
46//
47// private:
48// void NotifyFoo(const Foo& foo) {
caitkp@chromium.org49647322013-09-27 04:20:18 +090049// callback_list_.Notify(foo);
caitkp@google.com2b10b742013-09-25 22:56:23 +090050// }
51//
caitkp@chromium.org49647322013-09-27 04:20:18 +090052// base::CallbackList<void(const Foo&)> callback_list_;
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +090053//
54// DISALLOW_COPY_AND_ASSIGN(MyWidget);
caitkp@google.com2b10b742013-09-25 22:56:23 +090055// };
56//
57//
58// class MyWidgetListener {
59// public:
60// MyWidgetListener::MyWidgetListener() {
61// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
62// base::Bind(&MyWidgetListener::OnFoo, this)));
63// }
64//
65// MyWidgetListener::~MyWidgetListener() {
66// // Subscription gets deleted automatically and will deregister
67// // the callback in the process.
68// }
69//
70// private:
71// void OnFoo(const Foo& foo) {
72// // Do something.
73// }
74//
caitkp@chromium.org49647322013-09-27 04:20:18 +090075// scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
76// foo_subscription_;
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +090077//
78// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
caitkp@google.com2b10b742013-09-25 22:56:23 +090079// };
80
81namespace base {
82
83namespace internal {
84
85template <typename CallbackType>
caitkp@chromium.org49647322013-09-27 04:20:18 +090086class CallbackListBase {
caitkp@google.com2b10b742013-09-25 22:56:23 +090087 public:
88 class Subscription {
89 public:
caitkp@chromium.org49647322013-09-27 04:20:18 +090090 Subscription(CallbackListBase<CallbackType>* list,
caitkp@google.com2b10b742013-09-25 22:56:23 +090091 typename std::list<CallbackType>::iterator iter)
92 : list_(list),
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +090093 iter_(iter) {
94 }
caitkp@google.com2b10b742013-09-25 22:56:23 +090095
96 ~Subscription() {
jam@chromium.org63a01af2014-05-13 01:36:10 +090097 if (list_->active_iterator_count_) {
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +090098 iter_->Reset();
jam@chromium.org63a01af2014-05-13 01:36:10 +090099 } else {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900100 list_->callbacks_.erase(iter_);
jam@chromium.org63a01af2014-05-13 01:36:10 +0900101 if (!list_->removal_callback_.is_null())
102 list_->removal_callback_.Run();
103 }
caitkp@google.com2b10b742013-09-25 22:56:23 +0900104 }
105
106 private:
caitkp@chromium.org49647322013-09-27 04:20:18 +0900107 CallbackListBase<CallbackType>* list_;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900108 typename std::list<CallbackType>::iterator iter_;
109
110 DISALLOW_COPY_AND_ASSIGN(Subscription);
111 };
112
113 // Add a callback to the list. The callback will remain registered until the
114 // returned Subscription is destroyed, which must occur before the
caitkp@chromium.org49647322013-09-27 04:20:18 +0900115 // CallbackList is destroyed.
bauerb@chromium.org69cfb182013-11-16 00:54:36 +0900116 scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900117 DCHECK(!cb.is_null());
118 return scoped_ptr<Subscription>(
119 new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
120 }
121
jam@chromium.org63a01af2014-05-13 01:36:10 +0900122 // 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 }
126
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 }
133
caitkp@google.com2b10b742013-09-25 22:56:23 +0900134 protected:
135 // An iterator class that can be used to access the list of callbacks.
136 class Iterator {
137 public:
caitkp@chromium.org49647322013-09-27 04:20:18 +0900138 explicit Iterator(CallbackListBase<CallbackType>* list)
caitkp@google.com2b10b742013-09-25 22:56:23 +0900139 : list_(list),
140 list_iter_(list_->callbacks_.begin()) {
141 ++list_->active_iterator_count_;
142 }
143
144 Iterator(const Iterator& iter)
145 : list_(iter.list_),
146 list_iter_(iter.list_iter_) {
147 ++list_->active_iterator_count_;
148 }
149
150 ~Iterator() {
151 if (list_ && --list_->active_iterator_count_ == 0) {
152 list_->Compact();
153 }
154 }
155
156 CallbackType* GetNext() {
157 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
158 ++list_iter_;
159
160 CallbackType* cb = NULL;
161 if (list_iter_ != list_->callbacks_.end()) {
162 cb = &(*list_iter_);
163 ++list_iter_;
164 }
165 return cb;
166 }
167
168 private:
caitkp@chromium.org49647322013-09-27 04:20:18 +0900169 CallbackListBase<CallbackType>* list_;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900170 typename std::list<CallbackType>::iterator list_iter_;
171 };
172
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +0900173 CallbackListBase() : active_iterator_count_(0) {}
caitkp@google.com2b10b742013-09-25 22:56:23 +0900174
caitkp@chromium.org49647322013-09-27 04:20:18 +0900175 ~CallbackListBase() {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900176 DCHECK_EQ(0, active_iterator_count_);
177 DCHECK_EQ(0U, callbacks_.size());
178 }
179
caitkp@chromium.org49647322013-09-27 04:20:18 +0900180 // Returns an instance of a CallbackListBase::Iterator which can be used
caitkp@google.com2b10b742013-09-25 22:56:23 +0900181 // to run callbacks.
182 Iterator GetIterator() {
183 return Iterator(this);
184 }
185
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();
jam@chromium.org63a01af2014-05-13 01:36:10 +0900190 bool updated = false;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900191 while (it != callbacks_.end()) {
jam@chromium.org63a01af2014-05-13 01:36:10 +0900192 if ((*it).is_null()) {
193 updated = true;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900194 it = callbacks_.erase(it);
jam@chromium.org63a01af2014-05-13 01:36:10 +0900195 } else {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900196 ++it;
jam@chromium.org63a01af2014-05-13 01:36:10 +0900197 }
198
199 if (updated && !removal_callback_.is_null())
200 removal_callback_.Run();
caitkp@google.com2b10b742013-09-25 22:56:23 +0900201 }
202 }
203
204 private:
205 std::list<CallbackType> callbacks_;
206 int active_iterator_count_;
jam@chromium.org63a01af2014-05-13 01:36:10 +0900207 Closure removal_callback_;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900208
caitkp@chromium.org49647322013-09-27 04:20:18 +0900209 DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
caitkp@google.com2b10b742013-09-25 22:56:23 +0900210};
211
212} // namespace internal
213
caitkp@chromium.org49647322013-09-27 04:20:18 +0900214template <typename Sig> class CallbackList;
caitkp@google.com2b10b742013-09-25 22:56:23 +0900215
216
217$range ARITY 0..MAX_ARITY
218$for ARITY [[
219$range ARG 1..ARITY
220
221$if ARITY == 0 [[
222template <>
caitkp@chromium.org49647322013-09-27 04:20:18 +0900223class CallbackList<void(void)>
224 : public internal::CallbackListBase<Callback<void(void)> > {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900225]] $else [[
226template <$for ARG , [[typename A$(ARG)]]>
caitkp@chromium.org49647322013-09-27 04:20:18 +0900227class CallbackList<void($for ARG , [[A$(ARG)]])>
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +0900228 : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900229]]
230
231 public:
232$if ARITY == 0 [[
233
234 typedef Callback<void(void)> CallbackType;
235]] $else [[
236
237 typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType;
238]]
239
240
caitkp@chromium.org49647322013-09-27 04:20:18 +0900241 CallbackList() {}
caitkp@google.com2b10b742013-09-25 22:56:23 +0900242
243 void Notify($for ARG ,
244 [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
245$if ARITY == 0 [[
246
caitkp@chromium.org49647322013-09-27 04:20:18 +0900247 internal::CallbackListBase<CallbackType>::Iterator it =
caitkp@google.com2b10b742013-09-25 22:56:23 +0900248 this->GetIterator();
249]] $else [[
250
caitkp@chromium.org49647322013-09-27 04:20:18 +0900251 typename internal::CallbackListBase<CallbackType>::Iterator it =
caitkp@google.com2b10b742013-09-25 22:56:23 +0900252 this->GetIterator();
253]]
254
255 CallbackType* cb;
caitkp@chromium.org0b4414d2013-10-10 08:28:21 +0900256 while ((cb = it.GetNext()) != NULL) {
caitkp@google.com2b10b742013-09-25 22:56:23 +0900257 cb->Run($for ARG , [[a$(ARG)]]);
258 }
259 }
260
261 private:
caitkp@chromium.org49647322013-09-27 04:20:18 +0900262 DISALLOW_COPY_AND_ASSIGN(CallbackList);
caitkp@google.com2b10b742013-09-25 22:56:23 +0900263};
264
265
266]] $$ for ARITY
267} // namespace base
268
caitkp@chromium.org49647322013-09-27 04:20:18 +0900269#endif // BASE_CALLBACK_LIST_H_