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/gtest_prod_util.h"
     15 #include "base/logging.h"
     16 #include "base/macros.h"
     17 #include "base/memory/weak_ptr.h"
     18 #include "base/stl_util.h"
     19 
     20 ///////////////////////////////////////////////////////////////////////////////
     21 //
     22 // OVERVIEW:
     23 //
     24 //   A container for a list of observers.  Unlike a normal STL vector or list,
     25 //   this container can be modified during iteration without invalidating the
     26 //   iterator.  So, it safely handles the case of an observer removing itself
     27 //   or other observers from the list while observers are being notified.
     28 //
     29 // TYPICAL USAGE:
     30 //
     31 //   class MyWidget {
     32 //    public:
     33 //     ...
     34 //
     35 //     class Observer {
     36 //      public:
     37 //       virtual void OnFoo(MyWidget* w) = 0;
     38 //       virtual void OnBar(MyWidget* w, int x, int y) = 0;
     39 //     };
     40 //
     41 //     void AddObserver(Observer* obs) {
     42 //       observer_list_.AddObserver(obs);
     43 //     }
     44 //
     45 //     void RemoveObserver(Observer* obs) {
     46 //       observer_list_.RemoveObserver(obs);
     47 //     }
     48 //
     49 //     void NotifyFoo() {
     50 //       for (auto& observer : observer_list_)
     51 //         observer.OnFoo(this);
     52 //     }
     53 //
     54 //     void NotifyBar(int x, int y) {
     55 //       for (FooList::iterator i = observer_list.begin(),
     56 //           e = observer_list.end(); i != e; ++i)
     57 //        i->OnBar(this, x, y);
     58 //     }
     59 //
     60 //    private:
     61 //     base::ObserverList<Observer> observer_list_;
     62 //   };
     63 //
     64 //
     65 ///////////////////////////////////////////////////////////////////////////////
     66 
     67 namespace base {
     68 
     69 template <typename ObserverType>
     70 class ObserverListThreadSafe;
     71 
     72 template <class ObserverType>
     73 class ObserverListBase
     74     : public SupportsWeakPtr<ObserverListBase<ObserverType>> {
     75  public:
     76   // Enumeration of which observers are notified.
     77   enum NotificationType {
     78     // Specifies that any observers added during notification are notified.
     79     // This is the default type if non type is provided to the constructor.
     80     NOTIFY_ALL,
     81 
     82     // Specifies that observers added while sending out notification are not
     83     // notified.
     84     NOTIFY_EXISTING_ONLY
     85   };
     86 
     87   // An iterator class that can be used to access the list of observers.
     88   template <class ContainerType>
     89   class Iter {
     90    public:
     91     Iter();
     92     explicit Iter(ContainerType* list);
     93     ~Iter();
     94 
     95     // A workaround for C2244. MSVC requires fully qualified type name for
     96     // return type on a function definition to match a function declaration.
     97     using ThisType =
     98         typename ObserverListBase<ObserverType>::template Iter<ContainerType>;
     99 
    100     bool operator==(const Iter& other) const;
    101     bool operator!=(const Iter& other) const;
    102     ThisType& operator++();
    103     ObserverType* operator->() const;
    104     ObserverType& operator*() const;
    105 
    106    private:
    107     FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator);
    108     FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront);
    109 
    110     ObserverType* GetCurrent() const;
    111     void EnsureValidIndex();
    112 
    113     size_t clamped_max_index() const {
    114       return std::min(max_index_, list_->observers_.size());
    115     }
    116 
    117     bool is_end() const { return !list_ || index_ == clamped_max_index(); }
    118 
    119     WeakPtr<ObserverListBase<ObserverType>> list_;
    120     // When initially constructed and each time the iterator is incremented,
    121     // |index_| is guaranteed to point to a non-null index if the iterator
    122     // has not reached the end of the ObserverList.
    123     size_t index_;
    124     size_t max_index_;
    125   };
    126 
    127   using Iterator = Iter<ObserverListBase<ObserverType>>;
    128 
    129   using iterator = Iter<ObserverListBase<ObserverType>>;
    130   iterator begin() {
    131     // An optimization: do not involve weak pointers for empty list.
    132     // Note: can't use ?: operator here due to some MSVC bug (unit tests fail)
    133     if (observers_.empty())
    134       return iterator();
    135     return iterator(this);
    136   }
    137   iterator end() { return iterator(); }
    138 
    139   using const_iterator = Iter<const ObserverListBase<ObserverType>>;
    140   const_iterator begin() const {
    141     if (observers_.empty())
    142       return const_iterator();
    143     return const_iterator(this);
    144   }
    145   const_iterator end() const { return const_iterator(); }
    146 
    147   ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {}
    148   explicit ObserverListBase(NotificationType type)
    149       : notify_depth_(0), type_(type) {}
    150 
    151   // Add an observer to the list.  An observer should not be added to
    152   // the same list more than once.
    153   void AddObserver(ObserverType* obs);
    154 
    155   // Remove an observer from the list if it is in the list.
    156   void RemoveObserver(ObserverType* obs);
    157 
    158   // Determine whether a particular observer is in the list.
    159   bool HasObserver(const ObserverType* observer) const;
    160 
    161   void Clear();
    162 
    163  protected:
    164   size_t size() const { return observers_.size(); }
    165 
    166   void Compact();
    167 
    168  private:
    169   friend class ObserverListThreadSafe<ObserverType>;
    170 
    171   typedef std::vector<ObserverType*> ListType;
    172 
    173   ListType observers_;
    174   int notify_depth_;
    175   NotificationType type_;
    176 
    177   template <class ContainerType>
    178   friend class Iter;
    179 
    180   DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
    181 };
    182 
    183 template <class ObserverType>
    184 template <class ContainerType>
    185 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter()
    186     : index_(0), max_index_(0) {}
    187 
    188 template <class ObserverType>
    189 template <class ContainerType>
    190 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list)
    191     : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()),
    192       index_(0),
    193       max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max()
    194                                            : list->observers_.size()) {
    195   EnsureValidIndex();
    196   DCHECK(list_);
    197   ++list_->notify_depth_;
    198 }
    199 
    200 template <class ObserverType>
    201 template <class ContainerType>
    202 ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
    203   if (list_ && --list_->notify_depth_ == 0)
    204     list_->Compact();
    205 }
    206 
    207 template <class ObserverType>
    208 template <class ContainerType>
    209 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator==(
    210     const Iter& other) const {
    211   if (is_end() && other.is_end())
    212     return true;
    213   return list_.get() == other.list_.get() && index_ == other.index_;
    214 }
    215 
    216 template <class ObserverType>
    217 template <class ContainerType>
    218 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=(
    219     const Iter& other) const {
    220   return !operator==(other);
    221 }
    222 
    223 template <class ObserverType>
    224 template <class ContainerType>
    225 typename ObserverListBase<ObserverType>::template Iter<ContainerType>&
    226     ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() {
    227   if (list_) {
    228     ++index_;
    229     EnsureValidIndex();
    230   }
    231   return *this;
    232 }
    233 
    234 template <class ObserverType>
    235 template <class ContainerType>
    236 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->()
    237     const {
    238   ObserverType* current = GetCurrent();
    239   DCHECK(current);
    240   return current;
    241 }
    242 
    243 template <class ObserverType>
    244 template <class ContainerType>
    245 ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*()
    246     const {
    247   ObserverType* current = GetCurrent();
    248   DCHECK(current);
    249   return *current;
    250 }
    251 
    252 template <class ObserverType>
    253 template <class ContainerType>
    254 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetCurrent()
    255     const {
    256   if (!list_)
    257     return nullptr;
    258   return index_ < clamped_max_index() ? list_->observers_[index_] : nullptr;
    259 }
    260 
    261 template <class ObserverType>
    262 template <class ContainerType>
    263 void ObserverListBase<ObserverType>::Iter<ContainerType>::EnsureValidIndex() {
    264   if (!list_)
    265     return;
    266 
    267   size_t max_index = clamped_max_index();
    268   while (index_ < max_index && !list_->observers_[index_])
    269     ++index_;
    270 }
    271 
    272 template <class ObserverType>
    273 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) {
    274   DCHECK(obs);
    275   if (ContainsValue(observers_, obs)) {
    276     NOTREACHED() << "Observers can only be added once!";
    277     return;
    278   }
    279   observers_.push_back(obs);
    280 }
    281 
    282 template <class ObserverType>
    283 void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) {
    284   DCHECK(obs);
    285   typename ListType::iterator it =
    286     std::find(observers_.begin(), observers_.end(), obs);
    287   if (it != observers_.end()) {
    288     if (notify_depth_) {
    289       *it = nullptr;
    290     } else {
    291       observers_.erase(it);
    292     }
    293   }
    294 }
    295 
    296 template <class ObserverType>
    297 bool ObserverListBase<ObserverType>::HasObserver(
    298     const ObserverType* observer) const {
    299   for (size_t i = 0; i < observers_.size(); ++i) {
    300     if (observers_[i] == observer)
    301       return true;
    302   }
    303   return false;
    304 }
    305 
    306 template <class ObserverType>
    307 void ObserverListBase<ObserverType>::Clear() {
    308   if (notify_depth_) {
    309     for (typename ListType::iterator it = observers_.begin();
    310       it != observers_.end(); ++it) {
    311       *it = nullptr;
    312     }
    313   } else {
    314     observers_.clear();
    315   }
    316 }
    317 
    318 template <class ObserverType>
    319 void ObserverListBase<ObserverType>::Compact() {
    320   observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr),
    321                    observers_.end());
    322 }
    323 
    324 template <class ObserverType, bool check_empty = false>
    325 class ObserverList : public ObserverListBase<ObserverType> {
    326  public:
    327   typedef typename ObserverListBase<ObserverType>::NotificationType
    328       NotificationType;
    329 
    330   ObserverList() {}
    331   explicit ObserverList(NotificationType type)
    332       : ObserverListBase<ObserverType>(type) {}
    333 
    334   ~ObserverList() {
    335     // When check_empty is true, assert that the list is empty on destruction.
    336     if (check_empty) {
    337       ObserverListBase<ObserverType>::Compact();
    338       DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U);
    339     }
    340   }
    341 
    342   bool might_have_observers() const {
    343     return ObserverListBase<ObserverType>::size() != 0;
    344   }
    345 };
    346 
    347 }  // namespace base
    348 
    349 #endif  // BASE_OBSERVER_LIST_H_
    350