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