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/logging.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/stl_util.h"
18 
19 ///////////////////////////////////////////////////////////////////////////////
20 //
21 // OVERVIEW:
22 //
23 //   A container for a list of observers.  Unlike a normal STL vector or list,
24 //   this container can be modified during iteration without invalidating the
25 //   iterator.  So, it safely handles the case of an observer removing itself
26 //   or other observers from the list while observers are being notified.
27 //
28 // TYPICAL USAGE:
29 //
30 //   class MyWidget {
31 //    public:
32 //     ...
33 //
34 //     class Observer {
35 //      public:
36 //       virtual void OnFoo(MyWidget* w) = 0;
37 //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
38 //     };
39 //
40 //     void AddObserver(Observer* obs) {
41 //       observer_list_.AddObserver(obs);
42 //     }
43 //
44 //     void RemoveObserver(Observer* obs) {
45 //       observer_list_.RemoveObserver(obs);
46 //     }
47 //
48 //     void NotifyFoo() {
49 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
50 //     }
51 //
52 //     void NotifyBar(int x, int y) {
53 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
54 //     }
55 //
56 //    private:
57 //     base::ObserverList<Observer> observer_list_;
58 //   };
59 //
60 //
61 ///////////////////////////////////////////////////////////////////////////////
62 
63 namespace base {
64 
65 template <typename ObserverType>
66 class ObserverListThreadSafe;
67 
68 template <class ObserverType>
69 class ObserverListBase
70     : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
71  public:
72   // Enumeration of which observers are notified.
73   enum NotificationType {
74     // Specifies that any observers added during notification are notified.
75     // This is the default type if non type is provided to the constructor.
76     NOTIFY_ALL,
77 
78     // Specifies that observers added while sending out notification are not
79     // notified.
80     NOTIFY_EXISTING_ONLY
81   };
82 
83   // An iterator class that can be used to access the list of observers.  See
84   // also the FOR_EACH_OBSERVER macro defined below.
85   class Iterator {
86    public:
87     explicit Iterator(ObserverListBase<ObserverType>* list);
88     ~Iterator();
89     ObserverType* GetNext();
90 
91    private:
92     WeakPtr<ObserverListBase<ObserverType>> list_;
93     size_t index_;
94     size_t max_index_;
95   };
96 
ObserverListBase()97   ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
ObserverListBase(NotificationType type)98   explicit ObserverListBase(NotificationType type)
99       : notify_depth_(0), type_(type) {}
100 
101   // Add an observer to the list.  An observer should not be added to
102   // the same list more than once.
103   void AddObserver(ObserverType* obs);
104 
105   // Remove an observer from the list if it is in the list.
106   void RemoveObserver(ObserverType* obs);
107 
108   // Determine whether a particular observer is in the list.
109   bool HasObserver(const ObserverType* observer) const;
110 
111   void Clear();
112 
113  protected:
size()114   size_t size() const { return observers_.size(); }
115 
116   void Compact();
117 
118  private:
119   friend class ObserverListThreadSafe<ObserverType>;
120 
121   typedef std::vector<ObserverType*> ListType;
122 
123   ListType observers_;
124   int notify_depth_;
125   NotificationType type_;
126 
127   friend class ObserverListBase::Iterator;
128 
129   DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
130 };
131 
132 template <class ObserverType>
Iterator(ObserverListBase<ObserverType> * list)133 ObserverListBase<ObserverType>::Iterator::Iterator(
134     ObserverListBase<ObserverType>* list)
135     : list_(list->AsWeakPtr()),
136       index_(0),
137       max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
138                                            : list->observers_.size()) {
139   ++list_->notify_depth_;
140 }
141 
142 template <class ObserverType>
~Iterator()143 ObserverListBase<ObserverType>::Iterator::~Iterator() {
144   if (list_.get() && --list_->notify_depth_ == 0)
145     list_->Compact();
146 }
147 
148 template <class ObserverType>
GetNext()149 ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
150   if (!list_.get())
151     return nullptr;
152   ListType& observers = list_->observers_;
153   // Advance if the current element is null
154   size_t max_index = std::min(max_index_, observers.size());
155   while (index_ < max_index && !observers[index_])
156     ++index_;
157   return index_ < max_index ? observers[index_++] : nullptr;
158 }
159 
160 template <class ObserverType>
AddObserver(ObserverType * obs)161 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
162   DCHECK(obs);
163   if (ContainsValue(observers_, obs)) {
164     NOTREACHED() << "Observers can only be added once!";
165     return;
166   }
167   observers_.push_back(obs);
168 }
169 
170 template <class ObserverType>
RemoveObserver(ObserverType * obs)171 void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
172   DCHECK(obs);
173   typename ListType::iterator it =
174     std::find(observers_.begin(), observers_.end(), obs);
175   if (it != observers_.end()) {
176     if (notify_depth_) {
177       *it = nullptr;
178     } else {
179       observers_.erase(it);
180     }
181   }
182 }
183 
184 template <class ObserverType>
HasObserver(const ObserverType * observer)185 bool ObserverListBase<ObserverType>::HasObserver(
186     const ObserverType* observer) const {
187   for (size_t i = 0; i < observers_.size(); ++i) {
188     if (observers_[i] == observer)
189       return true;
190   }
191   return false;
192 }
193 
194 template <class ObserverType>
Clear()195 void ObserverListBase<ObserverType>::Clear() {
196   if (notify_depth_) {
197     for (typename ListType::iterator it = observers_.begin();
198       it != observers_.end(); ++it) {
199       *it = nullptr;
200     }
201   } else {
202     observers_.clear();
203   }
204 }
205 
206 template <class ObserverType>
Compact()207 void ObserverListBase<ObserverType>::Compact() {
208   observers_.erase(
209       std::remove(observers_.begin(), observers_.end(), nullptr),
210       observers_.end());
211 }
212 
213 template <class ObserverType, bool check_empty = false>
214 class ObserverList : public ObserverListBase<ObserverType> {
215  public:
216   typedef typename ObserverListBase<ObserverType>::NotificationType
217       NotificationType;
218 
ObserverList()219   ObserverList() {}
ObserverList(NotificationType type)220   explicit ObserverList(NotificationType type)
221       : ObserverListBase<ObserverType>(type) {}
222 
~ObserverList()223   ~ObserverList() {
224     // When check_empty is true, assert that the list is empty on destruction.
225     if (check_empty) {
226       ObserverListBase<ObserverType>::Compact();
227       DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
228     }
229   }
230 
might_have_observers()231   bool might_have_observers() const {
232     return ObserverListBase<ObserverType>::size() != 0;
233   }
234 };
235 
236 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func)             \
237   do {                                                                   \
238     if ((observer_list).might_have_observers()) {                        \
239       typename base::ObserverListBase<ObserverType>::Iterator            \
240           it_inside_observer_macro(&observer_list);                      \
241       ObserverType* obs;                                                 \
242       while ((obs = it_inside_observer_macro.GetNext()) != nullptr)      \
243         obs->func;                                                       \
244     }                                                                    \
245   } while (0)
246 
247 }  // namespace base
248 
249 #endif  // BASE_OBSERVER_LIST_H_
250