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