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