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