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/gtest_prod_util.h" 15 #include "base/logging.h" 16 #include "base/macros.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/stl_util.h" 19 20 /////////////////////////////////////////////////////////////////////////////// 21 // 22 // OVERVIEW: 23 // 24 // A container for a list of observers. Unlike a normal STL vector or list, 25 // this container can be modified during iteration without invalidating the 26 // iterator. So, it safely handles the case of an observer removing itself 27 // or other observers from the list while observers are being notified. 28 // 29 // TYPICAL USAGE: 30 // 31 // class MyWidget { 32 // public: 33 // ... 34 // 35 // class Observer { 36 // public: 37 // virtual void OnFoo(MyWidget* w) = 0; 38 // virtual void OnBar(MyWidget* w, int x, int y) = 0; 39 // }; 40 // 41 // void AddObserver(Observer* obs) { 42 // observer_list_.AddObserver(obs); 43 // } 44 // 45 // void RemoveObserver(Observer* obs) { 46 // observer_list_.RemoveObserver(obs); 47 // } 48 // 49 // void NotifyFoo() { 50 // for (auto& observer : observer_list_) 51 // observer.OnFoo(this); 52 // } 53 // 54 // void NotifyBar(int x, int y) { 55 // for (FooList::iterator i = observer_list.begin(), 56 // e = observer_list.end(); i != e; ++i) 57 // i->OnBar(this, x, y); 58 // } 59 // 60 // private: 61 // base::ObserverList<Observer> observer_list_; 62 // }; 63 // 64 // 65 /////////////////////////////////////////////////////////////////////////////// 66 67 namespace base { 68 69 template <typename ObserverType> 70 class ObserverListThreadSafe; 71 72 template <class ObserverType> 73 class ObserverListBase 74 : public SupportsWeakPtr<ObserverListBase<ObserverType>> { 75 public: 76 // Enumeration of which observers are notified. 77 enum NotificationType { 78 // Specifies that any observers added during notification are notified. 79 // This is the default type if non type is provided to the constructor. 80 NOTIFY_ALL, 81 82 // Specifies that observers added while sending out notification are not 83 // notified. 84 NOTIFY_EXISTING_ONLY 85 }; 86 87 // An iterator class that can be used to access the list of observers. 88 template <class ContainerType> 89 class Iter { 90 public: 91 Iter(); 92 explicit Iter(ContainerType* list); 93 ~Iter(); 94 95 // A workaround for C2244. MSVC requires fully qualified type name for 96 // return type on a function definition to match a function declaration. 97 using ThisType = 98 typename ObserverListBase<ObserverType>::template Iter<ContainerType>; 99 100 bool operator==(const Iter& other) const; 101 bool operator!=(const Iter& other) const; 102 ThisType& operator++(); 103 ObserverType* operator->() const; 104 ObserverType& operator*() const; 105 106 private: 107 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator); 108 FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront); 109 110 ObserverType* GetCurrent() const; 111 void EnsureValidIndex(); 112 113 size_t clamped_max_index() const { 114 return std::min(max_index_, list_->observers_.size()); 115 } 116 117 bool is_end() const { return !list_ || index_ == clamped_max_index(); } 118 119 WeakPtr<ObserverListBase<ObserverType>> list_; 120 // When initially constructed and each time the iterator is incremented, 121 // |index_| is guaranteed to point to a non-null index if the iterator 122 // has not reached the end of the ObserverList. 123 size_t index_; 124 size_t max_index_; 125 }; 126 127 using Iterator = Iter<ObserverListBase<ObserverType>>; 128 129 using iterator = Iter<ObserverListBase<ObserverType>>; 130 iterator begin() { 131 // An optimization: do not involve weak pointers for empty list. 132 // Note: can't use ?: operator here due to some MSVC bug (unit tests fail) 133 if (observers_.empty()) 134 return iterator(); 135 return iterator(this); 136 } 137 iterator end() { return iterator(); } 138 139 using const_iterator = Iter<const ObserverListBase<ObserverType>>; 140 const_iterator begin() const { 141 if (observers_.empty()) 142 return const_iterator(); 143 return const_iterator(this); 144 } 145 const_iterator end() const { return const_iterator(); } 146 147 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} 148 explicit ObserverListBase(NotificationType type) 149 : notify_depth_(0), type_(type) {} 150 151 // Add an observer to the list. An observer should not be added to 152 // the same list more than once. 153 void AddObserver(ObserverType* obs); 154 155 // Remove an observer from the list if it is in the list. 156 void RemoveObserver(ObserverType* obs); 157 158 // Determine whether a particular observer is in the list. 159 bool HasObserver(const ObserverType* observer) const; 160 161 void Clear(); 162 163 protected: 164 size_t size() const { return observers_.size(); } 165 166 void Compact(); 167 168 private: 169 friend class ObserverListThreadSafe<ObserverType>; 170 171 typedef std::vector<ObserverType*> ListType; 172 173 ListType observers_; 174 int notify_depth_; 175 NotificationType type_; 176 177 template <class ContainerType> 178 friend class Iter; 179 180 DISALLOW_COPY_AND_ASSIGN(ObserverListBase); 181 }; 182 183 template <class ObserverType> 184 template <class ContainerType> 185 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter() 186 : index_(0), max_index_(0) {} 187 188 template <class ObserverType> 189 template <class ContainerType> 190 ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list) 191 : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()), 192 index_(0), 193 max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max() 194 : list->observers_.size()) { 195 EnsureValidIndex(); 196 DCHECK(list_); 197 ++list_->notify_depth_; 198 } 199 200 template <class ObserverType> 201 template <class ContainerType> 202 ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() { 203 if (list_ && --list_->notify_depth_ == 0) 204 list_->Compact(); 205 } 206 207 template <class ObserverType> 208 template <class ContainerType> 209 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator==( 210 const Iter& other) const { 211 if (is_end() && other.is_end()) 212 return true; 213 return list_.get() == other.list_.get() && index_ == other.index_; 214 } 215 216 template <class ObserverType> 217 template <class ContainerType> 218 bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=( 219 const Iter& other) const { 220 return !operator==(other); 221 } 222 223 template <class ObserverType> 224 template <class ContainerType> 225 typename ObserverListBase<ObserverType>::template Iter<ContainerType>& 226 ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() { 227 if (list_) { 228 ++index_; 229 EnsureValidIndex(); 230 } 231 return *this; 232 } 233 234 template <class ObserverType> 235 template <class ContainerType> 236 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->() 237 const { 238 ObserverType* current = GetCurrent(); 239 DCHECK(current); 240 return current; 241 } 242 243 template <class ObserverType> 244 template <class ContainerType> 245 ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*() 246 const { 247 ObserverType* current = GetCurrent(); 248 DCHECK(current); 249 return *current; 250 } 251 252 template <class ObserverType> 253 template <class ContainerType> 254 ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetCurrent() 255 const { 256 if (!list_) 257 return nullptr; 258 return index_ < clamped_max_index() ? list_->observers_[index_] : nullptr; 259 } 260 261 template <class ObserverType> 262 template <class ContainerType> 263 void ObserverListBase<ObserverType>::Iter<ContainerType>::EnsureValidIndex() { 264 if (!list_) 265 return; 266 267 size_t max_index = clamped_max_index(); 268 while (index_ < max_index && !list_->observers_[index_]) 269 ++index_; 270 } 271 272 template <class ObserverType> 273 void ObserverListBase<ObserverType>::AddObserver(ObserverType* obs) { 274 DCHECK(obs); 275 if (ContainsValue(observers_, obs)) { 276 NOTREACHED() << "Observers can only be added once!"; 277 return; 278 } 279 observers_.push_back(obs); 280 } 281 282 template <class ObserverType> 283 void ObserverListBase<ObserverType>::RemoveObserver(ObserverType* obs) { 284 DCHECK(obs); 285 typename ListType::iterator it = 286 std::find(observers_.begin(), observers_.end(), obs); 287 if (it != observers_.end()) { 288 if (notify_depth_) { 289 *it = nullptr; 290 } else { 291 observers_.erase(it); 292 } 293 } 294 } 295 296 template <class ObserverType> 297 bool ObserverListBase<ObserverType>::HasObserver( 298 const ObserverType* observer) const { 299 for (size_t i = 0; i < observers_.size(); ++i) { 300 if (observers_[i] == observer) 301 return true; 302 } 303 return false; 304 } 305 306 template <class ObserverType> 307 void ObserverListBase<ObserverType>::Clear() { 308 if (notify_depth_) { 309 for (typename ListType::iterator it = observers_.begin(); 310 it != observers_.end(); ++it) { 311 *it = nullptr; 312 } 313 } else { 314 observers_.clear(); 315 } 316 } 317 318 template <class ObserverType> 319 void ObserverListBase<ObserverType>::Compact() { 320 observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr), 321 observers_.end()); 322 } 323 324 template <class ObserverType, bool check_empty = false> 325 class ObserverList : public ObserverListBase<ObserverType> { 326 public: 327 typedef typename ObserverListBase<ObserverType>::NotificationType 328 NotificationType; 329 330 ObserverList() {} 331 explicit ObserverList(NotificationType type) 332 : ObserverListBase<ObserverType>(type) {} 333 334 ~ObserverList() { 335 // When check_empty is true, assert that the list is empty on destruction. 336 if (check_empty) { 337 ObserverListBase<ObserverType>::Compact(); 338 DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U); 339 } 340 } 341 342 bool might_have_observers() const { 343 return ObserverListBase<ObserverType>::size() != 0; 344 } 345 }; 346 347 } // namespace base 348 349 #endif // BASE_OBSERVER_LIST_H_ 350