blob: f455c6573084268d5c3066df266bffad18efd7e2 [file] [log] [blame]
[email protected]893c8162013-09-11 15:16:331// 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.
4
[email protected]2a7cac02013-09-26 19:20:185#ifndef BASE_CALLBACK_LIST_H_
6#define BASE_CALLBACK_LIST_H_
[email protected]893c8162013-09-11 15:16:337
8#include <list>
dcheng093de9b2016-04-04 21:25:519#include <memory>
[email protected]893c8162013-09-11 15:16:3310
[email protected]893c8162013-09-11 15:16:3311#include "base/callback.h"
12#include "base/compiler_specific.h"
13#include "base/logging.h"
avi9b6f42932015-12-26 22:15:1414#include "base/macros.h"
[email protected]893c8162013-09-11 15:16:3315
16// OVERVIEW:
17//
Avi Drissman0939b5492018-03-29 01:13:2218// A container for a list of (repeating) callbacks. Unlike a normal vector or
19// list, this container can be modified during iteration without invalidating
20// the iterator. It safely handles the case of a callback removing itself or
21// another callback from the list while callbacks are being run.
[email protected]893c8162013-09-11 15:16:3322//
23// TYPICAL USAGE:
24//
25// class MyWidget {
26// public:
27// ...
28//
dcheng093de9b2016-04-04 21:25:5129// std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
Avi Drissman0939b5492018-03-29 01:13:2230// RegisterCallback(const base::RepeatingCallback<void(const Foo&)>& cb) {
[email protected]2a7cac02013-09-26 19:20:1831// return callback_list_.Add(cb);
[email protected]893c8162013-09-11 15:16:3332// }
33//
34// private:
35// void NotifyFoo(const Foo& foo) {
[email protected]2a7cac02013-09-26 19:20:1836// callback_list_.Notify(foo);
[email protected]893c8162013-09-11 15:16:3337// }
38//
[email protected]2a7cac02013-09-26 19:20:1839// base::CallbackList<void(const Foo&)> callback_list_;
[email protected]abdd66e2013-10-09 23:28:2140//
41// DISALLOW_COPY_AND_ASSIGN(MyWidget);
[email protected]893c8162013-09-11 15:16:3342// };
43//
44//
45// class MyWidgetListener {
46// public:
47// MyWidgetListener::MyWidgetListener() {
48// foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
Avi Drissman0939b5492018-03-29 01:13:2249// base::BindRepeating(&MyWidgetListener::OnFoo, this)));
[email protected]893c8162013-09-11 15:16:3350// }
51//
52// MyWidgetListener::~MyWidgetListener() {
53// // Subscription gets deleted automatically and will deregister
54// // the callback in the process.
55// }
56//
57// private:
58// void OnFoo(const Foo& foo) {
59// // Do something.
60// }
61//
dcheng093de9b2016-04-04 21:25:5162// std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
[email protected]243576f2013-09-25 13:56:2363// foo_subscription_;
[email protected]abdd66e2013-10-09 23:28:2164//
65// DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
[email protected]893c8162013-09-11 15:16:3366// };
67
68namespace base {
69
70namespace internal {
71
72template <typename CallbackType>
[email protected]2a7cac02013-09-26 19:20:1873class CallbackListBase {
[email protected]893c8162013-09-11 15:16:3374 public:
75 class Subscription {
76 public:
[email protected]2a7cac02013-09-26 19:20:1877 Subscription(CallbackListBase<CallbackType>* list,
[email protected]893c8162013-09-11 15:16:3378 typename std::list<CallbackType>::iterator iter)
79 : list_(list),
[email protected]abdd66e2013-10-09 23:28:2180 iter_(iter) {
81 }
[email protected]893c8162013-09-11 15:16:3382
83 ~Subscription() {
[email protected]f28ef9a32014-05-12 16:36:1084 if (list_->active_iterator_count_) {
[email protected]abdd66e2013-10-09 23:28:2185 iter_->Reset();
[email protected]f28ef9a32014-05-12 16:36:1086 } else {
[email protected]893c8162013-09-11 15:16:3387 list_->callbacks_.erase(iter_);
[email protected]f28ef9a32014-05-12 16:36:1088 if (!list_->removal_callback_.is_null())
89 list_->removal_callback_.Run();
90 }
[email protected]893c8162013-09-11 15:16:3391 }
92
93 private:
[email protected]2a7cac02013-09-26 19:20:1894 CallbackListBase<CallbackType>* list_;
[email protected]893c8162013-09-11 15:16:3395 typename std::list<CallbackType>::iterator iter_;
96
97 DISALLOW_COPY_AND_ASSIGN(Subscription);
98 };
99
100 // Add a callback to the list. The callback will remain registered until the
101 // returned Subscription is destroyed, which must occur before the
[email protected]2a7cac02013-09-26 19:20:18102 // CallbackList is destroyed.
dcheng093de9b2016-04-04 21:25:51103 std::unique_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
[email protected]893c8162013-09-11 15:16:33104 DCHECK(!cb.is_null());
Avi Drissman0939b5492018-03-29 01:13:22105 return std::make_unique<Subscription>(
106 this, callbacks_.insert(callbacks_.end(), cb));
[email protected]893c8162013-09-11 15:16:33107 }
108
[email protected]f28ef9a32014-05-12 16:36:10109 // Sets a callback which will be run when a subscription list is changed.
Avi Drissman0939b5492018-03-29 01:13:22110 void set_removal_callback(const RepeatingClosure& callback) {
[email protected]f28ef9a32014-05-12 16:36:10111 removal_callback_ = callback;
112 }
113
114 // Returns true if there are no subscriptions. This is only valid to call when
115 // not looping through the list.
116 bool empty() {
117 DCHECK_EQ(0, active_iterator_count_);
118 return callbacks_.empty();
119 }
120
[email protected]893c8162013-09-11 15:16:33121 protected:
122 // An iterator class that can be used to access the list of callbacks.
123 class Iterator {
124 public:
[email protected]2a7cac02013-09-26 19:20:18125 explicit Iterator(CallbackListBase<CallbackType>* list)
[email protected]893c8162013-09-11 15:16:33126 : list_(list),
127 list_iter_(list_->callbacks_.begin()) {
128 ++list_->active_iterator_count_;
129 }
130
131 Iterator(const Iterator& iter)
132 : list_(iter.list_),
133 list_iter_(iter.list_iter_) {
134 ++list_->active_iterator_count_;
135 }
136
137 ~Iterator() {
138 if (list_ && --list_->active_iterator_count_ == 0) {
139 list_->Compact();
140 }
141 }
142
143 CallbackType* GetNext() {
144 while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
145 ++list_iter_;
146
Avi Drissman0939b5492018-03-29 01:13:22147 CallbackType* cb = nullptr;
[email protected]da04fbf2013-09-11 16:44:56148 if (list_iter_ != list_->callbacks_.end()) {
149 cb = &(*list_iter_);
150 ++list_iter_;
151 }
[email protected]893c8162013-09-11 15:16:33152 return cb;
153 }
154
155 private:
[email protected]2a7cac02013-09-26 19:20:18156 CallbackListBase<CallbackType>* list_;
[email protected]893c8162013-09-11 15:16:33157 typename std::list<CallbackType>::iterator list_iter_;
158 };
159
[email protected]abdd66e2013-10-09 23:28:21160 CallbackListBase() : active_iterator_count_(0) {}
[email protected]893c8162013-09-11 15:16:33161
[email protected]2a7cac02013-09-26 19:20:18162 ~CallbackListBase() {
[email protected]893c8162013-09-11 15:16:33163 DCHECK_EQ(0, active_iterator_count_);
164 DCHECK_EQ(0U, callbacks_.size());
165 }
166
[email protected]2a7cac02013-09-26 19:20:18167 // Returns an instance of a CallbackListBase::Iterator which can be used
[email protected]893c8162013-09-11 15:16:33168 // to run callbacks.
169 Iterator GetIterator() {
170 return Iterator(this);
171 }
172
Avi Drissman0939b5492018-03-29 01:13:22173 // Compact the list: remove any entries which were nulled out during
[email protected]893c8162013-09-11 15:16:33174 // iteration.
175 void Compact() {
Avi Drissman0939b5492018-03-29 01:13:22176 auto it = callbacks_.begin();
[email protected]f28ef9a32014-05-12 16:36:10177 bool updated = false;
[email protected]893c8162013-09-11 15:16:33178 while (it != callbacks_.end()) {
[email protected]f28ef9a32014-05-12 16:36:10179 if ((*it).is_null()) {
180 updated = true;
[email protected]893c8162013-09-11 15:16:33181 it = callbacks_.erase(it);
[email protected]f28ef9a32014-05-12 16:36:10182 } else {
[email protected]893c8162013-09-11 15:16:33183 ++it;
[email protected]f28ef9a32014-05-12 16:36:10184 }
[email protected]893c8162013-09-11 15:16:33185 }
davidbenf126cb22015-10-30 20:42:07186
187 if (updated && !removal_callback_.is_null())
188 removal_callback_.Run();
[email protected]893c8162013-09-11 15:16:33189 }
190
191 private:
192 std::list<CallbackType> callbacks_;
193 int active_iterator_count_;
Avi Drissman0939b5492018-03-29 01:13:22194 RepeatingClosure removal_callback_;
[email protected]893c8162013-09-11 15:16:33195
[email protected]2a7cac02013-09-26 19:20:18196 DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
[email protected]893c8162013-09-11 15:16:33197};
198
199} // namespace internal
200
[email protected]2a7cac02013-09-26 19:20:18201template <typename Sig> class CallbackList;
[email protected]243576f2013-09-25 13:56:23202
thakis6117a472014-11-20 01:15:14203template <typename... Args>
204class CallbackList<void(Args...)>
Avi Drissman0939b5492018-03-29 01:13:22205 : public internal::CallbackListBase<RepeatingCallback<void(Args...)>> {
[email protected]893c8162013-09-11 15:16:33206 public:
Avi Drissman0939b5492018-03-29 01:13:22207 using CallbackType = RepeatingCallback<void(Args...)>;
[email protected]243576f2013-09-25 13:56:23208
Chris Watkins091d6292017-12-13 04:25:58209 CallbackList() = default;
[email protected]893c8162013-09-11 15:16:33210
tzikd2046ce32016-04-14 21:44:39211 template <typename... RunArgs>
212 void Notify(RunArgs&&... args) {
Avi Drissman0939b5492018-03-29 01:13:22213 auto it = this->GetIterator();
[email protected]243576f2013-09-25 13:56:23214 CallbackType* cb;
Avi Drissman0939b5492018-03-29 01:13:22215 while ((cb = it.GetNext()) != nullptr) {
thakis6117a472014-11-20 01:15:14216 cb->Run(args...);
[email protected]243576f2013-09-25 13:56:23217 }
218 }
219
220 private:
[email protected]2a7cac02013-09-26 19:20:18221 DISALLOW_COPY_AND_ASSIGN(CallbackList);
[email protected]243576f2013-09-25 13:56:23222};
223
[email protected]893c8162013-09-11 15:16:33224} // namespace base
225
[email protected]2a7cac02013-09-26 19:20:18226#endif // BASE_CALLBACK_LIST_H_