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