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