1 // Copyright 2013 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.
5 #ifndef BASE_CALLBACK_LIST_H_
6 #define BASE_CALLBACK_LIST_H_
10 #include "base/basictypes.h"
11 #include "base/callback.h"
12 #include "base/callback_internal.h"
13 #include "base/compiler_specific.h"
14 #include "base/logging.h"
15 #include "base/memory/scoped_ptr.h"
19 // A container for a list of callbacks. Unlike a normal STL vector or list,
20 // this container can be modified during iteration without invalidating the
21 // iterator. It safely handles the case of a callback removing itself
22 // or another callback from the list while callbacks are being run.
30 // typedef base::Callback<void(const Foo&)> OnFooCallback;
32 // scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
33 // RegisterCallback(const OnFooCallback& cb) {
34 // return callback_list_.Add(cb);
38 // void NotifyFoo(const Foo& foo) {
39 // callback_list_.Notify(foo);
42 // base::CallbackList<void(const Foo&)> callback_list_;
44 // DISALLOW_COPY_AND_ASSIGN(MyWidget);
48 // class MyWidgetListener {
50 // MyWidgetListener::MyWidgetListener() {
51 // foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
52 // base::Bind(&MyWidgetListener::OnFoo, this)));
55 // MyWidgetListener::~MyWidgetListener() {
56 // // Subscription gets deleted automatically and will deregister
57 // // the callback in the process.
61 // void OnFoo(const Foo& foo) {
65 // scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
68 // DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
75 template <typename CallbackType
>
76 class CallbackListBase
{
80 Subscription(CallbackListBase
<CallbackType
>* list
,
81 typename
std::list
<CallbackType
>::iterator iter
)
87 if (list_
->active_iterator_count_
) {
90 list_
->callbacks_
.erase(iter_
);
91 if (!list_
->removal_callback_
.is_null())
92 list_
->removal_callback_
.Run();
97 CallbackListBase
<CallbackType
>* list_
;
98 typename
std::list
<CallbackType
>::iterator iter_
;
100 DISALLOW_COPY_AND_ASSIGN(Subscription
);
103 // Add a callback to the list. The callback will remain registered until the
104 // returned Subscription is destroyed, which must occur before the
105 // CallbackList is destroyed.
106 scoped_ptr
<Subscription
> Add(const CallbackType
& cb
) WARN_UNUSED_RESULT
{
107 DCHECK(!cb
.is_null());
108 return scoped_ptr
<Subscription
>(
109 new Subscription(this, callbacks_
.insert(callbacks_
.end(), cb
)));
112 // Sets a callback which will be run when a subscription list is changed.
113 void set_removal_callback(const Closure
& callback
) {
114 removal_callback_
= callback
;
117 // Returns true if there are no subscriptions. This is only valid to call when
118 // not looping through the list.
120 DCHECK_EQ(0, active_iterator_count_
);
121 return callbacks_
.empty();
125 // An iterator class that can be used to access the list of callbacks.
128 explicit Iterator(CallbackListBase
<CallbackType
>* list
)
130 list_iter_(list_
->callbacks_
.begin()) {
131 ++list_
->active_iterator_count_
;
134 Iterator(const Iterator
& iter
)
136 list_iter_(iter
.list_iter_
) {
137 ++list_
->active_iterator_count_
;
141 if (list_
&& --list_
->active_iterator_count_
== 0) {
146 CallbackType
* GetNext() {
147 while ((list_iter_
!= list_
->callbacks_
.end()) && list_iter_
->is_null())
150 CallbackType
* cb
= NULL
;
151 if (list_iter_
!= list_
->callbacks_
.end()) {
159 CallbackListBase
<CallbackType
>* list_
;
160 typename
std::list
<CallbackType
>::iterator list_iter_
;
163 CallbackListBase() : active_iterator_count_(0) {}
165 ~CallbackListBase() {
166 DCHECK_EQ(0, active_iterator_count_
);
167 DCHECK_EQ(0U, callbacks_
.size());
170 // Returns an instance of a CallbackListBase::Iterator which can be used
172 Iterator
GetIterator() {
173 return Iterator(this);
176 // Compact the list: remove any entries which were NULLed out during
179 typename
std::list
<CallbackType
>::iterator it
= callbacks_
.begin();
180 bool updated
= false;
181 while (it
!= callbacks_
.end()) {
182 if ((*it
).is_null()) {
184 it
= callbacks_
.erase(it
);
189 if (updated
&& !removal_callback_
.is_null())
190 removal_callback_
.Run();
195 std::list
<CallbackType
> callbacks_
;
196 int active_iterator_count_
;
197 Closure removal_callback_
;
199 DISALLOW_COPY_AND_ASSIGN(CallbackListBase
);
202 } // namespace internal
204 template <typename Sig
> class CallbackList
;
206 template <typename
... Args
>
207 class CallbackList
<void(Args
...)>
208 : public internal::CallbackListBase
<Callback
<void(Args
...)> > {
210 typedef Callback
<void(Args
...)> CallbackType
;
215 typename
internal::CallbackParamTraits
<Args
>::ForwardType
... args
) {
216 typename
internal::CallbackListBase
<CallbackType
>::Iterator it
=
219 while ((cb
= it
.GetNext()) != NULL
) {
225 DISALLOW_COPY_AND_ASSIGN(CallbackList
);
230 #endif // BASE_CALLBACK_LIST_H_