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