blob: 0572ba6500da0f3584eb8d507e69a962ebf751f9 [file] [log] [blame]
[email protected]631739f2011-06-05 07:07:121// Copyright (c) 2011 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
tfarinaa31163512015-05-13 22:10:155#ifndef BASE_OBSERVER_LIST_H_
6#define BASE_OBSERVER_LIST_H_
initial.commitd7cae122008-07-26 21:49:387
avi9b6f42932015-12-26 22:15:148#include <stddef.h>
9
initial.commitd7cae122008-07-26 21:49:3810#include <algorithm>
[email protected]b3e2fad02008-10-31 03:32:0611#include <limits>
12#include <vector>
initial.commitd7cae122008-07-26 21:49:3813
loyso29025b62016-10-11 06:51:3314#include "base/gtest_prod_util.h"
initial.commitd7cae122008-07-26 21:49:3815#include "base/logging.h"
avi9b6f42932015-12-26 22:15:1416#include "base/macros.h"
[email protected]671b74d2011-06-09 03:41:1817#include "base/memory/weak_ptr.h"
thestig6c335d42015-12-07 18:25:3418#include "base/stl_util.h"
initial.commitd7cae122008-07-26 21:49:3819
20///////////////////////////////////////////////////////////////////////////////
21//
22// OVERVIEW:
23//
24// A container for a list of observers. Unlike a normal STL vector or list,
25// this container can be modified during iteration without invalidating the
26// iterator. So, it safely handles the case of an observer removing itself
27// or other observers from the list while observers are being notified.
28//
29// TYPICAL USAGE:
30//
31// class MyWidget {
32// public:
33// ...
34//
35// class Observer {
36// public:
37// virtual void OnFoo(MyWidget* w) = 0;
38// virtual void OnBar(MyWidget* w, int x, int y) = 0;
39// };
40//
41// void AddObserver(Observer* obs) {
42// observer_list_.AddObserver(obs);
43// }
44//
45// void RemoveObserver(Observer* obs) {
46// observer_list_.RemoveObserver(obs);
47// }
48//
49// void NotifyFoo() {
loyso29025b62016-10-11 06:51:3350// for (auto& observer : observer_list_)
51// observer.OnFoo(this);
initial.commitd7cae122008-07-26 21:49:3852// }
53//
54// void NotifyBar(int x, int y) {
loyso29025b62016-10-11 06:51:3355// for (FooList::iterator i = observer_list.begin(),
56// e = observer_list.end(); i != e; ++i)
57// i->OnBar(this, x, y);
initial.commitd7cae122008-07-26 21:49:3858// }
59//
60// private:
brettw5a1613dc2015-06-02 05:34:4361// base::ObserverList<Observer> observer_list_;
initial.commitd7cae122008-07-26 21:49:3862// };
63//
[email protected]b3e2fad02008-10-31 03:32:0664//
initial.commitd7cae122008-07-26 21:49:3865///////////////////////////////////////////////////////////////////////////////
66
brettw5a1613dc2015-06-02 05:34:4367namespace base {
68
[email protected]84aebed2010-02-25 03:09:4169template <typename ObserverType>
70class ObserverListThreadSafe;
71
72template <class ObserverType>
[email protected]671b74d2011-06-09 03:41:1873class ObserverListBase
brettw5a1613dc2015-06-02 05:34:4374 : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
initial.commitd7cae122008-07-26 21:49:3875 public:
[email protected]b3e2fad02008-10-31 03:32:0676 // Enumeration of which observers are notified.
77 enum NotificationType {
78 // Specifies that any observers added during notification are notified.
79 // This is the default type if non type is provided to the constructor.
80 NOTIFY_ALL,
81
82 // Specifies that observers added while sending out notification are not
83 // notified.
84 NOTIFY_EXISTING_ONLY
85 };
86
loyso29025b62016-10-11 06:51:3387 // An iterator class that can be used to access the list of observers.
88 template <class ContainerType>
89 class Iter {
initial.commitd7cae122008-07-26 21:49:3890 public:
loyso29025b62016-10-11 06:51:3391 Iter();
92 explicit Iter(ContainerType* list);
93 ~Iter();
94
loyso29025b62016-10-11 06:51:3395 // A workaround for C2244. MSVC requires fully qualified type name for
96 // return type on a function definition to match a function declaration.
97 using ThisType =
98 typename ObserverListBase<ObserverType>::template Iter<ContainerType>;
99
100 bool operator==(const Iter& other) const;
101 bool operator!=(const Iter& other) const;
102 ThisType& operator++();
103 ObserverType* operator->() const;
104 ObserverType& operator*() const;
105
initial.commitd7cae122008-07-26 21:49:38106 private:
loyso29025b62016-10-11 06:51:33107 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator);
108 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront);
109
110 ObserverType* GetCurrent() const;
111 void EnsureValidIndex();
112
113 size_t clamped_max_index() const {
114 return std::min(max_index_, list_->observers_.size());
115 }
116
117 bool is_end() const { return !list_ || index_ == clamped_max_index(); }
118
brettw5a1613dc2015-06-02 05:34:43119 WeakPtr<ObserverListBase<ObserverType>> list_;
loyso29025b62016-10-11 06:51:33120 // When initially constructed and each time the iterator is incremented,
121 // |index_| is guaranteed to point to a non-null index if the iterator
122 // has not reached the end of the ObserverList.
initial.commitd7cae122008-07-26 21:49:38123 size_t index_;
[email protected]b3e2fad02008-10-31 03:32:06124 size_t max_index_;
initial.commitd7cae122008-07-26 21:49:38125 };
126
loyso29025b62016-10-11 06:51:33127 using Iterator = Iter<ObserverListBase<ObserverType>>;
128
129 using iterator = Iter<ObserverListBase<ObserverType>>;
130 iterator begin() {
131 // An optimization: do not involve weak pointers for empty list.
132 // Note: can't use ?: operator here due to some MSVC bug (unit tests fail)
133 if (observers_.empty())
134 return iterator();
135 return iterator(this);
136 }
137 iterator end() { return iterator(); }
138
139 using const_iterator = Iter<const ObserverListBase<ObserverType>>;
140 const_iterator begin() const {
141 if (observers_.empty())
142 return const_iterator();
143 return const_iterator(this);
144 }
145 const_iterator end() const { return const_iterator(); }
146
[email protected]84aebed2010-02-25 03:09:41147 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
148 explicit ObserverListBase(NotificationType type)
149 : notify_depth_(0), type_(type) {}
initial.commitd7cae122008-07-26 21:49:38150
[email protected]631739f2011-06-05 07:07:12151 // Add an observer to the list. An observer should not be added to
152 // the same list more than once.
[email protected]86262b22014-07-17 12:39:34153 void AddObserver(ObserverType* obs);
[email protected]84aebed2010-02-25 03:09:41154
[email protected]631739f2011-06-05 07:07:12155 // Remove an observer from the list if it is in the list.
[email protected]86262b22014-07-17 12:39:34156 void RemoveObserver(ObserverType* obs);
[email protected]84aebed2010-02-25 03:09:41157
mgiuca64ccf2362014-11-10 06:44:23158 // Determine whether a particular observer is in the list.
159 bool HasObserver(const ObserverType* observer) const;
[email protected]84aebed2010-02-25 03:09:41160
[email protected]86262b22014-07-17 12:39:34161 void Clear();
[email protected]84aebed2010-02-25 03:09:41162
[email protected]188a47b2013-08-29 03:55:13163 protected:
[email protected]121594b2010-04-29 18:17:29164 size_t size() const { return observers_.size(); }
[email protected]84aebed2010-02-25 03:09:41165
[email protected]86262b22014-07-17 12:39:34166 void Compact();
initial.commitd7cae122008-07-26 21:49:38167
[email protected]84aebed2010-02-25 03:09:41168 private:
169 friend class ObserverListThreadSafe<ObserverType>;
170
171 typedef std::vector<ObserverType*> ListType;
172
173 ListType observers_;
174 int notify_depth_;
[email protected]b3e2fad02008-10-31 03:32:06175 NotificationType type_;
initial.commitd7cae122008-07-26 21:49:38176
loyso29025b62016-10-11 06:51:33177 template <class ContainerType>
178 friend class Iter;
initial.commitd7cae122008-07-26 21:49:38179
[email protected]84aebed2010-02-25 03:09:41180 DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
181};
182
[email protected]86262b22014-07-17 12:39:34183template <class ObserverType>
loyso29025b62016-10-11 06:51:33184template <class ContainerType>
185ObserverListBase<ObserverType>::Iter<ContainerType>::Iter()
186 : index_(0), max_index_(0) {}
187
188template <class ObserverType>
189template <class ContainerType>
190ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list)
191 : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()),
[email protected]86262b22014-07-17 12:39:34192 index_(0),
danakj4ef352d2015-03-09 17:45:39193 max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
194 : list->observers_.size()) {
loyso29025b62016-10-11 06:51:33195 EnsureValidIndex();
196 DCHECK(list_);
[email protected]86262b22014-07-17 12:39:34197 ++list_->notify_depth_;
198}
199
200template <class ObserverType>
loyso29025b62016-10-11 06:51:33201template <class ContainerType>
202ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
203 if (list_ && --list_->notify_depth_ == 0)
[email protected]86262b22014-07-17 12:39:34204 list_->Compact();
205}
206
207template <class ObserverType>
loyso29025b62016-10-11 06:51:33208template <class ContainerType>
209bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator==(
210 const Iter& other) const {
211 if (is_end() && other.is_end())
212 return true;
213 return list_.get() == other.list_.get() && index_ == other.index_;
214}
215
216template <class ObserverType>
217template <class ContainerType>
218bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=(
219 const Iter& other) const {
220 return !operator==(other);
221}
222
223template <class ObserverType>
224template <class ContainerType>
225typename ObserverListBase<ObserverType>::template Iter<ContainerType>&
226 ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() {
227 if (list_) {
[email protected]86262b22014-07-17 12:39:34228 ++index_;
loyso29025b62016-10-11 06:51:33229 EnsureValidIndex();
230 }
231 return *this;
232}
233
234template <class ObserverType>
235template <class ContainerType>
236ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->()
237 const {
238 ObserverType* current = GetCurrent();
239 DCHECK(current);
240 return current;
241}
242
243template <class ObserverType>
244template <class ContainerType>
245ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*()
246 const {
247 ObserverType* current = GetCurrent();
248 DCHECK(current);
249 return *current;
250}
251
252template <class ObserverType>
253template <class ContainerType>
254ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetCurrent()
255 const {
256 if (!list_)
257 return nullptr;
258 return index_ < clamped_max_index() ? list_->observers_[index_] : nullptr;
259}
260
261template <class ObserverType>
262template <class ContainerType>
263void ObserverListBase<ObserverType>::Iter<ContainerType>::EnsureValidIndex() {
264 if (!list_)
265 return;
266
267 size_t max_index = clamped_max_index();
268 while (index_ < max_index && !list_->observers_[index_])
269 ++index_;
270}
271
272template <class ObserverType>
[email protected]86262b22014-07-17 12:39:34273void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
oshima8750dd92015-04-08 22:57:52274 DCHECK(obs);
thestig6c335d42015-12-07 18:25:34275 if (ContainsValue(observers_, obs)) {
[email protected]86262b22014-07-17 12:39:34276 NOTREACHED() << "Observers can only be added once!";
277 return;
278 }
279 observers_.push_back(obs);
280}
281
282template <class ObserverType>
283void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
oshima8750dd92015-04-08 22:57:52284 DCHECK(obs);
[email protected]86262b22014-07-17 12:39:34285 typename ListType::iterator it =
286 std::find(observers_.begin(), observers_.end(), obs);
287 if (it != observers_.end()) {
288 if (notify_depth_) {
robliao6f5e4232015-04-23 22:45:32289 *it = nullptr;
[email protected]86262b22014-07-17 12:39:34290 } else {
291 observers_.erase(it);
292 }
293 }
294}
295
296template <class ObserverType>
mgiuca64ccf2362014-11-10 06:44:23297bool ObserverListBase<ObserverType>::HasObserver(
298 const ObserverType* observer) const {
[email protected]86262b22014-07-17 12:39:34299 for (size_t i = 0; i < observers_.size(); ++i) {
300 if (observers_[i] == observer)
301 return true;
302 }
303 return false;
304}
305
306template <class ObserverType>
307void ObserverListBase<ObserverType>::Clear() {
308 if (notify_depth_) {
309 for (typename ListType::iterator it = observers_.begin();
310 it != observers_.end(); ++it) {
robliao6f5e4232015-04-23 22:45:32311 *it = nullptr;
[email protected]86262b22014-07-17 12:39:34312 }
313 } else {
314 observers_.clear();
315 }
316}
317
318template <class ObserverType>
319void ObserverListBase<ObserverType>::Compact() {
loyso29025b62016-10-11 06:51:33320 observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr),
321 observers_.end());
[email protected]86262b22014-07-17 12:39:34322}
323
[email protected]84aebed2010-02-25 03:09:41324template <class ObserverType, bool check_empty = false>
325class ObserverList : public ObserverListBase<ObserverType> {
326 public:
327 typedef typename ObserverListBase<ObserverType>::NotificationType
328 NotificationType;
329
330 ObserverList() {}
331 explicit ObserverList(NotificationType type)
332 : ObserverListBase<ObserverType>(type) {}
333
334 ~ObserverList() {
335 // When check_empty is true, assert that the list is empty on destruction.
336 if (check_empty) {
337 ObserverListBase<ObserverType>::Compact();
338 DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
339 }
340 }
[email protected]fde08302011-10-13 14:13:43341
342 bool might_have_observers() const {
343 return ObserverListBase<ObserverType>::size() != 0;
344 }
initial.commitd7cae122008-07-26 21:49:38345};
346
brettw5a1613dc2015-06-02 05:34:43347} // namespace base
348
tfarinaa31163512015-05-13 22:10:15349#endif // BASE_OBSERVER_LIST_H_