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