1 // Copyright (c) 2011 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
5 #ifndef BASE_OBSERVER_LIST_H_
6 #define BASE_OBSERVER_LIST_H_
7
8 #include <stddef.h>
9
10 #include <algorithm>
11 #include <limits>
12 #include <vector>
13
14 #include "base/gtest_prod_util.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/memory/weak_ptr.h"
18 #include "base/stl_util.h"
19
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() {
50 // for (auto& observer : observer_list_)
51 // observer.OnFoo(this);
52 // }
53 //
54 // void NotifyBar(int x, int y) {
55 // for (FooList::iterator i = observer_list.begin(),
56 // e = observer_list.end(); i != e; ++i)
57 // i->OnBar(this, x, y);
58 // }
59 //
60 // private:
61 // base::ObserverList<Observer> observer_list_;
62 // };
63 //
64 //
65 ///////////////////////////////////////////////////////////////////////////////
66
67 namespace base {
68
69 template <typename ObserverType>
70 class ObserverListThreadSafe;
71
72 template <class ObserverType>
73 class ObserverListBase
74 : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
75 public:
76 // 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
87 // An iterator class that can be used to access the list of observers.
88 template <class ContainerType>
89 class Iter {
90 public:
91 Iter();
92 explicit Iter(ContainerType* list);
93 ~Iter();
94
95 // 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
106 private:
107 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator);
108 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront);
109
110 ObserverType* GetCurrent() const;
111 void EnsureValidIndex();
112
clamped_max_index()113 size_t clamped_max_index() const {
114 return std::min(max_index_, list_->observers_.size());
115 }
116
is_end()117 bool is_end() const { return !list_ || index_ == clamped_max_index(); }
118
119 WeakPtr<ObserverListBase<ObserverType>> list_;
120 // 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.
123 size_t index_;
124 size_t max_index_;
125 };
126
127 using Iterator = Iter<ObserverListBase<ObserverType>>;
128
129 using iterator = Iter<ObserverListBase<ObserverType>>;
begin()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 }
end()137 iterator end() { return iterator(); }
138
139 using const_iterator = Iter<const ObserverListBase<ObserverType>>;
begin()140 const_iterator begin() const {
141 if (observers_.empty())
142 return const_iterator();
143 return const_iterator(this);
144 }
end()145 const_iterator end() const { return const_iterator(); }
146
ObserverListBase()147 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
ObserverListBase(NotificationType type)148 explicit ObserverListBase(NotificationType type)
149 : notify_depth_(0), type_(type) {}
150
151 // Add an observer to the list. An observer should not be added to
152 // the same list more than once.
153 void AddObserver(ObserverType* obs);
154
155 // Remove an observer from the list if it is in the list.
156 void RemoveObserver(ObserverType* obs);
157
158 // Determine whether a particular observer is in the list.
159 bool HasObserver(const ObserverType* observer) const;
160
161 void Clear();
162
163 protected:
size()164 size_t size() const { return observers_.size(); }
165
166 void Compact();
167
168 private:
169 friend class ObserverListThreadSafe<ObserverType>;
170
171 typedef std::vector<ObserverType*> ListType;
172
173 ListType observers_;
174 int notify_depth_;
175 NotificationType type_;
176
177 template <class ContainerType>
178 friend class Iter;
179
180 DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
181 };
182
183 template <class ObserverType>
184 template <class ContainerType>
Iter()185 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter()
186 : index_(0), max_index_(0) {}
187
188 template <class ObserverType>
189 template <class ContainerType>
Iter(ContainerType * list)190 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list)
191 : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()),
192 index_(0),
193 max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
194 : list->observers_.size()) {
195 EnsureValidIndex();
196 DCHECK(list_);
197 ++list_->notify_depth_;
198 }
199
200 template <class ObserverType>
201 template <class ContainerType>
~Iter()202 ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
203 if (list_ && --list_->notify_depth_ == 0)
204 list_->Compact();
205 }
206
207 template <class ObserverType>
208 template <class ContainerType>
209 bool 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
216 template <class ObserverType>
217 template <class ContainerType>
218 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=(
219 const Iter& other) const {
220 return !operator==(other);
221 }
222
223 template <class ObserverType>
224 template <class ContainerType>
225 typename ObserverListBase<ObserverType>::template Iter<ContainerType>&
226 ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() {
227 if (list_) {
228 ++index_;
229 EnsureValidIndex();
230 }
231 return *this;
232 }
233
234 template <class ObserverType>
235 template <class ContainerType>
236 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->()
237 const {
238 ObserverType* current = GetCurrent();
239 DCHECK(current);
240 return current;
241 }
242
243 template <class ObserverType>
244 template <class ContainerType>
245 ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*()
246 const {
247 ObserverType* current = GetCurrent();
248 DCHECK(current);
249 return *current;
250 }
251
252 template <class ObserverType>
253 template <class ContainerType>
GetCurrent()254 ObserverType* 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
261 template <class ObserverType>
262 template <class ContainerType>
EnsureValidIndex()263 void 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
272 template <class ObserverType>
AddObserver(ObserverType * obs)273 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
274 DCHECK(obs);
275 if (ContainsValue(observers_, obs)) {
276 NOTREACHED() << "Observers can only be added once!";
277 return;
278 }
279 observers_.push_back(obs);
280 }
281
282 template <class ObserverType>
RemoveObserver(ObserverType * obs)283 void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
284 DCHECK(obs);
285 typename ListType::iterator it =
286 std::find(observers_.begin(), observers_.end(), obs);
287 if (it != observers_.end()) {
288 if (notify_depth_) {
289 *it = nullptr;
290 } else {
291 observers_.erase(it);
292 }
293 }
294 }
295
296 template <class ObserverType>
HasObserver(const ObserverType * observer)297 bool ObserverListBase<ObserverType>::HasObserver(
298 const ObserverType* observer) const {
299 for (size_t i = 0; i < observers_.size(); ++i) {
300 if (observers_[i] == observer)
301 return true;
302 }
303 return false;
304 }
305
306 template <class ObserverType>
Clear()307 void ObserverListBase<ObserverType>::Clear() {
308 if (notify_depth_) {
309 for (typename ListType::iterator it = observers_.begin();
310 it != observers_.end(); ++it) {
311 *it = nullptr;
312 }
313 } else {
314 observers_.clear();
315 }
316 }
317
318 template <class ObserverType>
Compact()319 void ObserverListBase<ObserverType>::Compact() {
320 observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr),
321 observers_.end());
322 }
323
324 template <class ObserverType, bool check_empty = false>
325 class ObserverList : public ObserverListBase<ObserverType> {
326 public:
327 typedef typename ObserverListBase<ObserverType>::NotificationType
328 NotificationType;
329
ObserverList()330 ObserverList() {}
ObserverList(NotificationType type)331 explicit ObserverList(NotificationType type)
332 : ObserverListBase<ObserverType>(type) {}
333
~ObserverList()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 }
341
might_have_observers()342 bool might_have_observers() const {
343 return ObserverListBase<ObserverType>::size() != 0;
344 }
345 };
346
347 } // namespace base
348
349 #endif // BASE_OBSERVER_LIST_H_
350