1 // Copyright (c) 2010 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 SRC_BASE_OBSERVER_LIST_H_
6 #define SRC_BASE_OBSERVER_LIST_H_
7 
8 #include <algorithm>
9 #include <limits>
10 #include <vector>
11 
12 ///////////////////////////////////////////////////////////////////////////////
13 //
14 // OVERVIEW:
15 //
16 //   A container for a list of observers.  Unlike a normal STL vector or list,
17 //   this container can be modified during iteration without invalidating the
18 //   iterator.  So, it safely handles the case of an observer removing itself
19 //   or other observers from the list while observers are being notified.
20 //
21 // TYPICAL USAGE:
22 //
23 //   class MyWidget {
24 //    public:
25 //     ...
26 //
27 //     class Observer {
28 //      public:
29 //       virtual void OnFoo(MyWidget* w) = 0;
30 //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
31 //     };
32 //
33 //     void AddObserver(Observer* obs) {
34 //       observer_list_.AddObserver(obs);
35 //     }
36 //
37 //     void RemoveObserver(Observer* obs) {
38 //       observer_list_.RemoveObserver(obs);
39 //     }
40 //
41 //     void NotifyFoo() {
42 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
43 //     }
44 //
45 //     void NotifyBar(int x, int y) {
46 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
47 //     }
48 //
49 //    private:
50 //     ObserverList<Observer> observer_list_;
51 //   };
52 //
53 //
54 ///////////////////////////////////////////////////////////////////////////////
55 
56 template <typename ObserverType>
57 class ObserverListThreadSafe;
58 
59 template <class ObserverType>
60 class ObserverListBase {
61  public:
62   // Enumeration of which observers are notified.
63   enum NotificationType {
64     // Specifies that any observers added during notification are notified.
65     // This is the default type if non type is provided to the constructor.
66     NOTIFY_ALL,
67 
68     // Specifies that observers added while sending out notification are not
69     // notified.
70     NOTIFY_EXISTING_ONLY
71   };
72 
73   // An iterator class that can be used to access the list of observers.  See
74   // also the FOR_EACH_OBSERVER macro defined below.
75   class Iterator {
76    public:
Iterator(ObserverListBase<ObserverType> & list)77     explicit Iterator(ObserverListBase<ObserverType>& list)
78         : list_(list),
79           index_(0),
80           max_index_(list.type_ == NOTIFY_ALL ?
81                      std::numeric_limits<size_t>::max() :
82                      list.observers_.size()) {
83       ++list_.notify_depth_;
84     }
85 
~Iterator()86     ~Iterator() {
87       if (--list_.notify_depth_ == 0)
88         list_.Compact();
89     }
90 
GetNext()91     ObserverType* GetNext() {
92       ListType& observers = list_.observers_;
93       // Advance if the current element is null
94       size_t max_index = std::min(max_index_, observers.size());
95       while (index_ < max_index && !observers[index_])
96         ++index_;
97       return index_ < max_index ? observers[index_++] : NULL;
98     }
99 
100    private:
101     ObserverListBase<ObserverType>& list_;
102     size_t index_;
103     size_t max_index_;
104   };
105 
ObserverListBase()106   ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
ObserverListBase(NotificationType type)107   explicit ObserverListBase(NotificationType type)
108       : notify_depth_(0), type_(type) {}
109 
110   // Add an observer to the list.
AddObserver(ObserverType * obs)111   void AddObserver(ObserverType* obs) {
112     observers_.push_back(obs);
113   }
114 
115   // Remove an observer from the list.
RemoveObserver(ObserverType * obs)116   void RemoveObserver(ObserverType* obs) {
117     typename ListType::iterator it =
118       std::find(observers_.begin(), observers_.end(), obs);
119     if (it != observers_.end()) {
120       if (notify_depth_) {
121         *it = 0;
122       } else {
123         observers_.erase(it);
124       }
125     }
126   }
127 
HasObserver(ObserverType * observer)128   bool HasObserver(ObserverType* observer) const {
129     for (size_t i = 0; i < observers_.size(); ++i) {
130       if (observers_[i] == observer)
131         return true;
132     }
133     return false;
134   }
135 
Clear()136   void Clear() {
137     if (notify_depth_) {
138       for (typename ListType::iterator it = observers_.begin();
139            it != observers_.end(); ++it) {
140         *it = 0;
141       }
142     } else {
143       observers_.clear();
144     }
145   }
146 
size()147   size_t size() const { return observers_.size(); }
148 
149  protected:
Compact()150   void Compact() {
151     typename ListType::iterator it = observers_.begin();
152     while (it != observers_.end()) {
153       if (*it) {
154         ++it;
155       } else {
156         it = observers_.erase(it);
157       }
158     }
159   }
160 
161  private:
162   friend class ObserverListThreadSafe<ObserverType>;
163 
164   typedef std::vector<ObserverType*> ListType;
165 
166   ListType observers_;
167   int notify_depth_;
168   NotificationType type_;
169 
170   friend class ObserverListBase::Iterator;
171 };
172 
173 template <class ObserverType, bool check_empty = false>
174 class ObserverList : public ObserverListBase<ObserverType> {
175  public:
176   typedef typename ObserverListBase<ObserverType>::NotificationType
177       NotificationType;
178 
ObserverList()179   ObserverList() {}
ObserverList(NotificationType type)180   explicit ObserverList(NotificationType type)
181       : ObserverListBase<ObserverType>(type) {}
182 
~ObserverList()183   ~ObserverList() {
184     // When check_empty is true, assert that the list is empty on destruction.
185     if (check_empty) {
186       ObserverListBase<ObserverType>::Compact();
187     }
188   }
189 };
190 
191 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func)  \
192   do {                                                        \
193     ObserverListBase<ObserverType>::Iterator it(observer_list);   \
194     ObserverType* obs;                                        \
195     while ((obs = it.GetNext()) != NULL)                      \
196       obs->func;                                              \
197   } while (0)
198 
199 #endif  // SRC_BASE_OBSERVER_LIST_H_
200