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_REGISTRY_H_
6 #define BASE_CALLBACK_REGISTRY_H_
10 #include "base/basictypes.h"
11 #include "base/callback.h"
12 #include "base/compiler_specific.h"
13 #include "base/logging.h"
14 #include "base/memory/scoped_ptr.h"
18 // A container for a list of callbacks. Unlike a normal STL vector or list,
19 // this container can be modified during iteration without invalidating the
20 // iterator. It safely handles the case of a callback removing itself
21 // or another callback from the list while callbacks are being run.
29 // typedef base::Callback<void(const Foo&)> OnFooCallback;
31 // scoped_ptr<base::CallbackRegistry<Foo>::Subscription> RegisterCallback(
32 // const OnFooCallback& cb) {
33 // return callback_registry_.Add(cb);
37 // void NotifyFoo(const Foo& foo) {
38 // callback_registry_.Notify(foo);
41 // base::CallbackRegistry<Foo> callback_registry_;
45 // class MyWidgetListener {
47 // MyWidgetListener::MyWidgetListener() {
48 // foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
49 // base::Bind(&MyWidgetListener::OnFoo, this)));
52 // MyWidgetListener::~MyWidgetListener() {
53 // // Subscription gets deleted automatically and will deregister
54 // // the callback in the process.
58 // void OnFoo(const Foo& foo) {
62 // scoped_ptr<base::CallbackRegistry<Foo>::Subscription> foo_subscription_;
69 template <typename CallbackType
>
70 class CallbackRegistryBase
{
74 Subscription(CallbackRegistryBase
<CallbackType
>* list
,
75 typename
std::list
<CallbackType
>::iterator iter
)
80 if (list_
->active_iterator_count_
)
83 list_
->callbacks_
.erase(iter_
);
87 CallbackRegistryBase
<CallbackType
>* list_
;
88 typename
std::list
<CallbackType
>::iterator iter_
;
90 DISALLOW_COPY_AND_ASSIGN(Subscription
);
93 // Add a callback to the list. The callback will remain registered until the
94 // returned Subscription is destroyed, which must occur before the
95 // CallbackRegistry is destroyed.
96 scoped_ptr
<Subscription
> Add(const CallbackType
& cb
) {
97 DCHECK(!cb
.is_null());
98 return scoped_ptr
<Subscription
>(
99 new Subscription(this, callbacks_
.insert(callbacks_
.end(), cb
)));
103 // An iterator class that can be used to access the list of callbacks.
106 explicit Iterator(CallbackRegistryBase
<CallbackType
>* list
)
108 list_iter_(list_
->callbacks_
.begin()) {
109 ++list_
->active_iterator_count_
;
112 Iterator(const Iterator
& iter
)
114 list_iter_(iter
.list_iter_
) {
115 ++list_
->active_iterator_count_
;
119 if (list_
&& --list_
->active_iterator_count_
== 0) {
124 CallbackType
* GetNext() {
125 while ((list_iter_
!= list_
->callbacks_
.end()) && list_iter_
->is_null())
128 CallbackType
* cb
= NULL
;
129 if (list_iter_
!= list_
->callbacks_
.end()) {
137 CallbackRegistryBase
<CallbackType
>* list_
;
138 typename
std::list
<CallbackType
>::iterator list_iter_
;
141 CallbackRegistryBase()
142 : active_iterator_count_(0) {}
144 ~CallbackRegistryBase() {
145 DCHECK_EQ(0, active_iterator_count_
);
146 DCHECK_EQ(0U, callbacks_
.size());
149 // Returns an instance of a CallbackRegistryBase::Iterator which can be used
151 Iterator
GetIterator() {
152 return Iterator(this);
155 // Compact the list: remove any entries which were NULLed out during
158 typename
std::list
<CallbackType
>::iterator it
= callbacks_
.begin();
159 while (it
!= callbacks_
.end()) {
161 it
= callbacks_
.erase(it
);
168 std::list
<CallbackType
> callbacks_
;
169 int active_iterator_count_
;
171 DISALLOW_COPY_AND_ASSIGN(CallbackRegistryBase
);
174 } // namespace internal
176 template <typename Details
>
177 class CallbackRegistry
178 : public internal::CallbackRegistryBase
<Callback
<void(const Details
&)> > {
180 CallbackRegistry() {}
182 // Execute all active callbacks with |details| parameter.
183 void Notify(const Details
& details
) {
184 typename
internal::CallbackRegistryBase
<
185 Callback
<void(const Details
&)> >::Iterator it
= this->GetIterator();
186 Callback
<void(const Details
&)>* cb
;
187 while((cb
= it
.GetNext()) != NULL
) {
193 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry
);
196 template <> class CallbackRegistry
<void>
197 : public internal::CallbackRegistryBase
<Closure
> {
199 CallbackRegistry() {}
201 // Execute all active callbacks.
203 Iterator it
= this->GetIterator();
205 while((cb
= it
.GetNext()) != NULL
) {
211 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry
);
216 #endif // BASE_CALLBACK_REGISTRY_H_