xref: /aosp_15_r20/external/cronet/base/observer_list.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2011 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_OBSERVER_LIST_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_OBSERVER_LIST_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <stddef.h>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include <algorithm>
11*6777b538SAndroid Build Coastguard Worker #include <iterator>
12*6777b538SAndroid Build Coastguard Worker #include <limits>
13*6777b538SAndroid Build Coastguard Worker #include <ostream>
14*6777b538SAndroid Build Coastguard Worker #include <string>
15*6777b538SAndroid Build Coastguard Worker #include <utility>
16*6777b538SAndroid Build Coastguard Worker #include <vector>
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/check_op.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/dcheck_is_on.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/debug/dump_without_crashing.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/notreached.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/observer_list_internal.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
26*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
27*6777b538SAndroid Build Coastguard Worker 
28*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
29*6777b538SAndroid Build Coastguard Worker //
30*6777b538SAndroid Build Coastguard Worker // OVERVIEW:
31*6777b538SAndroid Build Coastguard Worker //
32*6777b538SAndroid Build Coastguard Worker //   A list of observers. Unlike a standard vector or list, this container can
33*6777b538SAndroid Build Coastguard Worker //   be modified during iteration without invalidating the iterator. So, it
34*6777b538SAndroid Build Coastguard Worker //   safely handles the case of an observer removing itself or other observers
35*6777b538SAndroid Build Coastguard Worker //   from the list while observers are being notified.
36*6777b538SAndroid Build Coastguard Worker //
37*6777b538SAndroid Build Coastguard Worker //
38*6777b538SAndroid Build Coastguard Worker // WARNING:
39*6777b538SAndroid Build Coastguard Worker //
40*6777b538SAndroid Build Coastguard Worker //   ObserverList is not thread-compatible. Iterating on the same ObserverList
41*6777b538SAndroid Build Coastguard Worker //   simultaneously in different threads is not safe, even when the ObserverList
42*6777b538SAndroid Build Coastguard Worker //   itself is not modified.
43*6777b538SAndroid Build Coastguard Worker //
44*6777b538SAndroid Build Coastguard Worker //   For a thread-safe observer list, see ObserverListThreadSafe.
45*6777b538SAndroid Build Coastguard Worker //
46*6777b538SAndroid Build Coastguard Worker //
47*6777b538SAndroid Build Coastguard Worker // TYPICAL USAGE:
48*6777b538SAndroid Build Coastguard Worker //
49*6777b538SAndroid Build Coastguard Worker //   class MyWidget {
50*6777b538SAndroid Build Coastguard Worker //    public:
51*6777b538SAndroid Build Coastguard Worker //     ...
52*6777b538SAndroid Build Coastguard Worker //
53*6777b538SAndroid Build Coastguard Worker //     class Observer : public base::CheckedObserver {
54*6777b538SAndroid Build Coastguard Worker //      public:
55*6777b538SAndroid Build Coastguard Worker //       virtual void OnFoo(MyWidget* w) = 0;
56*6777b538SAndroid Build Coastguard Worker //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
57*6777b538SAndroid Build Coastguard Worker //     };
58*6777b538SAndroid Build Coastguard Worker //
59*6777b538SAndroid Build Coastguard Worker //     void AddObserver(Observer* obs) {
60*6777b538SAndroid Build Coastguard Worker //       observers_.AddObserver(obs);
61*6777b538SAndroid Build Coastguard Worker //     }
62*6777b538SAndroid Build Coastguard Worker //
63*6777b538SAndroid Build Coastguard Worker //     void RemoveObserver(Observer* obs) {
64*6777b538SAndroid Build Coastguard Worker //       observers_.RemoveObserver(obs);
65*6777b538SAndroid Build Coastguard Worker //     }
66*6777b538SAndroid Build Coastguard Worker //
67*6777b538SAndroid Build Coastguard Worker //     void NotifyFoo() {
68*6777b538SAndroid Build Coastguard Worker //       for (Observer& obs : observers_)
69*6777b538SAndroid Build Coastguard Worker //         obs.OnFoo(this);
70*6777b538SAndroid Build Coastguard Worker //     }
71*6777b538SAndroid Build Coastguard Worker //
72*6777b538SAndroid Build Coastguard Worker //     void NotifyBar(int x, int y) {
73*6777b538SAndroid Build Coastguard Worker //       for (Observer& obs : observers_)
74*6777b538SAndroid Build Coastguard Worker //         obs.OnBar(this, x, y);
75*6777b538SAndroid Build Coastguard Worker //     }
76*6777b538SAndroid Build Coastguard Worker //
77*6777b538SAndroid Build Coastguard Worker //    private:
78*6777b538SAndroid Build Coastguard Worker //     base::ObserverList<Observer> observers_;
79*6777b538SAndroid Build Coastguard Worker //   };
80*6777b538SAndroid Build Coastguard Worker //
81*6777b538SAndroid Build Coastguard Worker //
82*6777b538SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker namespace base {
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker // Enumeration of which observers are notified by ObserverList.
87*6777b538SAndroid Build Coastguard Worker enum class ObserverListPolicy {
88*6777b538SAndroid Build Coastguard Worker   // Specifies that any observers added during notification are notified.
89*6777b538SAndroid Build Coastguard Worker   // This is the default policy if no policy is provided to the constructor.
90*6777b538SAndroid Build Coastguard Worker   ALL,
91*6777b538SAndroid Build Coastguard Worker 
92*6777b538SAndroid Build Coastguard Worker   // Specifies that observers added while sending out notification are not
93*6777b538SAndroid Build Coastguard Worker   // notified.
94*6777b538SAndroid Build Coastguard Worker   EXISTING_ONLY,
95*6777b538SAndroid Build Coastguard Worker };
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker // When check_empty is true, assert that the list is empty on destruction.
98*6777b538SAndroid Build Coastguard Worker // When allow_reentrancy is false, iterating throught the list while already in
99*6777b538SAndroid Build Coastguard Worker // the iteration loop will result in DCHECK failure.
100*6777b538SAndroid Build Coastguard Worker // TODO(oshima): Change the default to non reentrant. https://crbug.com/812109
101*6777b538SAndroid Build Coastguard Worker template <class ObserverType,
102*6777b538SAndroid Build Coastguard Worker           bool check_empty = false,
103*6777b538SAndroid Build Coastguard Worker           bool allow_reentrancy = true,
104*6777b538SAndroid Build Coastguard Worker           class ObserverStorageType = internal::CheckedObserverAdapter>
105*6777b538SAndroid Build Coastguard Worker class ObserverList {
106*6777b538SAndroid Build Coastguard Worker  public:
107*6777b538SAndroid Build Coastguard Worker   // Allow declaring an ObserverList<...>::Unchecked that replaces the default
108*6777b538SAndroid Build Coastguard Worker   // ObserverStorageType to use `raw_ptr<T>`. This is required to support legacy
109*6777b538SAndroid Build Coastguard Worker   // observers that do not inherit from CheckedObserver. The majority of new
110*6777b538SAndroid Build Coastguard Worker   // code should not use this, but it may be suited for performance-critical
111*6777b538SAndroid Build Coastguard Worker   // situations to avoid overheads of a CHECK(). Note the type can't be chosen
112*6777b538SAndroid Build Coastguard Worker   // based on ObserverType's definition because ObserverLists are often declared
113*6777b538SAndroid Build Coastguard Worker   // in headers using a forward-declare of ObserverType.
114*6777b538SAndroid Build Coastguard Worker   using Unchecked = ObserverList<ObserverType,
115*6777b538SAndroid Build Coastguard Worker                                  check_empty,
116*6777b538SAndroid Build Coastguard Worker                                  allow_reentrancy,
117*6777b538SAndroid Build Coastguard Worker                                  internal::UncheckedObserverAdapter<>>;
118*6777b538SAndroid Build Coastguard Worker   // Allow declaring an ObserverList<...>::UncheckedAndDanglingUntriaged that
119*6777b538SAndroid Build Coastguard Worker   // replaces the default ObserverStorageType to use
120*6777b538SAndroid Build Coastguard Worker   // `raw_ptr<T, DanglingUntriaged>`. New use of this alias is strongly
121*6777b538SAndroid Build Coastguard Worker   // discouraged.
122*6777b538SAndroid Build Coastguard Worker   // TODO(crbug.com/40212619): Triage existing dangling observer pointers and
123*6777b538SAndroid Build Coastguard Worker   // remove this alias.
124*6777b538SAndroid Build Coastguard Worker   using UncheckedAndDanglingUntriaged =
125*6777b538SAndroid Build Coastguard Worker       ObserverList<ObserverType,
126*6777b538SAndroid Build Coastguard Worker                    check_empty,
127*6777b538SAndroid Build Coastguard Worker                    allow_reentrancy,
128*6777b538SAndroid Build Coastguard Worker                    internal::UncheckedObserverAdapter<DanglingUntriaged>>;
129*6777b538SAndroid Build Coastguard Worker 
130*6777b538SAndroid Build Coastguard Worker   // An iterator class that can be used to access the list of observers.
131*6777b538SAndroid Build Coastguard Worker   class Iter {
132*6777b538SAndroid Build Coastguard Worker    public:
133*6777b538SAndroid Build Coastguard Worker     using iterator_category = std::forward_iterator_tag;
134*6777b538SAndroid Build Coastguard Worker     using value_type = ObserverType;
135*6777b538SAndroid Build Coastguard Worker     using difference_type = ptrdiff_t;
136*6777b538SAndroid Build Coastguard Worker     using pointer = ObserverType*;
137*6777b538SAndroid Build Coastguard Worker     using reference = ObserverType&;
138*6777b538SAndroid Build Coastguard Worker 
Iter()139*6777b538SAndroid Build Coastguard Worker     Iter() : index_(0), max_index_(0) {}
140*6777b538SAndroid Build Coastguard Worker 
Iter(const ObserverList * list)141*6777b538SAndroid Build Coastguard Worker     explicit Iter(const ObserverList* list)
142*6777b538SAndroid Build Coastguard Worker         : list_(const_cast<ObserverList*>(list)),
143*6777b538SAndroid Build Coastguard Worker           index_(0),
144*6777b538SAndroid Build Coastguard Worker           max_index_(list->policy_ == ObserverListPolicy::ALL
145*6777b538SAndroid Build Coastguard Worker                          ? std::numeric_limits<size_t>::max()
146*6777b538SAndroid Build Coastguard Worker                          : list->observers_.size()) {
147*6777b538SAndroid Build Coastguard Worker       DCHECK(list);
148*6777b538SAndroid Build Coastguard Worker       // TODO(crbug.com/1423093): Turn into CHECK once very prevalent failures
149*6777b538SAndroid Build Coastguard Worker       // are weeded out.
150*6777b538SAndroid Build Coastguard Worker       DUMP_WILL_BE_CHECK(allow_reentrancy || list_.IsOnlyRemainingNode());
151*6777b538SAndroid Build Coastguard Worker       // Bind to this sequence when creating the first iterator.
152*6777b538SAndroid Build Coastguard Worker       DCHECK_CALLED_ON_VALID_SEQUENCE(list_->iteration_sequence_checker_);
153*6777b538SAndroid Build Coastguard Worker       EnsureValidIndex();
154*6777b538SAndroid Build Coastguard Worker     }
155*6777b538SAndroid Build Coastguard Worker 
~Iter()156*6777b538SAndroid Build Coastguard Worker     ~Iter() {
157*6777b538SAndroid Build Coastguard Worker       if (list_.IsOnlyRemainingNode())
158*6777b538SAndroid Build Coastguard Worker         list_->Compact();
159*6777b538SAndroid Build Coastguard Worker     }
160*6777b538SAndroid Build Coastguard Worker 
Iter(const Iter & other)161*6777b538SAndroid Build Coastguard Worker     Iter(const Iter& other)
162*6777b538SAndroid Build Coastguard Worker         : index_(other.index_), max_index_(other.max_index_) {
163*6777b538SAndroid Build Coastguard Worker       if (other.list_)
164*6777b538SAndroid Build Coastguard Worker         list_.SetList(other.list_.get());
165*6777b538SAndroid Build Coastguard Worker     }
166*6777b538SAndroid Build Coastguard Worker 
167*6777b538SAndroid Build Coastguard Worker     Iter& operator=(const Iter& other) {
168*6777b538SAndroid Build Coastguard Worker       if (&other == this)
169*6777b538SAndroid Build Coastguard Worker         return *this;
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker       if (list_.IsOnlyRemainingNode())
172*6777b538SAndroid Build Coastguard Worker         list_->Compact();
173*6777b538SAndroid Build Coastguard Worker 
174*6777b538SAndroid Build Coastguard Worker       list_.Invalidate();
175*6777b538SAndroid Build Coastguard Worker       if (other.list_)
176*6777b538SAndroid Build Coastguard Worker         list_.SetList(other.list_.get());
177*6777b538SAndroid Build Coastguard Worker 
178*6777b538SAndroid Build Coastguard Worker       index_ = other.index_;
179*6777b538SAndroid Build Coastguard Worker       max_index_ = other.max_index_;
180*6777b538SAndroid Build Coastguard Worker       return *this;
181*6777b538SAndroid Build Coastguard Worker     }
182*6777b538SAndroid Build Coastguard Worker 
183*6777b538SAndroid Build Coastguard Worker     bool operator==(const Iter& other) const {
184*6777b538SAndroid Build Coastguard Worker       return (is_end() && other.is_end()) ||
185*6777b538SAndroid Build Coastguard Worker              (list_.get() == other.list_.get() && index_ == other.index_);
186*6777b538SAndroid Build Coastguard Worker     }
187*6777b538SAndroid Build Coastguard Worker 
188*6777b538SAndroid Build Coastguard Worker     bool operator!=(const Iter& other) const { return !(*this == other); }
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker     Iter& operator++() {
191*6777b538SAndroid Build Coastguard Worker       if (list_) {
192*6777b538SAndroid Build Coastguard Worker         ++index_;
193*6777b538SAndroid Build Coastguard Worker         EnsureValidIndex();
194*6777b538SAndroid Build Coastguard Worker       }
195*6777b538SAndroid Build Coastguard Worker       return *this;
196*6777b538SAndroid Build Coastguard Worker     }
197*6777b538SAndroid Build Coastguard Worker 
198*6777b538SAndroid Build Coastguard Worker     Iter operator++(int) {
199*6777b538SAndroid Build Coastguard Worker       Iter it(*this);
200*6777b538SAndroid Build Coastguard Worker       ++(*this);
201*6777b538SAndroid Build Coastguard Worker       return it;
202*6777b538SAndroid Build Coastguard Worker     }
203*6777b538SAndroid Build Coastguard Worker 
204*6777b538SAndroid Build Coastguard Worker     ObserverType* operator->() const {
205*6777b538SAndroid Build Coastguard Worker       ObserverType* const current = GetCurrent();
206*6777b538SAndroid Build Coastguard Worker       DCHECK(current);
207*6777b538SAndroid Build Coastguard Worker       return current;
208*6777b538SAndroid Build Coastguard Worker     }
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker     ObserverType& operator*() const {
211*6777b538SAndroid Build Coastguard Worker       ObserverType* const current = GetCurrent();
212*6777b538SAndroid Build Coastguard Worker       DCHECK(current);
213*6777b538SAndroid Build Coastguard Worker       return *current;
214*6777b538SAndroid Build Coastguard Worker     }
215*6777b538SAndroid Build Coastguard Worker 
216*6777b538SAndroid Build Coastguard Worker    private:
217*6777b538SAndroid Build Coastguard Worker     friend class ObserverListTestBase;
218*6777b538SAndroid Build Coastguard Worker 
GetCurrent()219*6777b538SAndroid Build Coastguard Worker     ObserverType* GetCurrent() const {
220*6777b538SAndroid Build Coastguard Worker       DCHECK(list_);
221*6777b538SAndroid Build Coastguard Worker       DCHECK_LT(index_, clamped_max_index());
222*6777b538SAndroid Build Coastguard Worker       return ObserverStorageType::template Get<ObserverType>(
223*6777b538SAndroid Build Coastguard Worker           list_->observers_[index_]);
224*6777b538SAndroid Build Coastguard Worker     }
225*6777b538SAndroid Build Coastguard Worker 
EnsureValidIndex()226*6777b538SAndroid Build Coastguard Worker     void EnsureValidIndex() {
227*6777b538SAndroid Build Coastguard Worker       DCHECK(list_);
228*6777b538SAndroid Build Coastguard Worker       const size_t max_index = clamped_max_index();
229*6777b538SAndroid Build Coastguard Worker       while (index_ < max_index &&
230*6777b538SAndroid Build Coastguard Worker              list_->observers_[index_].IsMarkedForRemoval()) {
231*6777b538SAndroid Build Coastguard Worker         ++index_;
232*6777b538SAndroid Build Coastguard Worker       }
233*6777b538SAndroid Build Coastguard Worker     }
234*6777b538SAndroid Build Coastguard Worker 
clamped_max_index()235*6777b538SAndroid Build Coastguard Worker     size_t clamped_max_index() const {
236*6777b538SAndroid Build Coastguard Worker       return std::min(max_index_, list_->observers_.size());
237*6777b538SAndroid Build Coastguard Worker     }
238*6777b538SAndroid Build Coastguard Worker 
is_end()239*6777b538SAndroid Build Coastguard Worker     bool is_end() const { return !list_ || index_ == clamped_max_index(); }
240*6777b538SAndroid Build Coastguard Worker 
241*6777b538SAndroid Build Coastguard Worker     // Lightweight weak pointer to the ObserverList.
242*6777b538SAndroid Build Coastguard Worker     internal::WeakLinkNode<ObserverList> list_;
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker     // When initially constructed and each time the iterator is incremented,
245*6777b538SAndroid Build Coastguard Worker     // |index_| is guaranteed to point to a non-null index if the iterator
246*6777b538SAndroid Build Coastguard Worker     // has not reached the end of the ObserverList.
247*6777b538SAndroid Build Coastguard Worker     size_t index_;
248*6777b538SAndroid Build Coastguard Worker     size_t max_index_;
249*6777b538SAndroid Build Coastguard Worker   };
250*6777b538SAndroid Build Coastguard Worker 
251*6777b538SAndroid Build Coastguard Worker   using iterator = Iter;
252*6777b538SAndroid Build Coastguard Worker   using const_iterator = Iter;
253*6777b538SAndroid Build Coastguard Worker   using value_type = ObserverType;
254*6777b538SAndroid Build Coastguard Worker 
begin()255*6777b538SAndroid Build Coastguard Worker   const_iterator begin() const {
256*6777b538SAndroid Build Coastguard Worker     DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
257*6777b538SAndroid Build Coastguard Worker     // An optimization: do not involve weak pointers for empty list.
258*6777b538SAndroid Build Coastguard Worker     return observers_.empty() ? const_iterator() : const_iterator(this);
259*6777b538SAndroid Build Coastguard Worker   }
260*6777b538SAndroid Build Coastguard Worker 
end()261*6777b538SAndroid Build Coastguard Worker   const_iterator end() const { return const_iterator(); }
262*6777b538SAndroid Build Coastguard Worker 
263*6777b538SAndroid Build Coastguard Worker   explicit ObserverList(ObserverListPolicy policy = ObserverListPolicy::ALL)
policy_(policy)264*6777b538SAndroid Build Coastguard Worker       : policy_(policy) {
265*6777b538SAndroid Build Coastguard Worker     // Sequence checks only apply when iterators are live.
266*6777b538SAndroid Build Coastguard Worker     DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
267*6777b538SAndroid Build Coastguard Worker   }
268*6777b538SAndroid Build Coastguard Worker   ObserverList(const ObserverList&) = delete;
269*6777b538SAndroid Build Coastguard Worker   ObserverList& operator=(const ObserverList&) = delete;
~ObserverList()270*6777b538SAndroid Build Coastguard Worker   ~ObserverList() {
271*6777b538SAndroid Build Coastguard Worker     // If there are live iterators, ensure destruction is thread-safe.
272*6777b538SAndroid Build Coastguard Worker     if (!live_iterators_.empty())
273*6777b538SAndroid Build Coastguard Worker       DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
274*6777b538SAndroid Build Coastguard Worker 
275*6777b538SAndroid Build Coastguard Worker     while (!live_iterators_.empty())
276*6777b538SAndroid Build Coastguard Worker       live_iterators_.head()->value()->Invalidate();
277*6777b538SAndroid Build Coastguard Worker     if (check_empty) {
278*6777b538SAndroid Build Coastguard Worker       Compact();
279*6777b538SAndroid Build Coastguard Worker       // TODO(crbug.com/1423093): Turn into a CHECK once very prevalent failures
280*6777b538SAndroid Build Coastguard Worker       // are weeded out.
281*6777b538SAndroid Build Coastguard Worker       DUMP_WILL_BE_CHECK(observers_.empty())
282*6777b538SAndroid Build Coastguard Worker           << "\n"
283*6777b538SAndroid Build Coastguard Worker           << GetObserversCreationStackString();
284*6777b538SAndroid Build Coastguard Worker     }
285*6777b538SAndroid Build Coastguard Worker   }
286*6777b538SAndroid Build Coastguard Worker 
287*6777b538SAndroid Build Coastguard Worker   // Add an observer to this list. An observer should not be added to the same
288*6777b538SAndroid Build Coastguard Worker   // list more than once.
289*6777b538SAndroid Build Coastguard Worker   //
290*6777b538SAndroid Build Coastguard Worker   // Precondition: obs != nullptr
291*6777b538SAndroid Build Coastguard Worker   // Precondition: !HasObserver(obs)
AddObserver(ObserverType * obs)292*6777b538SAndroid Build Coastguard Worker   void AddObserver(ObserverType* obs) {
293*6777b538SAndroid Build Coastguard Worker     DCHECK(obs);
294*6777b538SAndroid Build Coastguard Worker     // TODO(crbug.com/1423093): Turn this into a CHECK once very prevalent
295*6777b538SAndroid Build Coastguard Worker     // failures are weeded out.
296*6777b538SAndroid Build Coastguard Worker     if (HasObserver(obs)) {
297*6777b538SAndroid Build Coastguard Worker       DUMP_WILL_BE_NOTREACHED_NORETURN() << "Observers can only be added once!";
298*6777b538SAndroid Build Coastguard Worker       return;
299*6777b538SAndroid Build Coastguard Worker     }
300*6777b538SAndroid Build Coastguard Worker     observers_count_++;
301*6777b538SAndroid Build Coastguard Worker     observers_.emplace_back(ObserverStorageType(obs));
302*6777b538SAndroid Build Coastguard Worker   }
303*6777b538SAndroid Build Coastguard Worker 
304*6777b538SAndroid Build Coastguard Worker   // Removes the given observer from this list. Does nothing if this observer is
305*6777b538SAndroid Build Coastguard Worker   // not in this list.
RemoveObserver(const ObserverType * obs)306*6777b538SAndroid Build Coastguard Worker   void RemoveObserver(const ObserverType* obs) {
307*6777b538SAndroid Build Coastguard Worker     DCHECK(obs);
308*6777b538SAndroid Build Coastguard Worker     const auto it = ranges::find_if(
309*6777b538SAndroid Build Coastguard Worker         observers_, [obs](const auto& o) { return o.IsEqual(obs); });
310*6777b538SAndroid Build Coastguard Worker     if (it == observers_.end())
311*6777b538SAndroid Build Coastguard Worker       return;
312*6777b538SAndroid Build Coastguard Worker     if (!it->IsMarkedForRemoval())
313*6777b538SAndroid Build Coastguard Worker       observers_count_--;
314*6777b538SAndroid Build Coastguard Worker     if (live_iterators_.empty()) {
315*6777b538SAndroid Build Coastguard Worker       observers_.erase(it);
316*6777b538SAndroid Build Coastguard Worker     } else {
317*6777b538SAndroid Build Coastguard Worker       DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
318*6777b538SAndroid Build Coastguard Worker       it->MarkForRemoval();
319*6777b538SAndroid Build Coastguard Worker     }
320*6777b538SAndroid Build Coastguard Worker   }
321*6777b538SAndroid Build Coastguard Worker 
322*6777b538SAndroid Build Coastguard Worker   // Determine whether a particular observer is in the list.
HasObserver(const ObserverType * obs)323*6777b538SAndroid Build Coastguard Worker   bool HasObserver(const ObserverType* obs) const {
324*6777b538SAndroid Build Coastguard Worker     // Client code passing null could be confused by the treatment of observers
325*6777b538SAndroid Build Coastguard Worker     // removed mid-iteration. TODO(https://crbug.com/876588): This should
326*6777b538SAndroid Build Coastguard Worker     // probably DCHECK, but some client code currently does pass null.
327*6777b538SAndroid Build Coastguard Worker     if (obs == nullptr)
328*6777b538SAndroid Build Coastguard Worker       return false;
329*6777b538SAndroid Build Coastguard Worker     return ranges::find_if(observers_, [obs](const auto& o) {
330*6777b538SAndroid Build Coastguard Worker              return o.IsEqual(obs);
331*6777b538SAndroid Build Coastguard Worker            }) != observers_.end();
332*6777b538SAndroid Build Coastguard Worker   }
333*6777b538SAndroid Build Coastguard Worker 
334*6777b538SAndroid Build Coastguard Worker   // Removes all the observers from this list.
Clear()335*6777b538SAndroid Build Coastguard Worker   void Clear() {
336*6777b538SAndroid Build Coastguard Worker     if (live_iterators_.empty()) {
337*6777b538SAndroid Build Coastguard Worker       observers_.clear();
338*6777b538SAndroid Build Coastguard Worker     } else {
339*6777b538SAndroid Build Coastguard Worker       DCHECK_CALLED_ON_VALID_SEQUENCE(iteration_sequence_checker_);
340*6777b538SAndroid Build Coastguard Worker       for (auto& observer : observers_)
341*6777b538SAndroid Build Coastguard Worker         observer.MarkForRemoval();
342*6777b538SAndroid Build Coastguard Worker     }
343*6777b538SAndroid Build Coastguard Worker     observers_count_ = 0;
344*6777b538SAndroid Build Coastguard Worker   }
345*6777b538SAndroid Build Coastguard Worker 
empty()346*6777b538SAndroid Build Coastguard Worker   bool empty() const { return !observers_count_; }
347*6777b538SAndroid Build Coastguard Worker 
348*6777b538SAndroid Build Coastguard Worker  private:
349*6777b538SAndroid Build Coastguard Worker   friend class internal::WeakLinkNode<ObserverList>;
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker   // Compacts list of observers by removing those marked for removal.
Compact()352*6777b538SAndroid Build Coastguard Worker   void Compact() {
353*6777b538SAndroid Build Coastguard Worker     // Detach whenever the last iterator is destroyed. Detaching is safe because
354*6777b538SAndroid Build Coastguard Worker     // Compact() is only ever called when the last iterator is destroyed.
355*6777b538SAndroid Build Coastguard Worker     DETACH_FROM_SEQUENCE(iteration_sequence_checker_);
356*6777b538SAndroid Build Coastguard Worker 
357*6777b538SAndroid Build Coastguard Worker     std::erase_if(observers_,
358*6777b538SAndroid Build Coastguard Worker                   [](const auto& o) { return o.IsMarkedForRemoval(); });
359*6777b538SAndroid Build Coastguard Worker   }
360*6777b538SAndroid Build Coastguard Worker 
GetObserversCreationStackString()361*6777b538SAndroid Build Coastguard Worker   std::string GetObserversCreationStackString() const {
362*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
363*6777b538SAndroid Build Coastguard Worker     std::string result;
364*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_IOS)
365*6777b538SAndroid Build Coastguard Worker     result += "Use go/observer-list-empty to interpret.\n";
366*6777b538SAndroid Build Coastguard Worker #endif
367*6777b538SAndroid Build Coastguard Worker     for (const auto& observer : observers_) {
368*6777b538SAndroid Build Coastguard Worker       result += observer.GetCreationStackString();
369*6777b538SAndroid Build Coastguard Worker       result += "\n";
370*6777b538SAndroid Build Coastguard Worker     }
371*6777b538SAndroid Build Coastguard Worker     return result;
372*6777b538SAndroid Build Coastguard Worker #else
373*6777b538SAndroid Build Coastguard Worker     return "For observer stack traces, build with `dcheck_always_on=true`.";
374*6777b538SAndroid Build Coastguard Worker #endif  // DCHECK_IS_ON()
375*6777b538SAndroid Build Coastguard Worker   }
376*6777b538SAndroid Build Coastguard Worker 
377*6777b538SAndroid Build Coastguard Worker   std::vector<ObserverStorageType> observers_;
378*6777b538SAndroid Build Coastguard Worker 
379*6777b538SAndroid Build Coastguard Worker   base::LinkedList<internal::WeakLinkNode<ObserverList>> live_iterators_;
380*6777b538SAndroid Build Coastguard Worker 
381*6777b538SAndroid Build Coastguard Worker   size_t observers_count_{0};
382*6777b538SAndroid Build Coastguard Worker 
383*6777b538SAndroid Build Coastguard Worker   const ObserverListPolicy policy_;
384*6777b538SAndroid Build Coastguard Worker 
385*6777b538SAndroid Build Coastguard Worker   SEQUENCE_CHECKER(iteration_sequence_checker_);
386*6777b538SAndroid Build Coastguard Worker };
387*6777b538SAndroid Build Coastguard Worker 
388*6777b538SAndroid Build Coastguard Worker template <class ObserverType, bool check_empty = false>
389*6777b538SAndroid Build Coastguard Worker using ReentrantObserverList = ObserverList<ObserverType, check_empty, true>;
390*6777b538SAndroid Build Coastguard Worker 
391*6777b538SAndroid Build Coastguard Worker }  // namespace base
392*6777b538SAndroid Build Coastguard Worker 
393*6777b538SAndroid Build Coastguard Worker #endif  // BASE_OBSERVER_LIST_H_
394