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 60 template <typename ObserverType> 61 class ObserverListThreadSafe; 62 63 template <class ObserverType> 64 class 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 : list_(list.AsWeakPtr()), 84 index_(0), 85 max_index_(list.type_ == NOTIFY_ALL ? 86 std::numeric_limits<size_t>::max() : 87 list.observers_.size()) { 88 ++list_->notify_depth_; 89 } 90 91 ~Iterator() { 92 if (list_.get() && --list_->notify_depth_ == 0) 93 list_->Compact(); 94 } 95 96 ObserverType* GetNext() { 97 if (!list_.get()) 98 return NULL; 99 ListType& observers = list_->observers_; 100 // Advance if the current element is null 101 size_t max_index = std::min(max_index_, observers.size()); 102 while (index_ < max_index && !observers[index_]) 103 ++index_; 104 return index_ < max_index ? observers[index_++] : NULL; 105 } 106 107 private: 108 base::WeakPtr<ObserverListBase<ObserverType> > list_; 109 size_t index_; 110 size_t max_index_; 111 }; 112 113 ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} 114 explicit ObserverListBase(NotificationType type) 115 : notify_depth_(0), type_(type) {} 116 117 // Add an observer to the list. An observer should not be added to 118 // the same list more than once. 119 void AddObserver(ObserverType* obs) { 120 if (std::find(observers_.begin(), observers_.end(), obs) 121 != observers_.end()) { 122 NOTREACHED() << "Observers can only be added once!"; 123 return; 124 } 125 observers_.push_back(obs); 126 } 127 128 // Remove an observer from the list if it is in the list. 129 void RemoveObserver(ObserverType* obs) { 130 typename ListType::iterator it = 131 std::find(observers_.begin(), observers_.end(), obs); 132 if (it != observers_.end()) { 133 if (notify_depth_) { 134 *it = 0; 135 } else { 136 observers_.erase(it); 137 } 138 } 139 } 140 141 bool HasObserver(ObserverType* observer) const { 142 for (size_t i = 0; i < observers_.size(); ++i) { 143 if (observers_[i] == observer) 144 return true; 145 } 146 return false; 147 } 148 149 void Clear() { 150 if (notify_depth_) { 151 for (typename ListType::iterator it = observers_.begin(); 152 it != observers_.end(); ++it) { 153 *it = 0; 154 } 155 } else { 156 observers_.clear(); 157 } 158 } 159 160 protected: 161 size_t size() const { return observers_.size(); } 162 163 void Compact() { 164 observers_.erase( 165 std::remove(observers_.begin(), observers_.end(), 166 static_cast<ObserverType*>(NULL)), observers_.end()); 167 } 168 169 private: 170 friend class ObserverListThreadSafe<ObserverType>; 171 172 typedef std::vector<ObserverType*> ListType; 173 174 ListType observers_; 175 int notify_depth_; 176 NotificationType type_; 177 178 friend class ObserverListBase::Iterator; 179 180 DISALLOW_COPY_AND_ASSIGN(ObserverListBase); 181 }; 182 183 template <class ObserverType, bool check_empty = false> 184 class ObserverList : public ObserverListBase<ObserverType> { 185 public: 186 typedef typename ObserverListBase<ObserverType>::NotificationType 187 NotificationType; 188 189 ObserverList() {} 190 explicit ObserverList(NotificationType type) 191 : ObserverListBase<ObserverType>(type) {} 192 193 ~ObserverList() { 194 // When check_empty is true, assert that the list is empty on destruction. 195 if (check_empty) { 196 ObserverListBase<ObserverType>::Compact(); 197 DCHECK_EQ(ObserverListBase<ObserverType>::size(), 0U); 198 } 199 } 200 201 bool might_have_observers() const { 202 return ObserverListBase<ObserverType>::size() != 0; 203 } 204 }; 205 206 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ 207 do { \ 208 if ((observer_list).might_have_observers()) { \ 209 ObserverListBase<ObserverType>::Iterator \ 210 it_inside_observer_macro(observer_list); \ 211 ObserverType* obs; \ 212 while ((obs = it_inside_observer_macro.GetNext()) != NULL) \ 213 obs->func; \ 214 } \ 215 } while (0) 216 217 #endif // BASE_OBSERVER_LIST_H__ 218