Move prefs::kLastPolicyStatisticsUpdate to the policy component.
[chromium-blink-merge.git] / base / callback_registry.h
blobfcacbf549f2a79412130e0b1d902715a9663cca0
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_
8 #include <list>
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"
16 // OVERVIEW:
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.
23 // TYPICAL USAGE:
25 // class MyWidget {
26 // public:
27 // ...
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);
34 // }
36 // private:
37 // void NotifyFoo(const Foo& foo) {
38 // callback_registry_.Notify(foo);
39 // }
41 // base::CallbackRegistry<Foo> callback_registry_;
42 // };
45 // class MyWidgetListener {
46 // public:
47 // MyWidgetListener::MyWidgetListener() {
48 // foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
49 // base::Bind(&MyWidgetListener::OnFoo, this)));
50 // }
52 // MyWidgetListener::~MyWidgetListener() {
53 // // Subscription gets deleted automatically and will deregister
54 // // the callback in the process.
55 // }
57 // private:
58 // void OnFoo(const Foo& foo) {
59 // // Do something.
60 // }
62 // scoped_ptr<base::CallbackRegistry<Foo>::Subscription> foo_subscription_;
63 // };
65 namespace base {
67 namespace internal {
69 template <typename CallbackType>
70 class CallbackRegistryBase {
71 public:
72 class Subscription {
73 public:
74 Subscription(CallbackRegistryBase<CallbackType>* list,
75 typename std::list<CallbackType>::iterator iter)
76 : list_(list),
77 iter_(iter) {}
79 ~Subscription() {
80 if (list_->active_iterator_count_)
81 (*iter_).Reset();
82 else
83 list_->callbacks_.erase(iter_);
86 private:
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)));
102 protected:
103 // An iterator class that can be used to access the list of callbacks.
104 class Iterator {
105 public:
106 explicit Iterator(CallbackRegistryBase<CallbackType>* list)
107 : list_(list),
108 list_iter_(list_->callbacks_.begin()) {
109 ++list_->active_iterator_count_;
112 Iterator(const Iterator& iter)
113 : list_(iter.list_),
114 list_iter_(iter.list_iter_) {
115 ++list_->active_iterator_count_;
118 ~Iterator() {
119 if (list_ && --list_->active_iterator_count_ == 0) {
120 list_->Compact();
124 CallbackType* GetNext() {
125 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
126 ++list_iter_;
128 CallbackType* cb = NULL;
129 if (list_iter_ != list_->callbacks_.end()) {
130 cb = &(*list_iter_);
131 ++list_iter_;
133 return cb;
136 private:
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
150 // to run callbacks.
151 Iterator GetIterator() {
152 return Iterator(this);
155 // Compact the list: remove any entries which were NULLed out during
156 // iteration.
157 void Compact() {
158 typename std::list<CallbackType>::iterator it = callbacks_.begin();
159 while (it != callbacks_.end()) {
160 if ((*it).is_null())
161 it = callbacks_.erase(it);
162 else
163 ++it;
167 private:
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&)> > {
179 public:
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) {
188 cb->Run(details);
192 private:
193 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
196 template <> class CallbackRegistry<void>
197 : public internal::CallbackRegistryBase<Closure> {
198 public:
199 CallbackRegistry() {}
201 // Execute all active callbacks.
202 void Notify() {
203 Iterator it = this->GetIterator();
204 Closure* cb;
205 while((cb = it.GetNext()) != NULL) {
206 cb->Run();
210 private:
211 DISALLOW_COPY_AND_ASSIGN(CallbackRegistry);
214 } // namespace base
216 #endif // BASE_CALLBACK_REGISTRY_H_