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