1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file. 4*635a8641SAndroid Build Coastguard Worker 5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_OBSERVER_LIST_H_ 6*635a8641SAndroid Build Coastguard Worker #define BASE_OBSERVER_LIST_H_ 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard Worker #include <stddef.h> 9*635a8641SAndroid Build Coastguard Worker 10*635a8641SAndroid Build Coastguard Worker #include <algorithm> 11*635a8641SAndroid Build Coastguard Worker #include <iterator> 12*635a8641SAndroid Build Coastguard Worker #include <limits> 13*635a8641SAndroid Build Coastguard Worker #include <utility> 14*635a8641SAndroid Build Coastguard Worker #include <vector> 15*635a8641SAndroid Build Coastguard Worker 16*635a8641SAndroid Build Coastguard Worker #include "base/gtest_prod_util.h" 17*635a8641SAndroid Build Coastguard Worker #include "base/logging.h" 18*635a8641SAndroid Build Coastguard Worker #include "base/macros.h" 19*635a8641SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h" 20*635a8641SAndroid Build Coastguard Worker #include "base/stl_util.h" 21*635a8641SAndroid Build Coastguard Worker 22*635a8641SAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////// 23*635a8641SAndroid Build Coastguard Worker // 24*635a8641SAndroid Build Coastguard Worker // OVERVIEW: 25*635a8641SAndroid Build Coastguard Worker // 26*635a8641SAndroid Build Coastguard Worker // A list of observers. Unlike a standard vector or list, this container can 27*635a8641SAndroid Build Coastguard Worker // be modified during iteration without invalidating the iterator. So, it 28*635a8641SAndroid Build Coastguard Worker // safely handles the case of an observer removing itself or other observers 29*635a8641SAndroid Build Coastguard Worker // from the list while observers are being notified. 30*635a8641SAndroid Build Coastguard Worker // 31*635a8641SAndroid Build Coastguard Worker // 32*635a8641SAndroid Build Coastguard Worker // WARNING: 33*635a8641SAndroid Build Coastguard Worker // 34*635a8641SAndroid Build Coastguard Worker // ObserverList is not thread-compatible. Iterating on the same ObserverList 35*635a8641SAndroid Build Coastguard Worker // simultaneously in different threads is not safe, even when the ObserverList 36*635a8641SAndroid Build Coastguard Worker // itself is not modified. 37*635a8641SAndroid Build Coastguard Worker // 38*635a8641SAndroid Build Coastguard Worker // For a thread-safe observer list, see ObserverListThreadSafe. 39*635a8641SAndroid Build Coastguard Worker // 40*635a8641SAndroid Build Coastguard Worker // 41*635a8641SAndroid Build Coastguard Worker // TYPICAL USAGE: 42*635a8641SAndroid Build Coastguard Worker // 43*635a8641SAndroid Build Coastguard Worker // class MyWidget { 44*635a8641SAndroid Build Coastguard Worker // public: 45*635a8641SAndroid Build Coastguard Worker // ... 46*635a8641SAndroid Build Coastguard Worker // 47*635a8641SAndroid Build Coastguard Worker // class Observer { 48*635a8641SAndroid Build Coastguard Worker // public: 49*635a8641SAndroid Build Coastguard Worker // virtual void OnFoo(MyWidget* w) = 0; 50*635a8641SAndroid Build Coastguard Worker // virtual void OnBar(MyWidget* w, int x, int y) = 0; 51*635a8641SAndroid Build Coastguard Worker // }; 52*635a8641SAndroid Build Coastguard Worker // 53*635a8641SAndroid Build Coastguard Worker // void AddObserver(Observer* obs) { 54*635a8641SAndroid Build Coastguard Worker // observers_.AddObserver(obs); 55*635a8641SAndroid Build Coastguard Worker // } 56*635a8641SAndroid Build Coastguard Worker // 57*635a8641SAndroid Build Coastguard Worker // void RemoveObserver(const Observer* obs) { 58*635a8641SAndroid Build Coastguard Worker // observers_.RemoveObserver(obs); 59*635a8641SAndroid Build Coastguard Worker // } 60*635a8641SAndroid Build Coastguard Worker // 61*635a8641SAndroid Build Coastguard Worker // void NotifyFoo() { 62*635a8641SAndroid Build Coastguard Worker // for (Observer& obs : observers_) 63*635a8641SAndroid Build Coastguard Worker // obs.OnFoo(this); 64*635a8641SAndroid Build Coastguard Worker // } 65*635a8641SAndroid Build Coastguard Worker // 66*635a8641SAndroid Build Coastguard Worker // void NotifyBar(int x, int y) { 67*635a8641SAndroid Build Coastguard Worker // for (Observer& obs : observers_) 68*635a8641SAndroid Build Coastguard Worker // obs.OnBar(this, x, y); 69*635a8641SAndroid Build Coastguard Worker // } 70*635a8641SAndroid Build Coastguard Worker // 71*635a8641SAndroid Build Coastguard Worker // private: 72*635a8641SAndroid Build Coastguard Worker // base::ObserverList<Observer> observers_; 73*635a8641SAndroid Build Coastguard Worker // }; 74*635a8641SAndroid Build Coastguard Worker // 75*635a8641SAndroid Build Coastguard Worker // 76*635a8641SAndroid Build Coastguard Worker /////////////////////////////////////////////////////////////////////////////// 77*635a8641SAndroid Build Coastguard Worker 78*635a8641SAndroid Build Coastguard Worker namespace base { 79*635a8641SAndroid Build Coastguard Worker 80*635a8641SAndroid Build Coastguard Worker // Enumeration of which observers are notified by ObserverList. 81*635a8641SAndroid Build Coastguard Worker enum class ObserverListPolicy { 82*635a8641SAndroid Build Coastguard Worker // Specifies that any observers added during notification are notified. 83*635a8641SAndroid Build Coastguard Worker // This is the default policy if no policy is provided to the constructor. 84*635a8641SAndroid Build Coastguard Worker ALL, 85*635a8641SAndroid Build Coastguard Worker 86*635a8641SAndroid Build Coastguard Worker // Specifies that observers added while sending out notification are not 87*635a8641SAndroid Build Coastguard Worker // notified. 88*635a8641SAndroid Build Coastguard Worker EXISTING_ONLY, 89*635a8641SAndroid Build Coastguard Worker }; 90*635a8641SAndroid Build Coastguard Worker 91*635a8641SAndroid Build Coastguard Worker // When check_empty is true, assert that the list is empty on destruction. 92*635a8641SAndroid Build Coastguard Worker // When allow_reentrancy is false, iterating throught the list while already in 93*635a8641SAndroid Build Coastguard Worker // the iteration loop will result in DCHECK failure. 94*635a8641SAndroid Build Coastguard Worker // TODO(oshima): Change the default to non reentrant. https://crbug.com/812109 95*635a8641SAndroid Build Coastguard Worker template <class ObserverType, 96*635a8641SAndroid Build Coastguard Worker bool check_empty = false, 97*635a8641SAndroid Build Coastguard Worker bool allow_reentrancy = true> 98*635a8641SAndroid Build Coastguard Worker class ObserverList 99*635a8641SAndroid Build Coastguard Worker : public SupportsWeakPtr< 100*635a8641SAndroid Build Coastguard Worker ObserverList<ObserverType, check_empty, allow_reentrancy>> { 101*635a8641SAndroid Build Coastguard Worker public: 102*635a8641SAndroid Build Coastguard Worker // An iterator class that can be used to access the list of observers. 103*635a8641SAndroid Build Coastguard Worker class Iter { 104*635a8641SAndroid Build Coastguard Worker public: 105*635a8641SAndroid Build Coastguard Worker using iterator_category = std::forward_iterator_tag; 106*635a8641SAndroid Build Coastguard Worker using value_type = ObserverType; 107*635a8641SAndroid Build Coastguard Worker using difference_type = ptrdiff_t; 108*635a8641SAndroid Build Coastguard Worker using pointer = ObserverType*; 109*635a8641SAndroid Build Coastguard Worker using reference = ObserverType&; 110*635a8641SAndroid Build Coastguard Worker Iter()111*635a8641SAndroid Build Coastguard Worker Iter() : index_(0), max_index_(0) {} 112*635a8641SAndroid Build Coastguard Worker Iter(const ObserverList * list)113*635a8641SAndroid Build Coastguard Worker explicit Iter(const ObserverList* list) 114*635a8641SAndroid Build Coastguard Worker : list_(const_cast<ObserverList*>(list)->AsWeakPtr()), 115*635a8641SAndroid Build Coastguard Worker index_(0), 116*635a8641SAndroid Build Coastguard Worker max_index_(list->policy_ == ObserverListPolicy::ALL 117*635a8641SAndroid Build Coastguard Worker ? std::numeric_limits<size_t>::max() 118*635a8641SAndroid Build Coastguard Worker : list->observers_.size()) { 119*635a8641SAndroid Build Coastguard Worker DCHECK(list_); 120*635a8641SAndroid Build Coastguard Worker DCHECK(allow_reentrancy || !list_->live_iterator_count_); 121*635a8641SAndroid Build Coastguard Worker EnsureValidIndex(); 122*635a8641SAndroid Build Coastguard Worker ++list_->live_iterator_count_; 123*635a8641SAndroid Build Coastguard Worker } 124*635a8641SAndroid Build Coastguard Worker ~Iter()125*635a8641SAndroid Build Coastguard Worker ~Iter() { 126*635a8641SAndroid Build Coastguard Worker if (!list_) 127*635a8641SAndroid Build Coastguard Worker return; 128*635a8641SAndroid Build Coastguard Worker 129*635a8641SAndroid Build Coastguard Worker DCHECK_GT(list_->live_iterator_count_, 0); 130*635a8641SAndroid Build Coastguard Worker if (--list_->live_iterator_count_ == 0) 131*635a8641SAndroid Build Coastguard Worker list_->Compact(); 132*635a8641SAndroid Build Coastguard Worker } 133*635a8641SAndroid Build Coastguard Worker Iter(const Iter & other)134*635a8641SAndroid Build Coastguard Worker Iter(const Iter& other) 135*635a8641SAndroid Build Coastguard Worker : list_(other.list_), 136*635a8641SAndroid Build Coastguard Worker index_(other.index_), 137*635a8641SAndroid Build Coastguard Worker max_index_(other.max_index_) { 138*635a8641SAndroid Build Coastguard Worker if (list_) 139*635a8641SAndroid Build Coastguard Worker ++list_->live_iterator_count_; 140*635a8641SAndroid Build Coastguard Worker } 141*635a8641SAndroid Build Coastguard Worker 142*635a8641SAndroid Build Coastguard Worker Iter& operator=(Iter other) { 143*635a8641SAndroid Build Coastguard Worker using std::swap; 144*635a8641SAndroid Build Coastguard Worker swap(list_, other.list_); 145*635a8641SAndroid Build Coastguard Worker swap(index_, other.index_); 146*635a8641SAndroid Build Coastguard Worker swap(max_index_, other.max_index_); 147*635a8641SAndroid Build Coastguard Worker return *this; 148*635a8641SAndroid Build Coastguard Worker } 149*635a8641SAndroid Build Coastguard Worker 150*635a8641SAndroid Build Coastguard Worker bool operator==(const Iter& other) const { 151*635a8641SAndroid Build Coastguard Worker return (is_end() && other.is_end()) || 152*635a8641SAndroid Build Coastguard Worker (list_.get() == other.list_.get() && index_ == other.index_); 153*635a8641SAndroid Build Coastguard Worker } 154*635a8641SAndroid Build Coastguard Worker 155*635a8641SAndroid Build Coastguard Worker bool operator!=(const Iter& other) const { return !(*this == other); } 156*635a8641SAndroid Build Coastguard Worker 157*635a8641SAndroid Build Coastguard Worker Iter& operator++() { 158*635a8641SAndroid Build Coastguard Worker if (list_) { 159*635a8641SAndroid Build Coastguard Worker ++index_; 160*635a8641SAndroid Build Coastguard Worker EnsureValidIndex(); 161*635a8641SAndroid Build Coastguard Worker } 162*635a8641SAndroid Build Coastguard Worker return *this; 163*635a8641SAndroid Build Coastguard Worker } 164*635a8641SAndroid Build Coastguard Worker 165*635a8641SAndroid Build Coastguard Worker Iter operator++(int) { 166*635a8641SAndroid Build Coastguard Worker Iter it(*this); 167*635a8641SAndroid Build Coastguard Worker ++(*this); 168*635a8641SAndroid Build Coastguard Worker return it; 169*635a8641SAndroid Build Coastguard Worker } 170*635a8641SAndroid Build Coastguard Worker 171*635a8641SAndroid Build Coastguard Worker ObserverType* operator->() const { 172*635a8641SAndroid Build Coastguard Worker ObserverType* const current = GetCurrent(); 173*635a8641SAndroid Build Coastguard Worker DCHECK(current); 174*635a8641SAndroid Build Coastguard Worker return current; 175*635a8641SAndroid Build Coastguard Worker } 176*635a8641SAndroid Build Coastguard Worker 177*635a8641SAndroid Build Coastguard Worker ObserverType& operator*() const { 178*635a8641SAndroid Build Coastguard Worker ObserverType* const current = GetCurrent(); 179*635a8641SAndroid Build Coastguard Worker DCHECK(current); 180*635a8641SAndroid Build Coastguard Worker return *current; 181*635a8641SAndroid Build Coastguard Worker } 182*635a8641SAndroid Build Coastguard Worker 183*635a8641SAndroid Build Coastguard Worker private: 184*635a8641SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator); 185*635a8641SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront); 186*635a8641SAndroid Build Coastguard Worker GetCurrent()187*635a8641SAndroid Build Coastguard Worker ObserverType* GetCurrent() const { 188*635a8641SAndroid Build Coastguard Worker DCHECK(list_); 189*635a8641SAndroid Build Coastguard Worker DCHECK_LT(index_, clamped_max_index()); 190*635a8641SAndroid Build Coastguard Worker return list_->observers_[index_]; 191*635a8641SAndroid Build Coastguard Worker } 192*635a8641SAndroid Build Coastguard Worker EnsureValidIndex()193*635a8641SAndroid Build Coastguard Worker void EnsureValidIndex() { 194*635a8641SAndroid Build Coastguard Worker DCHECK(list_); 195*635a8641SAndroid Build Coastguard Worker const size_t max_index = clamped_max_index(); 196*635a8641SAndroid Build Coastguard Worker while (index_ < max_index && !list_->observers_[index_]) 197*635a8641SAndroid Build Coastguard Worker ++index_; 198*635a8641SAndroid Build Coastguard Worker } 199*635a8641SAndroid Build Coastguard Worker clamped_max_index()200*635a8641SAndroid Build Coastguard Worker size_t clamped_max_index() const { 201*635a8641SAndroid Build Coastguard Worker return std::min(max_index_, list_->observers_.size()); 202*635a8641SAndroid Build Coastguard Worker } 203*635a8641SAndroid Build Coastguard Worker is_end()204*635a8641SAndroid Build Coastguard Worker bool is_end() const { return !list_ || index_ == clamped_max_index(); } 205*635a8641SAndroid Build Coastguard Worker 206*635a8641SAndroid Build Coastguard Worker WeakPtr<ObserverList> list_; 207*635a8641SAndroid Build Coastguard Worker 208*635a8641SAndroid Build Coastguard Worker // When initially constructed and each time the iterator is incremented, 209*635a8641SAndroid Build Coastguard Worker // |index_| is guaranteed to point to a non-null index if the iterator 210*635a8641SAndroid Build Coastguard Worker // has not reached the end of the ObserverList. 211*635a8641SAndroid Build Coastguard Worker size_t index_; 212*635a8641SAndroid Build Coastguard Worker size_t max_index_; 213*635a8641SAndroid Build Coastguard Worker }; 214*635a8641SAndroid Build Coastguard Worker 215*635a8641SAndroid Build Coastguard Worker using iterator = Iter; 216*635a8641SAndroid Build Coastguard Worker using const_iterator = Iter; 217*635a8641SAndroid Build Coastguard Worker begin()218*635a8641SAndroid Build Coastguard Worker const_iterator begin() const { 219*635a8641SAndroid Build Coastguard Worker // An optimization: do not involve weak pointers for empty list. 220*635a8641SAndroid Build Coastguard Worker return observers_.empty() ? const_iterator() : const_iterator(this); 221*635a8641SAndroid Build Coastguard Worker } 222*635a8641SAndroid Build Coastguard Worker end()223*635a8641SAndroid Build Coastguard Worker const_iterator end() const { return const_iterator(); } 224*635a8641SAndroid Build Coastguard Worker 225*635a8641SAndroid Build Coastguard Worker ObserverList() = default; ObserverList(ObserverListPolicy policy)226*635a8641SAndroid Build Coastguard Worker explicit ObserverList(ObserverListPolicy policy) : policy_(policy) {} 227*635a8641SAndroid Build Coastguard Worker ~ObserverList()228*635a8641SAndroid Build Coastguard Worker ~ObserverList() { 229*635a8641SAndroid Build Coastguard Worker if (check_empty) { 230*635a8641SAndroid Build Coastguard Worker Compact(); 231*635a8641SAndroid Build Coastguard Worker DCHECK(observers_.empty()); 232*635a8641SAndroid Build Coastguard Worker } 233*635a8641SAndroid Build Coastguard Worker } 234*635a8641SAndroid Build Coastguard Worker 235*635a8641SAndroid Build Coastguard Worker // Add an observer to this list. An observer should not be added to the same 236*635a8641SAndroid Build Coastguard Worker // list more than once. 237*635a8641SAndroid Build Coastguard Worker // 238*635a8641SAndroid Build Coastguard Worker // Precondition: obs != nullptr 239*635a8641SAndroid Build Coastguard Worker // Precondition: !HasObserver(obs) AddObserver(ObserverType * obs)240*635a8641SAndroid Build Coastguard Worker void AddObserver(ObserverType* obs) { 241*635a8641SAndroid Build Coastguard Worker DCHECK(obs); 242*635a8641SAndroid Build Coastguard Worker if (HasObserver(obs)) { 243*635a8641SAndroid Build Coastguard Worker NOTREACHED() << "Observers can only be added once!"; 244*635a8641SAndroid Build Coastguard Worker return; 245*635a8641SAndroid Build Coastguard Worker } 246*635a8641SAndroid Build Coastguard Worker observers_.push_back(obs); 247*635a8641SAndroid Build Coastguard Worker } 248*635a8641SAndroid Build Coastguard Worker 249*635a8641SAndroid Build Coastguard Worker // Removes the given observer from this list. Does nothing if this observer is 250*635a8641SAndroid Build Coastguard Worker // not in this list. RemoveObserver(const ObserverType * obs)251*635a8641SAndroid Build Coastguard Worker void RemoveObserver(const ObserverType* obs) { 252*635a8641SAndroid Build Coastguard Worker DCHECK(obs); 253*635a8641SAndroid Build Coastguard Worker const auto it = std::find(observers_.begin(), observers_.end(), obs); 254*635a8641SAndroid Build Coastguard Worker if (it == observers_.end()) 255*635a8641SAndroid Build Coastguard Worker return; 256*635a8641SAndroid Build Coastguard Worker 257*635a8641SAndroid Build Coastguard Worker DCHECK_GE(live_iterator_count_, 0); 258*635a8641SAndroid Build Coastguard Worker if (live_iterator_count_) { 259*635a8641SAndroid Build Coastguard Worker *it = nullptr; 260*635a8641SAndroid Build Coastguard Worker } else { 261*635a8641SAndroid Build Coastguard Worker observers_.erase(it); 262*635a8641SAndroid Build Coastguard Worker } 263*635a8641SAndroid Build Coastguard Worker } 264*635a8641SAndroid Build Coastguard Worker 265*635a8641SAndroid Build Coastguard Worker // Determine whether a particular observer is in the list. HasObserver(const ObserverType * obs)266*635a8641SAndroid Build Coastguard Worker bool HasObserver(const ObserverType* obs) const { 267*635a8641SAndroid Build Coastguard Worker return ContainsValue(observers_, obs); 268*635a8641SAndroid Build Coastguard Worker } 269*635a8641SAndroid Build Coastguard Worker 270*635a8641SAndroid Build Coastguard Worker // Removes all the observers from this list. Clear()271*635a8641SAndroid Build Coastguard Worker void Clear() { 272*635a8641SAndroid Build Coastguard Worker DCHECK_GE(live_iterator_count_, 0); 273*635a8641SAndroid Build Coastguard Worker if (live_iterator_count_) { 274*635a8641SAndroid Build Coastguard Worker std::fill(observers_.begin(), observers_.end(), nullptr); 275*635a8641SAndroid Build Coastguard Worker } else { 276*635a8641SAndroid Build Coastguard Worker observers_.clear(); 277*635a8641SAndroid Build Coastguard Worker } 278*635a8641SAndroid Build Coastguard Worker } 279*635a8641SAndroid Build Coastguard Worker might_have_observers()280*635a8641SAndroid Build Coastguard Worker bool might_have_observers() const { return !observers_.empty(); } 281*635a8641SAndroid Build Coastguard Worker 282*635a8641SAndroid Build Coastguard Worker private: 283*635a8641SAndroid Build Coastguard Worker // Compacts list of observers by removing null pointers. Compact()284*635a8641SAndroid Build Coastguard Worker void Compact() { 285*635a8641SAndroid Build Coastguard Worker observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr), 286*635a8641SAndroid Build Coastguard Worker observers_.end()); 287*635a8641SAndroid Build Coastguard Worker } 288*635a8641SAndroid Build Coastguard Worker 289*635a8641SAndroid Build Coastguard Worker std::vector<ObserverType*> observers_; 290*635a8641SAndroid Build Coastguard Worker 291*635a8641SAndroid Build Coastguard Worker // Number of active iterators referencing this ObserverList. 292*635a8641SAndroid Build Coastguard Worker // 293*635a8641SAndroid Build Coastguard Worker // This counter is not synchronized although it is modified by const 294*635a8641SAndroid Build Coastguard Worker // iterators. 295*635a8641SAndroid Build Coastguard Worker int live_iterator_count_ = 0; 296*635a8641SAndroid Build Coastguard Worker 297*635a8641SAndroid Build Coastguard Worker const ObserverListPolicy policy_ = ObserverListPolicy::ALL; 298*635a8641SAndroid Build Coastguard Worker 299*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(ObserverList); 300*635a8641SAndroid Build Coastguard Worker }; 301*635a8641SAndroid Build Coastguard Worker 302*635a8641SAndroid Build Coastguard Worker template <class ObserverType, bool check_empty = false> 303*635a8641SAndroid Build Coastguard Worker using ReentrantObserverList = ObserverList<ObserverType, check_empty, true>; 304*635a8641SAndroid Build Coastguard Worker 305*635a8641SAndroid Build Coastguard Worker } // namespace base 306*635a8641SAndroid Build Coastguard Worker 307*635a8641SAndroid Build Coastguard Worker #endif // BASE_OBSERVER_LIST_H_ 308