[go: nahoru, domu]

blob: f4aad8cde0672391a1415f77b8c26f7487b03e97 [file] [log] [blame]
Avi Drissmane4622aa2022-09-08 20:36:061// Copyright 2011 The Chromium Authors
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
tfarinaa31163512015-05-13 22:10:155#ifndef BASE_OBSERVER_LIST_H_
6#define BASE_OBSERVER_LIST_H_
initial.commitd7cae122008-07-26 21:49:387
avi9b6f42932015-12-26 22:15:148#include <stddef.h>
9
initial.commitd7cae122008-07-26 21:49:3810#include <algorithm>
jdoerrie977dc3f2017-12-12 09:23:3411#include <iterator>
sky@google.comb3e2fad02008-10-31 03:32:0612#include <limits>
Lei Zhang91450eb2021-12-24 02:11:1113#include <ostream>
Sumaid Syed22f60eeb2021-08-26 05:16:2614#include <string>
jdoerrie977dc3f2017-12-12 09:23:3415#include <utility>
sky@google.comb3e2fad02008-10-31 03:32:0616#include <vector>
initial.commitd7cae122008-07-26 21:49:3817
David Sanders8cfb63a2022-04-14 19:36:3018#include "base/check.h"
Hans Wennborg7b533712020-06-22 20:52:2719#include "base/check_op.h"
Lei Zhanga28deed2023-09-28 17:44:3120#include "base/containers/cxx20_erase_vector.h"
David Sandersfc1f17fa2022-04-15 00:15:4921#include "base/dcheck_is_on.h"
Peter Boström807a2a6b2023-04-08 15:20:4922#include "base/debug/dump_without_crashing.h"
Hans Wennborg7b533712020-06-22 20:52:2723#include "base/notreached.h"
Trent Apted30f97fd2018-08-21 09:03:4724#include "base/observer_list_internal.h"
Anton Bikineeva61fb572020-10-18 08:54:4425#include "base/ranges/algorithm.h"
Trent Aptedf59cdf0d32018-10-04 03:42:2226#include "base/sequence_checker.h"
Sylvain Defresnea86596e52023-01-13 18:55:2427#include "build/build_config.h"
initial.commitd7cae122008-07-26 21:49:3828
29///////////////////////////////////////////////////////////////////////////////
30//
31// OVERVIEW:
32//
François Degrosd6e2d7dd2017-11-22 05:37:0233// A list of observers. Unlike a standard vector or list, this container can
34// be modified during iteration without invalidating the iterator. So, it
35// safely handles the case of an observer removing itself or other observers
36// from the list while observers are being notified.
37//
38//
39// WARNING:
40//
41// ObserverList is not thread-compatible. Iterating on the same ObserverList
42// simultaneously in different threads is not safe, even when the ObserverList
43// itself is not modified.
44//
45// For a thread-safe observer list, see ObserverListThreadSafe.
46//
initial.commitd7cae122008-07-26 21:49:3847//
48// TYPICAL USAGE:
49//
50// class MyWidget {
51// public:
52// ...
53//
Rayan Kansod26a60d2019-02-27 16:21:4054// class Observer : public base::CheckedObserver {
initial.commitd7cae122008-07-26 21:49:3855// public:
56// virtual void OnFoo(MyWidget* w) = 0;
57// virtual void OnBar(MyWidget* w, int x, int y) = 0;
58// };
59//
60// void AddObserver(Observer* obs) {
François Degrosd6e2d7dd2017-11-22 05:37:0261// observers_.AddObserver(obs);
initial.commitd7cae122008-07-26 21:49:3862// }
63//
Evan Stade6bd38d42019-10-30 17:55:2364// void RemoveObserver(Observer* obs) {
François Degrosd6e2d7dd2017-11-22 05:37:0265// observers_.RemoveObserver(obs);
initial.commitd7cae122008-07-26 21:49:3866// }
67//
68// void NotifyFoo() {
François Degrosd6e2d7dd2017-11-22 05:37:0269// for (Observer& obs : observers_)
70// obs.OnFoo(this);
initial.commitd7cae122008-07-26 21:49:3871// }
72//
73// void NotifyBar(int x, int y) {
François Degrosd6e2d7dd2017-11-22 05:37:0274// for (Observer& obs : observers_)
75// obs.OnBar(this, x, y);
initial.commitd7cae122008-07-26 21:49:3876// }
77//
78// private:
François Degrosd6e2d7dd2017-11-22 05:37:0279// base::ObserverList<Observer> observers_;
initial.commitd7cae122008-07-26 21:49:3880// };
81//
sky@google.comb3e2fad02008-10-31 03:32:0682//
initial.commitd7cae122008-07-26 21:49:3883///////////////////////////////////////////////////////////////////////////////
84
brettw5a1613dc2015-06-02 05:34:4385namespace base {
86
François Degrosd6e2d7dd2017-11-22 05:37:0287// Enumeration of which observers are notified by ObserverList.
88enum class ObserverListPolicy {
89 // Specifies that any observers added during notification are notified.
90 // This is the default policy if no policy is provided to the constructor.
91 ALL,
92
93 // Specifies that observers added while sending out notification are not
94 // notified.
95 EXISTING_ONLY,
96};
97
98// When check_empty is true, assert that the list is empty on destruction.
Mitsuru Oshima538b1db2018-02-28 04:05:2399// When allow_reentrancy is false, iterating throught the list while already in
100// the iteration loop will result in DCHECK failure.
101// TODO(oshima): Change the default to non reentrant. https://crbug.com/812109
102template <class ObserverType,
103 bool check_empty = false,
Trent Apted30f97fd2018-08-21 09:03:47104 bool allow_reentrancy = true,
105 class ObserverStorageType = internal::CheckedObserverAdapter>
Trent Aptedf59cdf0d32018-10-04 03:42:22106class ObserverList {
initial.commitd7cae122008-07-26 21:49:38107 public:
Trent Apted30f97fd2018-08-21 09:03:47108 // Allow declaring an ObserverList<...>::Unchecked that replaces the default
109 // ObserverStorageType to use raw pointers. This is required to support legacy
Trent Apted453d0b5b2018-08-23 00:13:22110 // observers that do not inherit from CheckedObserver. The majority of new
111 // code should not use this, but it may be suited for performance-critical
Trent Apted30f97fd2018-08-21 09:03:47112 // situations to avoid overheads of a CHECK(). Note the type can't be chosen
113 // based on ObserverType's definition because ObserverLists are often declared
114 // in headers using a forward-declare of ObserverType.
115 using Unchecked = ObserverList<ObserverType,
116 check_empty,
117 allow_reentrancy,
118 internal::UncheckedObserverAdapter>;
Trent Apteda250ec3ab2018-08-19 08:52:19119
loyso29025b62016-10-11 06:51:33120 // An iterator class that can be used to access the list of observers.
loyso29025b62016-10-11 06:51:33121 class Iter {
initial.commitd7cae122008-07-26 21:49:38122 public:
jdoerrie977dc3f2017-12-12 09:23:34123 using iterator_category = std::forward_iterator_tag;
124 using value_type = ObserverType;
125 using difference_type = ptrdiff_t;
126 using pointer = ObserverType*;
127 using reference = ObserverType&;
128
François Degros36991ee2017-11-20 07:38:10129 Iter() : index_(0), max_index_(0) {}
loyso29025b62016-10-11 06:51:33130
François Degrosd6e2d7dd2017-11-22 05:37:02131 explicit Iter(const ObserverList* list)
Trent Aptedf59cdf0d32018-10-04 03:42:22132 : list_(const_cast<ObserverList*>(list)),
François Degros36991ee2017-11-20 07:38:10133 index_(0),
François Degrosd6e2d7dd2017-11-22 05:37:02134 max_index_(list->policy_ == ObserverListPolicy::ALL
François Degros36991ee2017-11-20 07:38:10135 ? std::numeric_limits<size_t>::max()
136 : list->observers_.size()) {
Trent Aptedf59cdf0d32018-10-04 03:42:22137 DCHECK(list);
Peter Boströmbc4629d2023-05-09 03:21:38138 // TODO(crbug.com/1423093): Turn into CHECK once very prevalent failures
139 // are weeded out.
140 DUMP_WILL_BE_CHECK(allow_reentrancy || list_.IsOnlyRemainingNode());
Trent Aptedf59cdf0d32018-10-04 03:42:22141 // Bind to this sequence when creating the first iterator.
142 DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
François Degros36991ee2017-11-20 07:38:10143 EnsureValidIndex();
François Degros36991ee2017-11-20 07:38:10144 }
145
146 ~Iter() {
Trent Aptedf59cdf0d32018-10-04 03:42:22147 if (list_.IsOnlyRemainingNode())
François Degros36991ee2017-11-20 07:38:10148 list_->Compact();
149 }
150
François Degros0659d69332017-11-15 09:31:44151 Iter(const Iter& other)
Trent Aptedf59cdf0d32018-10-04 03:42:22152 : index_(other.index_), max_index_(other.max_index_) {
153 if (other.list_)
154 list_.SetList(other.list_.get());
François Degros0659d69332017-11-15 09:31:44155 }
156
Trent Aptedf59cdf0d32018-10-04 03:42:22157 Iter& operator=(const Iter& other) {
158 if (&other == this)
159 return *this;
160
161 if (list_.IsOnlyRemainingNode())
162 list_->Compact();
163
164 list_.Invalidate();
165 if (other.list_)
166 list_.SetList(other.list_.get());
167
168 index_ = other.index_;
169 max_index_ = other.max_index_;
François Degros0659d69332017-11-15 09:31:44170 return *this;
171 }
172
François Degros36991ee2017-11-20 07:38:10173 bool operator==(const Iter& other) const {
174 return (is_end() && other.is_end()) ||
175 (list_.get() == other.list_.get() && index_ == other.index_);
176 }
loyso29025b62016-10-11 06:51:33177
François Degros36991ee2017-11-20 07:38:10178 bool operator!=(const Iter& other) const { return !(*this == other); }
179
180 Iter& operator++() {
181 if (list_) {
182 ++index_;
183 EnsureValidIndex();
184 }
185 return *this;
186 }
187
jdoerrie977dc3f2017-12-12 09:23:34188 Iter operator++(int) {
189 Iter it(*this);
190 ++(*this);
191 return it;
192 }
193
François Degros36991ee2017-11-20 07:38:10194 ObserverType* operator->() const {
195 ObserverType* const current = GetCurrent();
196 DCHECK(current);
197 return current;
198 }
199
200 ObserverType& operator*() const {
201 ObserverType* const current = GetCurrent();
202 DCHECK(current);
203 return *current;
204 }
loyso29025b62016-10-11 06:51:33205
initial.commitd7cae122008-07-26 21:49:38206 private:
Trent Apted30f97fd2018-08-21 09:03:47207 friend class ObserverListTestBase;
loyso29025b62016-10-11 06:51:33208
François Degros36991ee2017-11-20 07:38:10209 ObserverType* GetCurrent() const {
210 DCHECK(list_);
211 DCHECK_LT(index_, clamped_max_index());
Trent Apted30f97fd2018-08-21 09:03:47212 return ObserverStorageType::template Get<ObserverType>(
213 list_->observers_[index_]);
François Degros36991ee2017-11-20 07:38:10214 }
215
216 void EnsureValidIndex() {
217 DCHECK(list_);
218 const size_t max_index = clamped_max_index();
Trent Apted30f97fd2018-08-21 09:03:47219 while (index_ < max_index &&
220 list_->observers_[index_].IsMarkedForRemoval()) {
François Degros36991ee2017-11-20 07:38:10221 ++index_;
Trent Apted30f97fd2018-08-21 09:03:47222 }
François Degros36991ee2017-11-20 07:38:10223 }
loyso29025b62016-10-11 06:51:33224
225 size_t clamped_max_index() const {
226 return std::min(max_index_, list_->observers_.size());
227 }
228
229 bool is_end() const { return !list_ || index_ == clamped_max_index(); }
230
Trent Aptedf59cdf0d32018-10-04 03:42:22231 // Lightweight weak pointer to the ObserverList.
232 internal::WeakLinkNode<ObserverList> list_;
François Degros36991ee2017-11-20 07:38:10233
loyso29025b62016-10-11 06:51:33234 // When initially constructed and each time the iterator is incremented,
235 // |index_| is guaranteed to point to a non-null index if the iterator
236 // has not reached the end of the ObserverList.
initial.commitd7cae122008-07-26 21:49:38237 size_t index_;
sky@google.comb3e2fad02008-10-31 03:32:06238 size_t max_index_;
initial.commitd7cae122008-07-26 21:49:38239 };
240
François Degros36991ee2017-11-20 07:38:10241 using iterator = Iter;
242 using const_iterator = Iter;
Trent Apted30f97fd2018-08-21 09:03:47243 using value_type = ObserverType;
loyso29025b62016-10-11 06:51:33244
loyso29025b62016-10-11 06:51:33245 const_iterator begin() const {
François Degros36991ee2017-11-20 07:38:10246 // An optimization: do not involve weak pointers for empty list.
247 return observers_.empty() ? const_iterator() : const_iterator(this);
loyso29025b62016-10-11 06:51:33248 }
François Degros36991ee2017-11-20 07:38:10249
loyso29025b62016-10-11 06:51:33250 const_iterator end() const { return const_iterator(); }
251
Oskar Sundbomc92fda62018-10-24 11:38:02252 explicit ObserverList(ObserverListPolicy policy = ObserverListPolicy::ALL)
253 : policy_(policy) {
Trent Aptedf59cdf0d32018-10-04 03:42:22254 // Sequence checks only apply when iterators are live.
255 DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
256 }
David Bienvenub4b441e2020-09-23 05:49:57257 ObserverList(const ObserverList&) = delete;
258 ObserverList& operator=(const ObserverList&) = delete;
François Degrosd6e2d7dd2017-11-22 05:37:02259 ~ObserverList() {
Trent Aptedf59cdf0d32018-10-04 03:42:22260 // If there are live iterators, ensure destruction is thread-safe.
261 if (!live_iterators_.empty())
262 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
263
264 while (!live_iterators_.empty())
265 live_iterators_.head()->value()->Invalidate();
François Degrosd6e2d7dd2017-11-22 05:37:02266 if (check_empty) {
267 Compact();
Peter Boströmbc4629d2023-05-09 03:21:38268 // TODO(crbug.com/1423093): Turn into a CHECK once very prevalent failures
269 // are weeded out.
270 DUMP_WILL_BE_CHECK(observers_.empty())
271 << "\n"
272 << GetObserversCreationStackString();
François Degrosd6e2d7dd2017-11-22 05:37:02273 }
274 }
initial.commitd7cae122008-07-26 21:49:38275
François Degros36991ee2017-11-20 07:38:10276 // Add an observer to this list. An observer should not be added to the same
277 // list more than once.
278 //
279 // Precondition: obs != nullptr
280 // Precondition: !HasObserver(obs)
281 void AddObserver(ObserverType* obs) {
282 DCHECK(obs);
Peter Boström807a2a6b2023-04-08 15:20:49283 // TODO(crbug.com/1423093): Turn this into a CHECK once very prevalent
284 // failures are weeded out.
Xiyuan Xia406bc1e2023-02-22 07:32:22285 if (HasObserver(obs)) {
286 NOTREACHED() << "Observers can only be added once!";
287 return;
288 }
Mitsuru Oshima71ad7332020-12-04 02:55:38289 observers_count_++;
Trent Apted30f97fd2018-08-21 09:03:47290 observers_.emplace_back(ObserverStorageType(obs));
François Degros36991ee2017-11-20 07:38:10291 }
willchan@chromium.org84aebed2010-02-25 03:09:41292
François Degros36991ee2017-11-20 07:38:10293 // Removes the given observer from this list. Does nothing if this observer is
294 // not in this list.
295 void RemoveObserver(const ObserverType* obs) {
296 DCHECK(obs);
Anton Bikineeva61fb572020-10-18 08:54:44297 const auto it = ranges::find_if(
298 observers_, [obs](const auto& o) { return o.IsEqual(obs); });
François Degros36991ee2017-11-20 07:38:10299 if (it == observers_.end())
300 return;
Mitsuru Oshima71ad7332020-12-04 02:55:38301 if (!it->IsMarkedForRemoval())
302 observers_count_--;
Trent Aptedf59cdf0d32018-10-04 03:42:22303 if (live_iterators_.empty()) {
François Degros36991ee2017-11-20 07:38:10304 observers_.erase(it);
Trent Aptedf59cdf0d32018-10-04 03:42:22305 } else {
306 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
307 it->MarkForRemoval();
François Degros36991ee2017-11-20 07:38:10308 }
309 }
willchan@chromium.org84aebed2010-02-25 03:09:41310
mgiuca64ccf2362014-11-10 06:44:23311 // Determine whether a particular observer is in the list.
François Degros36991ee2017-11-20 07:38:10312 bool HasObserver(const ObserverType* obs) const {
Trent Apted30f97fd2018-08-21 09:03:47313 // Client code passing null could be confused by the treatment of observers
Trent Apted453d0b5b2018-08-23 00:13:22314 // removed mid-iteration. TODO(https://crbug.com/876588): This should
315 // probably DCHECK, but some client code currently does pass null.
Trent Apted30f97fd2018-08-21 09:03:47316 if (obs == nullptr)
317 return false;
Anton Bikineeva61fb572020-10-18 08:54:44318 return ranges::find_if(observers_, [obs](const auto& o) {
319 return o.IsEqual(obs);
320 }) != observers_.end();
François Degros36991ee2017-11-20 07:38:10321 }
willchan@chromium.org84aebed2010-02-25 03:09:41322
François Degros36991ee2017-11-20 07:38:10323 // Removes all the observers from this list.
324 void Clear() {
Trent Aptedf59cdf0d32018-10-04 03:42:22325 if (live_iterators_.empty()) {
326 observers_.clear();
327 } else {
328 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
Trent Apted30f97fd2018-08-21 09:03:47329 for (auto& observer : observers_)
330 observer.MarkForRemoval();
François Degros36991ee2017-11-20 07:38:10331 }
Mitsuru Oshima71ad7332020-12-04 02:55:38332 observers_count_ = 0;
François Degros36991ee2017-11-20 07:38:10333 }
willchan@chromium.org84aebed2010-02-25 03:09:41334
Mitsuru Oshimade680cf2021-01-13 19:22:18335 bool empty() const { return !observers_count_; }
Mitsuru Oshima71ad7332020-12-04 02:55:38336
François Degrosd6e2d7dd2017-11-22 05:37:02337 private:
Trent Aptedf59cdf0d32018-10-04 03:42:22338 friend class internal::WeakLinkNode<ObserverList>;
339
Trent Apted30f97fd2018-08-21 09:03:47340 // Compacts list of observers by removing those marked for removal.
François Degros36991ee2017-11-20 07:38:10341 void Compact() {
Trent Aptedf59cdf0d32018-10-04 03:42:22342 // Detach whenever the last iterator is destroyed. Detaching is safe because
343 // Compact() is only ever called when the last iterator is destroyed.
344 DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
345
Sakib Shabir Tantrayf37bdad2023-09-25 20:52:08346 base::EraseIf(observers_,
347 [](const auto& o) { return o.IsMarkedForRemoval(); });
François Degros36991ee2017-11-20 07:38:10348 }
initial.commitd7cae122008-07-26 21:49:38349
Marc Treibd29f5d582021-02-23 18:32:58350 std::string GetObserversCreationStackString() const {
Peter Boström7a4f04c2023-01-10 17:28:44351#if DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:58352 std::string result;
Sylvain Defresnea86596e52023-01-13 18:55:24353#if BUILDFLAG(IS_IOS)
354 result += "Use go/observer-list-empty to interpret.\n";
355#endif
Hans Wennborgd3c6ab52021-04-01 09:34:51356 for (const auto& observer : observers_) {
357 result += observer.GetCreationStackString();
358 result += "\n";
359 }
Marc Treibd29f5d582021-02-23 18:32:58360 return result;
Peter Boström51b93212021-07-09 20:24:16361#else
Peter Boström7a4f04c2023-01-10 17:28:44362 return "For observer stack traces, build with `dcheck_always_on=true`.";
363#endif // DCHECK_IS_ON()
Marc Treibd29f5d582021-02-23 18:32:58364 }
365
Trent Apted30f97fd2018-08-21 09:03:47366 std::vector<ObserverStorageType> observers_;
François Degros0659d69332017-11-15 09:31:44367
Trent Aptedf59cdf0d32018-10-04 03:42:22368 base::LinkedList<internal::WeakLinkNode<ObserverList>> live_iterators_;
François Degros0659d69332017-11-15 09:31:44369
Mitsuru Oshima71ad7332020-12-04 02:55:38370 size_t observers_count_{0};
371
Oskar Sundbomc92fda62018-10-24 11:38:02372 const ObserverListPolicy policy_;
initial.commitd7cae122008-07-26 21:49:38373
Trent Aptedf59cdf0d32018-10-04 03:42:22374 SEQUENCE_CHECKER(iteration_sequence_checker_);
initial.commitd7cae122008-07-26 21:49:38375};
376
Mitsuru Oshima538b1db2018-02-28 04:05:23377template <class ObserverType, bool check_empty = false>
378using ReentrantObserverList = ObserverList<ObserverType, check_empty, true>;
379
brettw5a1613dc2015-06-02 05:34:43380} // namespace base
381
tfarinaa31163512015-05-13 22:10:15382#endif // BASE_OBSERVER_LIST_H_