xref: /aosp_15_r20/external/libchrome/base/observer_list.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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