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
3 // found in the LICENSE file.
5 #ifndef BASE_OBSERVER_LIST_H_
6 #define BASE_OBSERVER_LIST_H_
16 #include "base/check_op.h"
17 #include "base/gtest_prod_util.h"
18 #include "base/macros.h"
19 #include "base/notreached.h"
20 #include "base/observer_list_internal.h"
21 #include "base/sequence_checker.h"
22 #include "base/stl_util.h"
24 ///////////////////////////////////////////////////////////////////////////////
28 // A list of observers. Unlike a standard vector or list, this container can
29 // be modified during iteration without invalidating the iterator. So, it
30 // safely handles the case of an observer removing itself or other observers
31 // from the list while observers are being notified.
36 // ObserverList is not thread-compatible. Iterating on the same ObserverList
37 // simultaneously in different threads is not safe, even when the ObserverList
38 // itself is not modified.
40 // For a thread-safe observer list, see ObserverListThreadSafe.
49 // class Observer : public base::CheckedObserver {
51 // virtual void OnFoo(MyWidget* w) = 0;
52 // virtual void OnBar(MyWidget* w, int x, int y) = 0;
55 // void AddObserver(Observer* obs) {
56 // observers_.AddObserver(obs);
59 // void RemoveObserver(Observer* obs) {
60 // observers_.RemoveObserver(obs);
64 // for (Observer& obs : observers_)
68 // void NotifyBar(int x, int y) {
69 // for (Observer& obs : observers_)
70 // obs.OnBar(this, x, y);
74 // base::ObserverList<Observer> observers_;
78 ///////////////////////////////////////////////////////////////////////////////
82 // Enumeration of which observers are notified by ObserverList.
83 enum class ObserverListPolicy {
84 // Specifies that any observers added during notification are notified.
85 // This is the default policy if no policy is provided to the constructor.
88 // Specifies that observers added while sending out notification are not
93 // When check_empty is true, assert that the list is empty on destruction.
94 // When allow_reentrancy is false, iterating throught the list while already in
95 // the iteration loop will result in DCHECK failure.
96 // TODO(oshima): Change the default to non reentrant. https://crbug.com/812109
97 template <class ObserverType,
98 bool check_empty = false,
99 bool allow_reentrancy = true,
100 class ObserverStorageType = internal::CheckedObserverAdapter>
103 // Allow declaring an ObserverList<...>::Unchecked that replaces the default
104 // ObserverStorageType to use raw pointers. This is required to support legacy
105 // observers that do not inherit from CheckedObserver. The majority of new
106 // code should not use this, but it may be suited for performance-critical
107 // situations to avoid overheads of a CHECK(). Note the type can't be chosen
108 // based on ObserverType's definition because ObserverLists are often declared
109 // in headers using a forward-declare of ObserverType.
110 using Unchecked = ObserverList<ObserverType,
113 internal::UncheckedObserverAdapter>;
115 // An iterator class that can be used to access the list of observers.
118 using iterator_category = std::forward_iterator_tag;
119 using value_type = ObserverType;
120 using difference_type = ptrdiff_t;
121 using pointer = ObserverType*;
122 using reference = ObserverType&;
124 Iter() : index_(0), max_index_(0) {}
126 explicit Iter(const ObserverList* list)
127 : list_(const_cast<ObserverList*>(list)),
129 max_index_(list->policy_ == ObserverListPolicy::ALL
130 ? std::numeric_limits<size_t>::max()
131 : list->observers_.size()) {
133 DCHECK(allow_reentrancy || list_.IsOnlyRemainingNode());
134 // Bind to this sequence when creating the first iterator.
135 DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
140 if (list_.IsOnlyRemainingNode())
144 Iter(const Iter& other)
145 : index_(other.index_), max_index_(other.max_index_) {
147 list_.SetList(other.list_.get());
150 Iter& operator=(const Iter& other) {
154 if (list_.IsOnlyRemainingNode())
159 list_.SetList(other.list_.get());
161 index_ = other.index_;
162 max_index_ = other.max_index_;
166 bool operator==(const Iter& other) const {
167 return (is_end() && other.is_end()) ||
168 (list_.get() == other.list_.get() && index_ == other.index_);
171 bool operator!=(const Iter& other) const { return !(*this == other); }
181 Iter operator++(int) {
187 ObserverType* operator->() const {
188 ObserverType* const current = GetCurrent();
193 ObserverType& operator*() const {
194 ObserverType* const current = GetCurrent();
200 friend class ObserverListTestBase;
202 ObserverType* GetCurrent() const {
204 DCHECK_LT(index_, clamped_max_index());
205 return ObserverStorageType::template Get<ObserverType>(
206 list_->observers_[index_]);
209 void EnsureValidIndex() {
211 const size_t max_index = clamped_max_index();
212 while (index_ < max_index &&
213 list_->observers_[index_].IsMarkedForRemoval()) {
218 size_t clamped_max_index() const {
219 return std::min(max_index_, list_->observers_.size());
222 bool is_end() const { return !list_ || index_ == clamped_max_index(); }
224 // Lightweight weak pointer to the ObserverList.
225 internal::WeakLinkNode<ObserverList> list_;
227 // When initially constructed and each time the iterator is incremented,
228 // |index_| is guaranteed to point to a non-null index if the iterator
229 // has not reached the end of the ObserverList.
234 using iterator = Iter;
235 using const_iterator = Iter;
236 using value_type = ObserverType;
238 const_iterator begin() const {
239 // An optimization: do not involve weak pointers for empty list.
240 return observers_.empty() ? const_iterator() : const_iterator(this);
243 const_iterator end() const { return const_iterator(); }
245 explicit ObserverList(ObserverListPolicy policy = ObserverListPolicy::ALL)
247 // Sequence checks only apply when iterators are live.
248 DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
252 // If there are live iterators, ensure destruction is thread-safe.
253 if (!live_iterators_.empty())
254 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
256 while (!live_iterators_.empty())
257 live_iterators_.head()->value()->Invalidate();
260 DCHECK(observers_.empty());
264 // Add an observer to this list. An observer should not be added to the same
265 // list more than once.
267 // Precondition: obs != nullptr
268 // Precondition: !HasObserver(obs)
269 void AddObserver(ObserverType* obs) {
271 if (HasObserver(obs)) {
272 NOTREACHED() << "Observers can only be added once!";
275 observers_.emplace_back(ObserverStorageType(obs));
278 // Removes the given observer from this list. Does nothing if this observer is
280 void RemoveObserver(const ObserverType* obs) {
283 std::find_if(observers_.begin(), observers_.end(),
284 [obs](const auto& o) { return o.IsEqual(obs); });
285 if (it == observers_.end())
288 if (live_iterators_.empty()) {
289 observers_.erase(it);
291 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
292 it->MarkForRemoval();
296 // Determine whether a particular observer is in the list.
297 bool HasObserver(const ObserverType* obs) const {
298 // Client code passing null could be confused by the treatment of observers
299 // removed mid-iteration. TODO(https://crbug.com/876588): This should
300 // probably DCHECK, but some client code currently does pass null.
303 return std::find_if(observers_.begin(), observers_.end(),
304 [obs](const auto& o) { return o.IsEqual(obs); }) !=
308 // Removes all the observers from this list.
310 if (live_iterators_.empty()) {
313 DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
314 for (auto& observer : observers_)
315 observer.MarkForRemoval();
319 bool might_have_observers() const { return !observers_.empty(); }
322 friend class internal::WeakLinkNode<ObserverList>;
324 // Compacts list of observers by removing those marked for removal.
326 // Detach whenever the last iterator is destroyed. Detaching is safe because
327 // Compact() is only ever called when the last iterator is destroyed.
328 DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
330 EraseIf(observers_, [](const auto& o) { return o.IsMarkedForRemoval(); });
333 std::vector<ObserverStorageType> observers_;
335 base::LinkedList<internal::WeakLinkNode<ObserverList>> live_iterators_;
337 const ObserverListPolicy policy_;
339 SEQUENCE_CHECKER(iteration_sequence_checker_);
341 DISALLOW_COPY_AND_ASSIGN(ObserverList);
344 template <class ObserverType, bool check_empty = false>
345 using ReentrantObserverList = ObserverList<ObserverType, check_empty, true>;
349 #endif // BASE_OBSERVER_LIST_H_