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