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