xref: /aosp_15_r20/external/libchrome/base/callback_list.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2013 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_CALLBACK_LIST_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_CALLBACK_LIST_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include <list>
9*635a8641SAndroid Build Coastguard Worker #include <memory>
10*635a8641SAndroid Build Coastguard Worker 
11*635a8641SAndroid Build Coastguard Worker #include "base/callback.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/macros.h"
15*635a8641SAndroid Build Coastguard Worker 
16*635a8641SAndroid Build Coastguard Worker // OVERVIEW:
17*635a8641SAndroid Build Coastguard Worker //
18*635a8641SAndroid Build Coastguard Worker // A container for a list of (repeating) callbacks. Unlike a normal vector or
19*635a8641SAndroid Build Coastguard Worker // list, this container can be modified during iteration without invalidating
20*635a8641SAndroid Build Coastguard Worker // the iterator. It safely handles the case of a callback removing itself or
21*635a8641SAndroid Build Coastguard Worker // another callback from the list while callbacks are being run.
22*635a8641SAndroid Build Coastguard Worker //
23*635a8641SAndroid Build Coastguard Worker // TYPICAL USAGE:
24*635a8641SAndroid Build Coastguard Worker //
25*635a8641SAndroid Build Coastguard Worker // class MyWidget {
26*635a8641SAndroid Build Coastguard Worker //  public:
27*635a8641SAndroid Build Coastguard Worker //   ...
28*635a8641SAndroid Build Coastguard Worker //
29*635a8641SAndroid Build Coastguard Worker //   std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
30*635a8641SAndroid Build Coastguard Worker //   RegisterCallback(const base::RepeatingCallback<void(const Foo&)>& cb) {
31*635a8641SAndroid Build Coastguard Worker //     return callback_list_.Add(cb);
32*635a8641SAndroid Build Coastguard Worker //   }
33*635a8641SAndroid Build Coastguard Worker //
34*635a8641SAndroid Build Coastguard Worker //  private:
35*635a8641SAndroid Build Coastguard Worker //   void NotifyFoo(const Foo& foo) {
36*635a8641SAndroid Build Coastguard Worker //      callback_list_.Notify(foo);
37*635a8641SAndroid Build Coastguard Worker //   }
38*635a8641SAndroid Build Coastguard Worker //
39*635a8641SAndroid Build Coastguard Worker //   base::CallbackList<void(const Foo&)> callback_list_;
40*635a8641SAndroid Build Coastguard Worker //
41*635a8641SAndroid Build Coastguard Worker //   DISALLOW_COPY_AND_ASSIGN(MyWidget);
42*635a8641SAndroid Build Coastguard Worker // };
43*635a8641SAndroid Build Coastguard Worker //
44*635a8641SAndroid Build Coastguard Worker //
45*635a8641SAndroid Build Coastguard Worker // class MyWidgetListener {
46*635a8641SAndroid Build Coastguard Worker //  public:
47*635a8641SAndroid Build Coastguard Worker //   MyWidgetListener::MyWidgetListener() {
48*635a8641SAndroid Build Coastguard Worker //     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
49*635a8641SAndroid Build Coastguard Worker //             base::BindRepeating(&MyWidgetListener::OnFoo, this)));
50*635a8641SAndroid Build Coastguard Worker //   }
51*635a8641SAndroid Build Coastguard Worker //
52*635a8641SAndroid Build Coastguard Worker //   MyWidgetListener::~MyWidgetListener() {
53*635a8641SAndroid Build Coastguard Worker //      // Subscription gets deleted automatically and will deregister
54*635a8641SAndroid Build Coastguard Worker //      // the callback in the process.
55*635a8641SAndroid Build Coastguard Worker //   }
56*635a8641SAndroid Build Coastguard Worker //
57*635a8641SAndroid Build Coastguard Worker //  private:
58*635a8641SAndroid Build Coastguard Worker //   void OnFoo(const Foo& foo) {
59*635a8641SAndroid Build Coastguard Worker //     // Do something.
60*635a8641SAndroid Build Coastguard Worker //   }
61*635a8641SAndroid Build Coastguard Worker //
62*635a8641SAndroid Build Coastguard Worker //   std::unique_ptr<base::CallbackList<void(const Foo&)>::Subscription>
63*635a8641SAndroid Build Coastguard Worker //       foo_subscription_;
64*635a8641SAndroid Build Coastguard Worker //
65*635a8641SAndroid Build Coastguard Worker //   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
66*635a8641SAndroid Build Coastguard Worker // };
67*635a8641SAndroid Build Coastguard Worker 
68*635a8641SAndroid Build Coastguard Worker namespace base {
69*635a8641SAndroid Build Coastguard Worker 
70*635a8641SAndroid Build Coastguard Worker namespace internal {
71*635a8641SAndroid Build Coastguard Worker 
72*635a8641SAndroid Build Coastguard Worker template <typename CallbackType>
73*635a8641SAndroid Build Coastguard Worker class CallbackListBase {
74*635a8641SAndroid Build Coastguard Worker  public:
75*635a8641SAndroid Build Coastguard Worker   class Subscription {
76*635a8641SAndroid Build Coastguard Worker    public:
Subscription(CallbackListBase<CallbackType> * list,typename std::list<CallbackType>::iterator iter)77*635a8641SAndroid Build Coastguard Worker     Subscription(CallbackListBase<CallbackType>* list,
78*635a8641SAndroid Build Coastguard Worker                  typename std::list<CallbackType>::iterator iter)
79*635a8641SAndroid Build Coastguard Worker         : list_(list),
80*635a8641SAndroid Build Coastguard Worker           iter_(iter) {
81*635a8641SAndroid Build Coastguard Worker     }
82*635a8641SAndroid Build Coastguard Worker 
~Subscription()83*635a8641SAndroid Build Coastguard Worker     ~Subscription() {
84*635a8641SAndroid Build Coastguard Worker       if (list_->active_iterator_count_) {
85*635a8641SAndroid Build Coastguard Worker         iter_->Reset();
86*635a8641SAndroid Build Coastguard Worker       } else {
87*635a8641SAndroid Build Coastguard Worker         list_->callbacks_.erase(iter_);
88*635a8641SAndroid Build Coastguard Worker         if (!list_->removal_callback_.is_null())
89*635a8641SAndroid Build Coastguard Worker           list_->removal_callback_.Run();
90*635a8641SAndroid Build Coastguard Worker       }
91*635a8641SAndroid Build Coastguard Worker     }
92*635a8641SAndroid Build Coastguard Worker 
93*635a8641SAndroid Build Coastguard Worker    private:
94*635a8641SAndroid Build Coastguard Worker     CallbackListBase<CallbackType>* list_;
95*635a8641SAndroid Build Coastguard Worker     typename std::list<CallbackType>::iterator iter_;
96*635a8641SAndroid Build Coastguard Worker 
97*635a8641SAndroid Build Coastguard Worker     DISALLOW_COPY_AND_ASSIGN(Subscription);
98*635a8641SAndroid Build Coastguard Worker   };
99*635a8641SAndroid Build Coastguard Worker 
100*635a8641SAndroid Build Coastguard Worker   // Add a callback to the list. The callback will remain registered until the
101*635a8641SAndroid Build Coastguard Worker   // returned Subscription is destroyed, which must occur before the
102*635a8641SAndroid Build Coastguard Worker   // CallbackList is destroyed.
Add(const CallbackType & cb)103*635a8641SAndroid Build Coastguard Worker   std::unique_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
104*635a8641SAndroid Build Coastguard Worker     DCHECK(!cb.is_null());
105*635a8641SAndroid Build Coastguard Worker     return std::make_unique<Subscription>(
106*635a8641SAndroid Build Coastguard Worker         this, callbacks_.insert(callbacks_.end(), cb));
107*635a8641SAndroid Build Coastguard Worker   }
108*635a8641SAndroid Build Coastguard Worker 
109*635a8641SAndroid Build Coastguard Worker   // Sets a callback which will be run when a subscription list is changed.
set_removal_callback(const RepeatingClosure & callback)110*635a8641SAndroid Build Coastguard Worker   void set_removal_callback(const RepeatingClosure& callback) {
111*635a8641SAndroid Build Coastguard Worker     removal_callback_ = callback;
112*635a8641SAndroid Build Coastguard Worker   }
113*635a8641SAndroid Build Coastguard Worker 
114*635a8641SAndroid Build Coastguard Worker   // Returns true if there are no subscriptions. This is only valid to call when
115*635a8641SAndroid Build Coastguard Worker   // not looping through the list.
empty()116*635a8641SAndroid Build Coastguard Worker   bool empty() {
117*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(0, active_iterator_count_);
118*635a8641SAndroid Build Coastguard Worker     return callbacks_.empty();
119*635a8641SAndroid Build Coastguard Worker   }
120*635a8641SAndroid Build Coastguard Worker 
121*635a8641SAndroid Build Coastguard Worker  protected:
122*635a8641SAndroid Build Coastguard Worker   // An iterator class that can be used to access the list of callbacks.
123*635a8641SAndroid Build Coastguard Worker   class Iterator {
124*635a8641SAndroid Build Coastguard Worker    public:
Iterator(CallbackListBase<CallbackType> * list)125*635a8641SAndroid Build Coastguard Worker     explicit Iterator(CallbackListBase<CallbackType>* list)
126*635a8641SAndroid Build Coastguard Worker         : list_(list),
127*635a8641SAndroid Build Coastguard Worker           list_iter_(list_->callbacks_.begin()) {
128*635a8641SAndroid Build Coastguard Worker       ++list_->active_iterator_count_;
129*635a8641SAndroid Build Coastguard Worker     }
130*635a8641SAndroid Build Coastguard Worker 
Iterator(const Iterator & iter)131*635a8641SAndroid Build Coastguard Worker     Iterator(const Iterator& iter)
132*635a8641SAndroid Build Coastguard Worker         : list_(iter.list_),
133*635a8641SAndroid Build Coastguard Worker           list_iter_(iter.list_iter_) {
134*635a8641SAndroid Build Coastguard Worker       ++list_->active_iterator_count_;
135*635a8641SAndroid Build Coastguard Worker     }
136*635a8641SAndroid Build Coastguard Worker 
~Iterator()137*635a8641SAndroid Build Coastguard Worker     ~Iterator() {
138*635a8641SAndroid Build Coastguard Worker       if (list_ && --list_->active_iterator_count_ == 0) {
139*635a8641SAndroid Build Coastguard Worker         list_->Compact();
140*635a8641SAndroid Build Coastguard Worker       }
141*635a8641SAndroid Build Coastguard Worker     }
142*635a8641SAndroid Build Coastguard Worker 
GetNext()143*635a8641SAndroid Build Coastguard Worker     CallbackType* GetNext() {
144*635a8641SAndroid Build Coastguard Worker       while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
145*635a8641SAndroid Build Coastguard Worker         ++list_iter_;
146*635a8641SAndroid Build Coastguard Worker 
147*635a8641SAndroid Build Coastguard Worker       CallbackType* cb = nullptr;
148*635a8641SAndroid Build Coastguard Worker       if (list_iter_ != list_->callbacks_.end()) {
149*635a8641SAndroid Build Coastguard Worker         cb = &(*list_iter_);
150*635a8641SAndroid Build Coastguard Worker         ++list_iter_;
151*635a8641SAndroid Build Coastguard Worker       }
152*635a8641SAndroid Build Coastguard Worker       return cb;
153*635a8641SAndroid Build Coastguard Worker     }
154*635a8641SAndroid Build Coastguard Worker 
155*635a8641SAndroid Build Coastguard Worker    private:
156*635a8641SAndroid Build Coastguard Worker     CallbackListBase<CallbackType>* list_;
157*635a8641SAndroid Build Coastguard Worker     typename std::list<CallbackType>::iterator list_iter_;
158*635a8641SAndroid Build Coastguard Worker   };
159*635a8641SAndroid Build Coastguard Worker 
CallbackListBase()160*635a8641SAndroid Build Coastguard Worker   CallbackListBase() : active_iterator_count_(0) {}
161*635a8641SAndroid Build Coastguard Worker 
~CallbackListBase()162*635a8641SAndroid Build Coastguard Worker   ~CallbackListBase() {
163*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(0, active_iterator_count_);
164*635a8641SAndroid Build Coastguard Worker     DCHECK_EQ(0U, callbacks_.size());
165*635a8641SAndroid Build Coastguard Worker   }
166*635a8641SAndroid Build Coastguard Worker 
167*635a8641SAndroid Build Coastguard Worker   // Returns an instance of a CallbackListBase::Iterator which can be used
168*635a8641SAndroid Build Coastguard Worker   // to run callbacks.
GetIterator()169*635a8641SAndroid Build Coastguard Worker   Iterator GetIterator() {
170*635a8641SAndroid Build Coastguard Worker     return Iterator(this);
171*635a8641SAndroid Build Coastguard Worker   }
172*635a8641SAndroid Build Coastguard Worker 
173*635a8641SAndroid Build Coastguard Worker   // Compact the list: remove any entries which were nulled out during
174*635a8641SAndroid Build Coastguard Worker   // iteration.
Compact()175*635a8641SAndroid Build Coastguard Worker   void Compact() {
176*635a8641SAndroid Build Coastguard Worker     auto it = callbacks_.begin();
177*635a8641SAndroid Build Coastguard Worker     bool updated = false;
178*635a8641SAndroid Build Coastguard Worker     while (it != callbacks_.end()) {
179*635a8641SAndroid Build Coastguard Worker       if ((*it).is_null()) {
180*635a8641SAndroid Build Coastguard Worker         updated = true;
181*635a8641SAndroid Build Coastguard Worker         it = callbacks_.erase(it);
182*635a8641SAndroid Build Coastguard Worker       } else {
183*635a8641SAndroid Build Coastguard Worker         ++it;
184*635a8641SAndroid Build Coastguard Worker       }
185*635a8641SAndroid Build Coastguard Worker     }
186*635a8641SAndroid Build Coastguard Worker 
187*635a8641SAndroid Build Coastguard Worker     if (updated && !removal_callback_.is_null())
188*635a8641SAndroid Build Coastguard Worker       removal_callback_.Run();
189*635a8641SAndroid Build Coastguard Worker   }
190*635a8641SAndroid Build Coastguard Worker 
191*635a8641SAndroid Build Coastguard Worker  private:
192*635a8641SAndroid Build Coastguard Worker   std::list<CallbackType> callbacks_;
193*635a8641SAndroid Build Coastguard Worker   int active_iterator_count_;
194*635a8641SAndroid Build Coastguard Worker   RepeatingClosure removal_callback_;
195*635a8641SAndroid Build Coastguard Worker 
196*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
197*635a8641SAndroid Build Coastguard Worker };
198*635a8641SAndroid Build Coastguard Worker 
199*635a8641SAndroid Build Coastguard Worker }  // namespace internal
200*635a8641SAndroid Build Coastguard Worker 
201*635a8641SAndroid Build Coastguard Worker template <typename Sig> class CallbackList;
202*635a8641SAndroid Build Coastguard Worker 
203*635a8641SAndroid Build Coastguard Worker template <typename... Args>
204*635a8641SAndroid Build Coastguard Worker class CallbackList<void(Args...)>
205*635a8641SAndroid Build Coastguard Worker     : public internal::CallbackListBase<RepeatingCallback<void(Args...)>> {
206*635a8641SAndroid Build Coastguard Worker  public:
207*635a8641SAndroid Build Coastguard Worker   using CallbackType = RepeatingCallback<void(Args...)>;
208*635a8641SAndroid Build Coastguard Worker 
209*635a8641SAndroid Build Coastguard Worker   CallbackList() = default;
210*635a8641SAndroid Build Coastguard Worker 
211*635a8641SAndroid Build Coastguard Worker   template <typename... RunArgs>
Notify(RunArgs &&...args)212*635a8641SAndroid Build Coastguard Worker   void Notify(RunArgs&&... args) {
213*635a8641SAndroid Build Coastguard Worker     auto it = this->GetIterator();
214*635a8641SAndroid Build Coastguard Worker     CallbackType* cb;
215*635a8641SAndroid Build Coastguard Worker     while ((cb = it.GetNext()) != nullptr) {
216*635a8641SAndroid Build Coastguard Worker       cb->Run(args...);
217*635a8641SAndroid Build Coastguard Worker     }
218*635a8641SAndroid Build Coastguard Worker   }
219*635a8641SAndroid Build Coastguard Worker 
220*635a8641SAndroid Build Coastguard Worker  private:
221*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(CallbackList);
222*635a8641SAndroid Build Coastguard Worker };
223*635a8641SAndroid Build Coastguard Worker 
224*635a8641SAndroid Build Coastguard Worker }  // namespace base
225*635a8641SAndroid Build Coastguard Worker 
226*635a8641SAndroid Build Coastguard Worker #endif  // BASE_CALLBACK_LIST_H_
227