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