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