Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(501)

Side by Side Diff: base/observer_list.h

Issue 2340583005: Base ObserverList: Add basic support for standard C++ iterators. (Closed)
Patch Set: Some usages expect macro to be an expression, not a statement. Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | base/observer_list_unittest.cc » ('j') | base/observer_list_unittest.cc » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef BASE_OBSERVER_LIST_H_ 5 #ifndef BASE_OBSERVER_LIST_H_
6 #define BASE_OBSERVER_LIST_H_ 6 #define BASE_OBSERVER_LIST_H_
7 7
8 #include <stddef.h> 8 #include <stddef.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <limits> 11 #include <limits>
12 #include <vector> 12 #include <vector>
13 13
14 #include "base/gtest_prod_util.h"
14 #include "base/logging.h" 15 #include "base/logging.h"
15 #include "base/macros.h" 16 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h" 17 #include "base/memory/weak_ptr.h"
17 #include "base/stl_util.h" 18 #include "base/stl_util.h"
18 19
19 /////////////////////////////////////////////////////////////////////////////// 20 ///////////////////////////////////////////////////////////////////////////////
20 // 21 //
21 // OVERVIEW: 22 // OVERVIEW:
22 // 23 //
23 // A container for a list of observers. Unlike a normal STL vector or list, 24 // A container for a list of observers. Unlike a normal STL vector or list,
(...skipping 15 matching lines...) Expand all
39 // 40 //
40 // void AddObserver(Observer* obs) { 41 // void AddObserver(Observer* obs) {
41 // observer_list_.AddObserver(obs); 42 // observer_list_.AddObserver(obs);
42 // } 43 // }
43 // 44 //
44 // void RemoveObserver(Observer* obs) { 45 // void RemoveObserver(Observer* obs) {
45 // observer_list_.RemoveObserver(obs); 46 // observer_list_.RemoveObserver(obs);
46 // } 47 // }
47 // 48 //
48 // void NotifyFoo() { 49 // void NotifyFoo() {
49 // FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); 50 // for (auto& observer : observer_list_)
51 // observer.OnFoo(this);
50 // } 52 // }
51 // 53 //
52 // void NotifyBar(int x, int y) { 54 // void NotifyBar(int x, int y) {
53 // FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); 55 // for (FooList::iterator i = observer_list.begin(),
56 // e = observer_list.end(); i != e; ++i)
57 // i->OnBar(this, x, y);
54 // } 58 // }
55 // 59 //
56 // private: 60 // private:
57 // base::ObserverList<Observer> observer_list_; 61 // base::ObserverList<Observer> observer_list_;
58 // }; 62 // };
59 // 63 //
60 // 64 //
61 /////////////////////////////////////////////////////////////////////////////// 65 ///////////////////////////////////////////////////////////////////////////////
62 66
63 namespace base { 67 namespace base {
64 68
65 template <typename ObserverType> 69 template <typename ObserverType>
66 class ObserverListThreadSafe; 70 class ObserverListThreadSafe;
67 71
68 template <class ObserverType> 72 template <class ObserverType>
69 class ObserverListBase 73 class ObserverListBase
70 : public SupportsWeakPtr<ObserverListBase<ObserverType>> { 74 : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
71 public: 75 public:
72 // Enumeration of which observers are notified. 76 // Enumeration of which observers are notified.
73 enum NotificationType { 77 enum NotificationType {
74 // Specifies that any observers added during notification are notified. 78 // Specifies that any observers added during notification are notified.
75 // This is the default type if non type is provided to the constructor. 79 // This is the default type if non type is provided to the constructor.
76 NOTIFY_ALL, 80 NOTIFY_ALL,
77 81
78 // Specifies that observers added while sending out notification are not 82 // Specifies that observers added while sending out notification are not
79 // notified. 83 // notified.
80 NOTIFY_EXISTING_ONLY 84 NOTIFY_EXISTING_ONLY
81 }; 85 };
82 86
83 // An iterator class that can be used to access the list of observers. See 87 // An iterator class that can be used to access the list of observers.
84 // also the FOR_EACH_OBSERVER macro defined below. 88 template <class ContainerType>
85 class Iterator { 89 class Iter {
86 public: 90 public:
87 explicit Iterator(ObserverListBase<ObserverType>* list); 91 Iter();
88 ~Iterator(); 92 explicit Iter(ContainerType* list);
93 ~Iter();
94
95 // Deprecated.
89 ObserverType* GetNext(); 96 ObserverType* GetNext();
90 97
98 // A workaround for C2244. MSVC requires fully qualified type name for
99 // return type on a function definition to match a function declaration.
100 using ThisType =
101 typename ObserverListBase<ObserverType>::template Iter<ContainerType>;
102
103 bool operator!=(const Iter& other) const;
104 ThisType& operator++();
105 ObserverType* operator->() const;
106 ObserverType& operator*() const;
107
91 private: 108 private:
92 WeakPtr<ObserverListBase<ObserverType>> list_; 109 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator);
110 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront);
111
112 // TODO(loyso): Clean it up once GetNext is removed.
113 ObserverType* GetNonNullCurrent() const;
114 ObserverType* GetCurrent() const;
115
116 size_t GetNonNullIndex() const;
117
118 size_t clamped_max_index() const {
119 return std::min(max_index_, list_->observers_.size());
120 }
121 WeakPtr<ContainerType> list_;
93 size_t index_; 122 size_t index_;
dcheng 2016/10/05 07:08:24 Let's add a comment to document the invariants for
loyso (OOO) 2016/10/05 07:24:42 What do you mean by "incremented"? This invariant
loyso (OOO) 2016/10/07 03:45:08 Done.
94 size_t max_index_; 123 size_t max_index_;
95 }; 124 };
96 125
126 using Iterator = Iter<ObserverListBase<ObserverType>>;
127
128 using iterator = Iter<ObserverListBase<ObserverType>>;
129 iterator begin() {
130 // An optimization: do not involve weak pointers for empty list.
131 // Note: can't use ?: operator here due to some MSVC bug (unit tests fail)
132 if (observers_.empty())
133 return iterator();
134 return iterator(this);
135 }
136 iterator end() { return iterator(); }
137
138 using const_iterator = Iter<const ObserverListBase<ObserverType>>;
139 const_iterator begin() const {
140 if (observers_.empty())
141 return const_iterator();
142 return const_iterator(this);
143 }
144 const_iterator end() const { return const_iterator(); }
145
97 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} 146 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
98 explicit ObserverListBase(NotificationType type) 147 explicit ObserverListBase(NotificationType type)
99 : notify_depth_(0), type_(type) {} 148 : notify_depth_(0), type_(type) {}
100 149
101 // Add an observer to the list. An observer should not be added to 150 // Add an observer to the list. An observer should not be added to
102 // the same list more than once. 151 // the same list more than once.
103 void AddObserver(ObserverType* obs); 152 void AddObserver(ObserverType* obs);
104 153
105 // Remove an observer from the list if it is in the list. 154 // Remove an observer from the list if it is in the list.
106 void RemoveObserver(ObserverType* obs); 155 void RemoveObserver(ObserverType* obs);
107 156
108 // Determine whether a particular observer is in the list. 157 // Determine whether a particular observer is in the list.
109 bool HasObserver(const ObserverType* observer) const; 158 bool HasObserver(const ObserverType* observer) const;
110 159
111 void Clear(); 160 void Clear();
112 161
113 protected: 162 protected:
114 size_t size() const { return observers_.size(); } 163 size_t size() const { return observers_.size(); }
115 164
116 void Compact(); 165 // Defragments the list despite const.
166 void Compact() const;
117 167
118 private: 168 private:
119 friend class ObserverListThreadSafe<ObserverType>; 169 friend class ObserverListThreadSafe<ObserverType>;
120 170
121 typedef std::vector<ObserverType*> ListType; 171 typedef std::vector<ObserverType*> ListType;
122 172
123 ListType observers_; 173 ListType observers_;
124 int notify_depth_; 174 mutable int notify_depth_;
125 NotificationType type_; 175 NotificationType type_;
126 176
127 friend class ObserverListBase::Iterator; 177 template <class ContainerType>
178 friend class Iter;
128 179
129 DISALLOW_COPY_AND_ASSIGN(ObserverListBase); 180 DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
130 }; 181 };
131 182
132 template <class ObserverType> 183 template <class ObserverType>
133 ObserverListBase<ObserverType>::Iterator::Iterator( 184 template <class ContainerType>
134 ObserverListBase<ObserverType>* list) 185 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter()
135 : list_(list->AsWeakPtr()), 186 : index_(0), max_index_(0) {}
187
188 template <class ObserverType>
189 template <class ContainerType>
190 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list)
191 : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()),
136 index_(0), 192 index_(0),
dcheng 2016/10/05 07:08:23 Then to guarantee the invariant, initialize this t
loyso (OOO) 2016/10/07 03:45:07 Done.
137 max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max() 193 max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
138 : list->observers_.size()) { 194 : list->observers_.size()) {
139 ++list_->notify_depth_; 195 ++list_->notify_depth_;
140 } 196 }
141 197
142 template <class ObserverType> 198 template <class ObserverType>
143 ObserverListBase<ObserverType>::Iterator::~Iterator() { 199 template <class ContainerType>
144 if (list_.get() && --list_->notify_depth_ == 0) 200 ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
201 if (list_ && --list_->notify_depth_ == 0)
145 list_->Compact(); 202 list_->Compact();
146 } 203 }
147 204
148 template <class ObserverType> 205 template <class ObserverType>
149 ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() { 206 template <class ContainerType>
150 if (!list_.get()) 207 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=(
151 return nullptr; 208 const Iter& other) const {
152 ListType& observers = list_->observers_; 209 return GetNonNullCurrent() != other.GetNonNullCurrent();
dcheng 2016/10/05 07:08:23 Hmm. Given this observer list: { nullptr, nullpt
loyso (OOO) 2016/10/07 03:45:07 Done.
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 } 210 }
159 211
160 template <class ObserverType> 212 template <class ObserverType>
213 template <class ContainerType>
214 typename ObserverListBase<ObserverType>::template Iter<ContainerType>&
215 ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() {
216 if (list_) {
217 ++index_;
218 index_ = GetNonNullIndex();
219 }
220 return *this;
221 }
222
223 template <class ObserverType>
224 template <class ContainerType>
225 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->()
226 const {
227 ObserverType* current = GetCurrent();
228 DCHECK(current);
229 return current;
230 }
231
232 template <class ObserverType>
233 template <class ContainerType>
234 ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*()
235 const {
236 ObserverType* current = GetCurrent();
237 DCHECK(current);
238 return *current;
239 }
240
241 template <class ObserverType>
242 template <class ContainerType>
243 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetCurrent()
244 const {
245 if (!list_)
246 return nullptr;
247 return index_ < clamped_max_index() ? list_->observers_[index_] : nullptr;
248 }
249
250 template <class ObserverType>
251 template <class ContainerType>
252 ObserverType*
253 ObserverListBase<ObserverType>::Iter<ContainerType>::GetNonNullCurrent() const {
254 if (!list_)
255 return nullptr;
256 size_t index = GetNonNullIndex();
257 return index < clamped_max_index() ? list_->observers_[index] : nullptr;
258 }
259
260 template <class ObserverType>
261 template <class ContainerType>
262 size_t ObserverListBase<ObserverType>::Iter<ContainerType>::GetNonNullIndex()
263 const {
264 size_t index = index_;
265 size_t max_index = clamped_max_index();
266 while (index < max_index && !list_->observers_[index])
267 ++index;
268 return index;
269 }
270
271 template <class ObserverType>
272 template <class ContainerType>
273 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetNext() {
274 if (!list_)
275 return nullptr;
276
277 ObserverType* current = GetNonNullCurrent();
dcheng 2016/10/05 07:08:24 With the previously mentioned invariant in place,
dcheng 2016/10/05 21:01:15 You're right, this has to be tweaked a bit. But t
278
279 index_ = GetNonNullIndex();
280 ++index_;
281
282 return current;
283 }
284
285 template <class ObserverType>
161 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) { 286 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
162 DCHECK(obs); 287 DCHECK(obs);
163 if (ContainsValue(observers_, obs)) { 288 if (ContainsValue(observers_, obs)) {
164 NOTREACHED() << "Observers can only be added once!"; 289 NOTREACHED() << "Observers can only be added once!";
165 return; 290 return;
166 } 291 }
167 observers_.push_back(obs); 292 observers_.push_back(obs);
168 } 293 }
169 294
170 template <class ObserverType> 295 template <class ObserverType>
(...skipping 26 matching lines...) Expand all
197 for (typename ListType::iterator it = observers_.begin(); 322 for (typename ListType::iterator it = observers_.begin();
198 it != observers_.end(); ++it) { 323 it != observers_.end(); ++it) {
199 *it = nullptr; 324 *it = nullptr;
200 } 325 }
201 } else { 326 } else {
202 observers_.clear(); 327 observers_.clear();
203 } 328 }
204 } 329 }
205 330
206 template <class ObserverType> 331 template <class ObserverType>
207 void ObserverListBase<ObserverType>::Compact() { 332 void ObserverListBase<ObserverType>::Compact() const {
208 observers_.erase( 333 auto& observers = const_cast<ListType&>(observers_);
209 std::remove(observers_.begin(), observers_.end(), nullptr), 334 observers.erase(std::remove(observers.begin(), observers.end(), nullptr),
210 observers_.end()); 335 observers.end());
211 } 336 }
212 337
213 template <class ObserverType, bool check_empty = false> 338 template <class ObserverType, bool check_empty = false>
214 class ObserverList : public ObserverListBase<ObserverType> { 339 class ObserverList : public ObserverListBase<ObserverType> {
215 public: 340 public:
216 typedef typename ObserverListBase<ObserverType>::NotificationType 341 typedef typename ObserverListBase<ObserverType>::NotificationType
217 NotificationType; 342 NotificationType;
218 343
219 ObserverList() {} 344 ObserverList() {}
220 explicit ObserverList(NotificationType type) 345 explicit ObserverList(NotificationType type)
221 : ObserverListBase<ObserverType>(type) {} 346 : ObserverListBase<ObserverType>(type) {}
222 347
223 ~ObserverList() { 348 ~ObserverList() {
224 // When check_empty is true, assert that the list is empty on destruction. 349 // When check_empty is true, assert that the list is empty on destruction.
225 if (check_empty) { 350 if (check_empty) {
226 ObserverListBase<ObserverType>::Compact(); 351 ObserverListBase<ObserverType>::Compact();
227 DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U); 352 DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
228 } 353 }
229 } 354 }
230 355
231 bool might_have_observers() const { 356 bool might_have_observers() const {
232 return ObserverListBase<ObserverType>::size() != 0; 357 return ObserverListBase<ObserverType>::size() != 0;
233 } 358 }
234 }; 359 };
235 360
236 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ 361 // Deprecated. Use the range-based for loop instead.
237 do { \ 362 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
238 if ((observer_list).might_have_observers()) { \ 363 do { \
239 typename base::ObserverListBase<ObserverType>::Iterator \ 364 for (ObserverType& o : observer_list) { \
240 it_inside_observer_macro(&observer_list); \ 365 o.func; \
241 ObserverType* obs; \ 366 } \
242 while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \
243 obs->func; \
244 } \
245 } while (0) 367 } while (0)
246 368
247 } // namespace base 369 } // namespace base
248 370
249 #endif // BASE_OBSERVER_LIST_H_ 371 #endif // BASE_OBSERVER_LIST_H_
OLDNEW
« no previous file with comments | « no previous file | base/observer_list_unittest.cc » ('j') | base/observer_list_unittest.cc » ('J')

Powered by Google App Engine
This is Rietveld 408576698