Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2006-2008 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_OBSERVER_LIST_H__
      6 #define BASE_OBSERVER_LIST_H__
      7 
      8 #include <algorithm>
      9 #include <limits>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/logging.h"
     14 
     15 ///////////////////////////////////////////////////////////////////////////////
     16 //
     17 // OVERVIEW:
     18 //
     19 //   A container for a list of observers.  Unlike a normal STL vector or list,
     20 //   this container can be modified during iteration without invalidating the
     21 //   iterator.  So, it safely handles the case of an observer removing itself
     22 //   or other observers from the list while observers are being notified.
     23 //
     24 // TYPICAL USAGE:
     25 //
     26 //   class MyWidget {
     27 //    public:
     28 //     ...
     29 //
     30 //     class Observer {
     31 //      public:
     32 //       virtual void OnFoo(MyWidget* w) = 0;
     33 //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
     34 //     };
     35 //
     36 //     void AddObserver(Observer* obs) {
     37 //       observer_list_.AddObserver(obs);
     38 //     }
     39 //
     40 //     void RemoveObserver(Observer* obs) {
     41 //       observer_list_.RemoveObserver(obs);
     42 //     }
     43 //
     44 //     void NotifyFoo() {
     45 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
     46 //     }
     47 //
     48 //     void NotifyBar(int x, int y) {
     49 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
     50 //     }
     51 //
     52 //    private:
     53 //     ObserverList<Observer> observer_list_;
     54 //   };
     55 //
     56 //
     57 ///////////////////////////////////////////////////////////////////////////////
     58 
     59 template <class ObserverType, bool check_empty = false>
     60 class ObserverList {
     61  public:
     62   // Enumeration of which observers are notified.
     63   enum NotificationType {
     64     // Specifies that any observers added during notification are notified.
     65     // This is the default type if non type is provided to the constructor.
     66     NOTIFY_ALL,
     67 
     68     // Specifies that observers added while sending out notification are not
     69     // notified.
     70     NOTIFY_EXISTING_ONLY
     71   };
     72 
     73   ObserverList() : notify_depth_(0), type_(NOTIFY_ALL) {}
     74   ObserverList(NotificationType type) : notify_depth_(0), type_(type) {}
     75   ~ObserverList() {
     76     // When check_empty is true, assert that the list is empty on destruction.
     77     if (check_empty) {
     78       Compact();
     79       DCHECK_EQ(observers_.size(), 0U);
     80     }
     81   }
     82 
     83   // Add an observer to the list.
     84   void AddObserver(ObserverType* obs) {
     85     DCHECK(find(observers_.begin(), observers_.end(), obs) == observers_.end())
     86         << "Observers can only be added once!";
     87     observers_.push_back(obs);
     88   }
     89 
     90   // Remove an observer from the list.
     91   void RemoveObserver(ObserverType* obs) {
     92     typename ListType::iterator it =
     93       std::find(observers_.begin(), observers_.end(), obs);
     94     if (it != observers_.end()) {
     95       if (notify_depth_) {
     96         *it = 0;
     97       } else {
     98         observers_.erase(it);
     99       }
    100     }
    101   }
    102 
    103   size_t size() const {
    104     return observers_.size();
    105   }
    106 
    107   ObserverType* GetElementAt(int index) const {
    108     return observers_[index];
    109   }
    110 
    111   // An iterator class that can be used to access the list of observers.  See
    112   // also the FOREACH_OBSERVER macro defined below.
    113   class Iterator {
    114    public:
    115     Iterator(const ObserverList<ObserverType>& list)
    116         : list_(list),
    117           index_(0),
    118           max_index_(list.type_ == NOTIFY_ALL ?
    119                      std::numeric_limits<size_t>::max() :
    120                      list.observers_.size()) {
    121       ++list_.notify_depth_;
    122     }
    123 
    124     ~Iterator() {
    125       if (--list_.notify_depth_ == 0)
    126         list_.Compact();
    127     }
    128 
    129     ObserverType* GetNext() {
    130       ListType& observers = list_.observers_;
    131       // Advance if the current element is null
    132       size_t max_index = std::min(max_index_, observers.size());
    133       while (index_ < max_index && !observers[index_])
    134         ++index_;
    135       return index_ < max_index ? observers[index_++] : NULL;
    136     }
    137 
    138    private:
    139     const ObserverList<ObserverType>& list_;
    140     size_t index_;
    141     size_t max_index_;
    142   };
    143 
    144  private:
    145   typedef std::vector<ObserverType*> ListType;
    146 
    147   void Compact() const {
    148     typename ListType::iterator it = observers_.begin();
    149     while (it != observers_.end()) {
    150       if (*it) {
    151         ++it;
    152       } else {
    153         it = observers_.erase(it);
    154       }
    155     }
    156   }
    157 
    158   // These are marked mutable to facilitate having NotifyAll be const.
    159   mutable ListType observers_;
    160   mutable int notify_depth_;
    161   NotificationType type_;
    162 
    163   friend class ObserverList::Iterator;
    164 
    165   DISALLOW_EVIL_CONSTRUCTORS(ObserverList);
    166 };
    167 
    168 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func)  \
    169   do {                                                        \
    170     ObserverList<ObserverType>::Iterator it(observer_list);   \
    171     ObserverType* obs;                                        \
    172     while ((obs = it.GetNext()) != NULL)                      \
    173       obs->func;                                              \
    174   } while (0)
    175 
    176 #endif  // BASE_OBSERVER_LIST_H__
    177