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