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         if (!list_->removal_callback_.is_null())
    102           list_->removal_callback_.Run();
    103       }
    104     }
    105 
    106    private:
    107     CallbackListBase<CallbackType>* list_;
    108     typename std::list<CallbackType>::iterator iter_;
    109 
    110     DISALLOW_COPY_AND_ASSIGN(Subscription);
    111   };
    112 
    113   // Add a callback to the list. The callback will remain registered until the
    114   // returned Subscription is destroyed, which must occur before the
    115   // CallbackList is destroyed.
    116   scoped_ptr<Subscription> Add(const CallbackType& cb) WARN_UNUSED_RESULT {
    117     DCHECK(!cb.is_null());
    118     return scoped_ptr<Subscription>(
    119         new Subscription(this, callbacks_.insert(callbacks_.end(), cb)));
    120   }
    121 
    122   // Sets a callback which will be run when a subscription list is changed.
    123   void set_removal_callback(const Closure& callback) {
    124     removal_callback_ = callback;
    125   }
    126 
    127   // Returns true if there are no subscriptions. This is only valid to call when
    128   // not looping through the list.
    129   bool empty() {
    130     DCHECK_EQ(0, active_iterator_count_);
    131     return callbacks_.empty();
    132   }
    133 
    134  protected:
    135   // An iterator class that can be used to access the list of callbacks.
    136   class Iterator {
    137    public:
    138     explicit Iterator(CallbackListBase<CallbackType>* list)
    139         : list_(list),
    140           list_iter_(list_->callbacks_.begin()) {
    141       ++list_->active_iterator_count_;
    142     }
    143 
    144     Iterator(const Iterator& iter)
    145         : list_(iter.list_),
    146           list_iter_(iter.list_iter_) {
    147       ++list_->active_iterator_count_;
    148     }
    149 
    150     ~Iterator() {
    151       if (list_ && --list_->active_iterator_count_ == 0) {
    152         list_->Compact();
    153       }
    154     }
    155 
    156     CallbackType* GetNext() {
    157       while ((list_iter_ != list_->callbacks_.end()) && list_iter_->is_null())
    158         ++list_iter_;
    159 
    160       CallbackType* cb = NULL;
    161       if (list_iter_ != list_->callbacks_.end()) {
    162         cb = &(*list_iter_);
    163         ++list_iter_;
    164       }
    165       return cb;
    166     }
    167 
    168    private:
    169     CallbackListBase<CallbackType>* list_;
    170     typename std::list<CallbackType>::iterator list_iter_;
    171   };
    172 
    173   CallbackListBase() : active_iterator_count_(0) {}
    174 
    175   ~CallbackListBase() {
    176     DCHECK_EQ(0, active_iterator_count_);
    177     DCHECK_EQ(0U, callbacks_.size());
    178   }
    179 
    180   // Returns an instance of a CallbackListBase::Iterator which can be used
    181   // to run callbacks.
    182   Iterator GetIterator() {
    183     return Iterator(this);
    184   }
    185 
    186   // Compact the list: remove any entries which were NULLed out during
    187   // iteration.
    188   void Compact() {
    189     typename std::list<CallbackType>::iterator it = callbacks_.begin();
    190     bool updated = false;
    191     while (it != callbacks_.end()) {
    192       if ((*it).is_null()) {
    193         updated = true;
    194         it = callbacks_.erase(it);
    195       } else {
    196         ++it;
    197       }
    198 
    199       if (updated && !removal_callback_.is_null())
    200         removal_callback_.Run();
    201     }
    202   }
    203 
    204  private:
    205   std::list<CallbackType> callbacks_;
    206   int active_iterator_count_;
    207   Closure removal_callback_;
    208 
    209   DISALLOW_COPY_AND_ASSIGN(CallbackListBase);
    210 };
    211 
    212 }  // namespace internal
    213 
    214 template <typename Sig> class CallbackList;
    215 
    216 
    217 $range ARITY 0..MAX_ARITY
    218 $for ARITY [[
    219 $range ARG 1..ARITY
    220 
    221 $if ARITY == 0 [[
    222 template <>
    223 class CallbackList<void(void)>
    224     : public internal::CallbackListBase<Callback<void(void)> > {
    225 ]] $else [[
    226 template <$for ARG , [[typename A$(ARG)]]>
    227 class CallbackList<void($for ARG , [[A$(ARG)]])>
    228     : public internal::CallbackListBase<Callback<void($for ARG , [[A$(ARG)]])> > {
    229 ]]
    230 
    231  public:
    232 $if ARITY == 0 [[
    233 
    234   typedef Callback<void(void)> CallbackType;
    235 ]] $else [[
    236 
    237   typedef Callback<void($for ARG , [[A$(ARG)]])> CallbackType;
    238 ]]
    239 
    240 
    241   CallbackList() {}
    242 
    243   void Notify($for ARG ,
    244               [[typename internal::CallbackParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) {
    245 $if ARITY == 0 [[
    246 
    247     internal::CallbackListBase<CallbackType>::Iterator it =
    248         this->GetIterator();
    249 ]] $else [[
    250 
    251     typename internal::CallbackListBase<CallbackType>::Iterator it =
    252         this->GetIterator();
    253 ]]
    254 
    255     CallbackType* cb;
    256     while ((cb = it.GetNext()) != NULL) {
    257       cb->Run($for ARG , [[a$(ARG)]]);
    258     }
    259   }
    260 
    261  private:
    262   DISALLOW_COPY_AND_ASSIGN(CallbackList);
    263 };
    264 
    265 
    266 ]]  $$ for ARITY
    267 }  // namespace base
    268 
    269 #endif  // BASE_CALLBACK_LIST_H_
    270