Home | History | Annotate | Download | only in base
      1 // Copyright (c) 2011 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 <stddef.h>
      9 
     10 #include <algorithm>
     11 #include <limits>
     12 #include <vector>
     13 
     14 #include "base/logging.h"
     15 #include "base/macros.h"
     16 #include "base/memory/weak_ptr.h"
     17 
     18 ///////////////////////////////////////////////////////////////////////////////
     19 //
     20 // OVERVIEW:
     21 //
     22 //   A container for a list of observers.  Unlike a normal STL vector or list,
     23 //   this container can be modified during iteration without invalidating the
     24 //   iterator.  So, it safely handles the case of an observer removing itself
     25 //   or other observers from the list while observers are being notified.
     26 //
     27 // TYPICAL USAGE:
     28 //
     29 //   class MyWidget {
     30 //    public:
     31 //     ...
     32 //
     33 //     class Observer {
     34 //      public:
     35 //       virtual void OnFoo(MyWidget* w) = 0;
     36 //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
     37 //     };
     38 //
     39 //     void AddObserver(Observer* obs) {
     40 //       observer_list_.AddObserver(obs);
     41 //     }
     42 //
     43 //     void RemoveObserver(Observer* obs) {
     44 //       observer_list_.RemoveObserver(obs);
     45 //     }
     46 //
     47 //     void NotifyFoo() {
     48 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this));
     49 //     }
     50 //
     51 //     void NotifyBar(int x, int y) {
     52 //       FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
     53 //     }
     54 //
     55 //    private:
     56 //     base::ObserverList<Observer> observer_list_;
     57 //   };
     58 //
     59 //
     60 ///////////////////////////////////////////////////////////////////////////////
     61 
     62 namespace base {
     63 
     64 template <class ObserverType>
     65 class ObserverListBase
     66     : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
     67  public:
     68   // Enumeration of which observers are notified.
     69   enum NotificationType {
     70     // Specifies that any observers added during notification are notified.
     71     // This is the default type if non type is provided to the constructor.
     72     NOTIFY_ALL,
     73 
     74     // Specifies that observers added while sending out notification are not
     75     // notified.
     76     NOTIFY_EXISTING_ONLY
     77   };
     78 
     79   // An iterator class that can be used to access the list of observers.  See
     80   // also the FOR_EACH_OBSERVER macro defined below.
     81   class Iterator {
     82    public:
     83     explicit Iterator(ObserverListBase<ObserverType>* list);
     84     ~Iterator();
     85     ObserverType* GetNext();
     86 
     87    private:
     88     WeakPtr<ObserverListBase<ObserverType>> list_;
     89     size_t index_;
     90     size_t max_index_;
     91   };
     92 
     93   ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
     94   explicit ObserverListBase(NotificationType type)
     95       : notify_depth_(0), type_(type) {}
     96 
     97   // Add an observer to the list.  An observer should not be added to
     98   // the same list more than once.
     99   void AddObserver(ObserverType* obs);
    100 
    101   // Remove an observer from the list if it is in the list.
    102   void RemoveObserver(ObserverType* obs);
    103 
    104   // Determine whether a particular observer is in the list.
    105   bool HasObserver(const ObserverType* observer) const;
    106 
    107   void Clear();
    108 
    109  protected:
    110   size_t size() const { return observers_.size(); }
    111 
    112   void Compact();
    113 
    114  private:
    115   typedef std::vector<ObserverType*> ListType;
    116 
    117   ListType observers_;
    118   int notify_depth_;
    119   NotificationType type_;
    120 
    121   friend class ObserverListBase::Iterator;
    122 
    123   DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
    124 };
    125 
    126 template <class ObserverType>
    127 ObserverListBase<ObserverType>::Iterator::Iterator(
    128     ObserverListBase<ObserverType>* list)
    129     : list_(list->AsWeakPtr()),
    130       index_(0),
    131       max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
    132                                            : list->observers_.size()) {
    133   ++list_->notify_depth_;
    134 }
    135 
    136 template <class ObserverType>
    137 ObserverListBase<ObserverType>::Iterator::~Iterator() {
    138   if (list_.get() && --list_->notify_depth_ == 0)
    139     list_->Compact();
    140 }
    141 
    142 template <class ObserverType>
    143 ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
    144   if (!list_.get())
    145     return nullptr;
    146   ListType& observers = list_->observers_;
    147   // Advance if the current element is null
    148   size_t max_index = std::min(max_index_, observers.size());
    149   while (index_ < max_index && !observers[index_])
    150     ++index_;
    151   return index_ < max_index ? observers[index_++] : nullptr;
    152 }
    153 
    154 template <class ObserverType>
    155 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
    156   DCHECK(obs);
    157   auto it = std::find(observers_.begin(), observers_.end(), obs);
    158   if (it != observers_.end()) {
    159     NOTREACHED() << "Observers can only be added once!";
    160     return;
    161   }
    162   observers_.push_back(obs);
    163 }
    164 
    165 template <class ObserverType>
    166 void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
    167   DCHECK(obs);
    168   typename ListType::iterator it =
    169     std::find(observers_.begin(), observers_.end(), obs);
    170   if (it != observers_.end()) {
    171     if (notify_depth_) {
    172       *it = nullptr;
    173     } else {
    174       observers_.erase(it);
    175     }
    176   }
    177 }
    178 
    179 template <class ObserverType>
    180 bool ObserverListBase<ObserverType>::HasObserver(
    181     const ObserverType* observer) const {
    182   for (size_t i = 0; i < observers_.size(); ++i) {
    183     if (observers_[i] == observer)
    184       return true;
    185   }
    186   return false;
    187 }
    188 
    189 template <class ObserverType>
    190 void ObserverListBase<ObserverType>::Clear() {
    191   if (notify_depth_) {
    192     for (typename ListType::iterator it = observers_.begin();
    193       it != observers_.end(); ++it) {
    194       *it = nullptr;
    195     }
    196   } else {
    197     observers_.clear();
    198   }
    199 }
    200 
    201 template <class ObserverType>
    202 void ObserverListBase<ObserverType>::Compact() {
    203   observers_.erase(
    204       std::remove(observers_.begin(), observers_.end(), nullptr),
    205       observers_.end());
    206 }
    207 
    208 template <class ObserverType, bool check_empty = false>
    209 class ObserverList : public ObserverListBase<ObserverType> {
    210  public:
    211   typedef typename ObserverListBase<ObserverType>::NotificationType
    212       NotificationType;
    213 
    214   ObserverList() {}
    215   explicit ObserverList(NotificationType type)
    216       : ObserverListBase<ObserverType>(type) {}
    217 
    218   ~ObserverList() {
    219     // When check_empty is true, assert that the list is empty on destruction.
    220     if (check_empty) {
    221       ObserverListBase<ObserverType>::Compact();
    222       DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
    223     }
    224   }
    225 
    226   bool might_have_observers() const {
    227     return ObserverListBase<ObserverType>::size() != 0;
    228   }
    229 };
    230 
    231 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func)             \
    232   do {                                                                   \
    233     if ((observer_list).might_have_observers()) {                        \
    234       base::ObserverListBase<ObserverType>::Iterator it_inside_observer_macro( \
    235           &observer_list);                                               \
    236       ObserverType* obs;                                                 \
    237       while ((obs = it_inside_observer_macro.GetNext()) != nullptr)      \
    238         obs->func;                                                       \
    239     }                                                                    \
    240   } while (0)
    241 
    242 }  // namespace base
    243 
    244 #endif  // BASE_OBSERVER_LIST_H_
    245