• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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