Home | History | Annotate | Download | only in base
      1 $$ This is a pump file for generating file templates.  Pump is a python
      2 $$ script that is part of the Google Test suite of utilities.  Description
      3 $$ can be found here:
      4 $$
      5 $$ http://code.google.com/p/googletest/wiki/PumpManual
      6 $$
      7 
      8 $$ See comment for MAX_ARITY in base/bind.h.pump.
      9 $var MAX_ARITY = 7
     10 
     11 // Copyright 2013 The Chromium Authors. All rights reserved.
     12 // Use of this source code is governed by a BSD-style license that can be
     13 // found in the LICENSE file.
     14 
     15 #ifndef BASE_CALLBACK_LIST_H_
     16 #define BASE_CALLBACK_LIST_H_
     17 
     18 #include <list>
     19 
     20 #include "base/basictypes.h"
     21 #include "base/callback.h"
     22 #include "base/callback_internal.h"
     23 #include "base/compiler_specific.h"
     24 #include "base/logging.h"
     25 #include "base/memory/scoped_ptr.h"
     26 
     27 // OVERVIEW:
     28 //
     29 // A container for a list of callbacks.  Unlike a normal STL vector or list,
     30 // this container can be modified during iteration without invalidating the
     31 // iterator. It safely handles the case of a callback removing itself
     32 // or another callback from the list while callbacks are being run.
     33 //
     34 // TYPICAL USAGE:
     35 //
     36 // class MyWidget {
     37 //  public:
     38 //   ...
     39 //
     40 //   typedef base::Callback<void(const Foo&)> OnFooCallback;
     41 //
     42 //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
     43 //   RegisterCallback(const OnFooCallback& cb) {
     44 //     return callback_list_.Add(cb);
     45 //   }
     46 //
     47 //  private:
     48 //   void NotifyFoo(const Foo& foo) {
     49 //      callback_list_.Notify(foo);
     50 //   }
     51 //
     52 //   base::CallbackList<void(const Foo&)> callback_list_;
     53 //
     54 //   DISALLOW_COPY_AND_ASSIGN(MyWidget);
     55 // };
     56 //
     57 //
     58 // class MyWidgetListener {
     59 //  public:
     60 //   MyWidgetListener::MyWidgetListener() {
     61 //     foo_subscription_ = MyWidget::GetCurrent()->RegisterCallback(
     62 //             base::Bind(&MyWidgetListener::OnFoo, this)));
     63 //   }
     64 //
     65 //   MyWidgetListener::~MyWidgetListener() {
     66 //      // Subscription gets deleted automatically and will deregister
     67 //      // the callback in the process.
     68 //   }
     69 //
     70 //  private:
     71 //   void OnFoo(const Foo& foo) {
     72 //     // Do something.
     73 //   }
     74 //
     75 //   scoped_ptr<base::CallbackList<void(const Foo&)>::Subscription>
     76 //       foo_subscription_;
     77 //
     78 //   DISALLOW_COPY_AND_ASSIGN(MyWidgetListener);
     79 // };
     80 
     81 namespace base {
     82 
     83 namespace internal {
     84 
     85 template <typename CallbackType>
     86 class CallbackListBase {
     87  public:
     88   class Subscription {
     89    public:
     90     Subscription(CallbackListBase<CallbackType>* list,
     91                  typename std::list<CallbackType>::iterator iter)
     92         : list_(list),
     93           iter_(iter) {
     94     }
     95 
     96     ~Subscription() {
     97       if (list_->active_iterator_count_)
     98         iter_->Reset();
     99       else
    100         list_->callbacks_.erase(iter_);
    101     }
    102 
    103    private:
    104     CallbackListBase<CallbackType>* list_;
    105     typename std::list<CallbackType>::iterator iter_;
    106 
    107     DISALLOW_COPY_AND_ASSIGN(Subscription);
    108   };
    109 
    110   // Add a callback to the list. The callback will remain registered until the
    111   // returned Subscription is destroyed, which must occur before the
    112   // CallbackList is destroyed.
    113   scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
    114     DCHECK(!cb.is_null());
    115     return scoped_ptr<Subscription>(
    116         new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
    117   }
    118 
    119  protected:
    120   // An iterator class that can be used to access the list of callbacks.
    121   class Iterator {
    122    public:
    123     explicit Iterator(CallbackListBase<CallbackType>* list)
    124         : list_(list),
    125           list_iter_(list_->callbacks_.begin()) {
    126       ++list_->active_iterator_count_;
    127     }
    128 
    129     Iterator(const Iterator& iter)
    130         : list_(iter.list_),
    131           list_iter_(iter.list_iter_) {
    132       ++list_->active_iterator_count_;
    133     }
    134 
    135     ~Iterator() {
    136       if (list_ && --list_->active_iterator_count_ == 0) {
    137         list_->Compact();
    138       }
    139     }
    140 
    141     CallbackType* GetNext() {
    142       while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
    143         ++list_iter_;
    144 
    145       CallbackType* cb = NULL;
    146       if (list_iter_ != list_->callbacks_.end()) {
    147         cb = &(*list_iter_);
    148         ++list_iter_;
    149       }
    150       return cb;
    151     }
    152 
    153    private:
    154     CallbackListBase<CallbackType>* list_;
    155     typename std::list<CallbackType>::iterator list_iter_;
    156   };
    157 
    158   CallbackListBase() : active_iterator_count_(0) {}
    159 
    160   ~CallbackListBase() {
    161     DCHECK_EQ(0, active_iterator_count_);
    162     DCHECK_EQ(0U, callbacks_.size());
    163   }
    164 
    165   // Returns an instance of a CallbackListBase::Iterator which can be used
    166   // to run callbacks.
    167   Iterator GetIterator() {
    168     return Iterator(this);
    169   }
    170 
    171   // Compact the list: remove any entries which were NULLed out during
    172   // iteration.
    173   void Compact() {
    174     typename std::list<CallbackType>::iterator it = callbacks_.begin();
    175     while (it != callbacks_.end()) {
    176       if ((*it).is_null())
    177         it = callbacks_.erase(it);
    178       else
    179         ++it;
    180     }
    181   }
    182 
    183  private:
    184   std::list<CallbackType> callbacks_;
    185   int active_iterator_count_;
    186 
    187   DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
    188 };
    189 
    190 }  // namespace internal
    191 
    192 template <typename Sig> class CallbackList;
    193 
    194 
    195 $range ARITY 0..MAX_ARITY
    196 $for ARITY [[
    197 $range ARG 1..ARITY
    198 
    199 $if ARITY == 0 [[
    200 template <>
    201 class CallbackList<void(void)>
    202     : public internal::CallbackListBase<Callback<void(void)> > {
    203 ]] $else [[
    204 template <$for ARG , [[typename A$(ARG)]]>
    205 class CallbackList<void($for ARG , [[A$(ARG)]])>
    206     : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > {
    207 ]]
    208 
    209  public:
    210 $if ARITY == 0 [[
    211 
    212   typedef Callback<void(void)> CallbackType;
    213 ]] $else [[
    214 
    215   typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType;
    216 ]]
    217 
    218 
    219   CallbackList() {}
    220 
    221   void Notify($for ARG ,
    222               [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
    223 $if ARITY == 0 [[
    224 
    225     internal::CallbackListBase<CallbackType>::Iterator it =
    226         this->GetIterator();
    227 ]] $else [[
    228 
    229     typename internal::CallbackListBase<CallbackType>::Iterator it =
    230         this->GetIterator();
    231 ]]
    232 
    233     CallbackType* cb;
    234     while ((cb = it.GetNext()) != NULL) {
    235       cb->Run($for ARG , [[a$(ARG)]]);
    236     }
    237   }
    238 
    239  private:
    240   DISALLOW_COPY_AND_ASSIGN(CallbackList);
    241 };
    242 
    243 
    244 ]]  $$ for ARITY
    245 }  // namespace base
    246 
    247 #endif  // BASE_CALLBACK_LIST_H_
    248