1 // Copyright (c) 2006-2008 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 15 /////////////////////////////////////////////////////////////////////////////// 16 // 17 // OVERVIEW: 18 // 19 // A container for a list of observers. Unlike a normal STL vector or list, 20 // this container can be modified during iteration without invalidating the 21 // iterator. So, it safely handles the case of an observer removing itself 22 // or other observers from the list while observers are being notified. 23 // 24 // TYPICAL USAGE: 25 // 26 // class MyWidget { 27 // public: 28 // ... 29 // 30 // class Observer { 31 // public: 32 // virtual void OnFoo(MyWidget* w) = 0; 33 // virtual void OnBar(MyWidget* w, int x, int y) = 0; 34 // }; 35 // 36 // void AddObserver(Observer* obs) { 37 // observer_list_.AddObserver(obs); 38 // } 39 // 40 // void RemoveObserver(Observer* obs) { 41 // observer_list_.RemoveObserver(obs); 42 // } 43 // 44 // void NotifyFoo() { 45 // FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); 46 // } 47 // 48 // void NotifyBar(int x, int y) { 49 // FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); 50 // } 51 // 52 // private: 53 // ObserverList<Observer> observer_list_; 54 // }; 55 // 56 // 57 /////////////////////////////////////////////////////////////////////////////// 58 59 template <class ObserverType, bool check_empty = false> 60 class ObserverList { 61 public: 62 // Enumeration of which observers are notified. 63 enum NotificationType { 64 // Specifies that any observers added during notification are notified. 65 // This is the default type if non type is provided to the constructor. 66 NOTIFY_ALL, 67 68 // Specifies that observers added while sending out notification are not 69 // notified. 70 NOTIFY_EXISTING_ONLY 71 }; 72 73 ObserverList() : notify_depth_(0), type_(NOTIFY_ALL) {} 74 ObserverList(NotificationType type) : notify_depth_(0), type_(type) {} 75 ~ObserverList() { 76 // When check_empty is true, assert that the list is empty on destruction. 77 if (check_empty) { 78 Compact(); 79 DCHECK_EQ(observers_.size(), 0U); 80 } 81 } 82 83 // Add an observer to the list. 84 void AddObserver(ObserverType* obs) { 85 DCHECK(find(observers_.begin(), observers_.end(), obs) == observers_.end()) 86 << "Observers can only be added once!"; 87 observers_.push_back(obs); 88 } 89 90 // Remove an observer from the list. 91 void RemoveObserver(ObserverType* obs) { 92 typename ListType::iterator it = 93 std::find(observers_.begin(), observers_.end(), obs); 94 if (it != observers_.end()) { 95 if (notify_depth_) { 96 *it = 0; 97 } else { 98 observers_.erase(it); 99 } 100 } 101 } 102 103 size_t size() const { 104 return observers_.size(); 105 } 106 107 ObserverType* GetElementAt(int index) const { 108 return observers_[index]; 109 } 110 111 // An iterator class that can be used to access the list of observers. See 112 // also the FOREACH_OBSERVER macro defined below. 113 class Iterator { 114 public: 115 Iterator(const ObserverList<ObserverType>& list) 116 : list_(list), 117 index_(0), 118 max_index_(list.type_ == NOTIFY_ALL ? 119 std::numeric_limits<size_t>::max() : 120 list.observers_.size()) { 121 ++list_.notify_depth_; 122 } 123 124 ~Iterator() { 125 if (--list_.notify_depth_ == 0) 126 list_.Compact(); 127 } 128 129 ObserverType* GetNext() { 130 ListType& observers = list_.observers_; 131 // Advance if the current element is null 132 size_t max_index = std::min(max_index_, observers.size()); 133 while (index_ < max_index && !observers[index_]) 134 ++index_; 135 return index_ < max_index ? observers[index_++] : NULL; 136 } 137 138 private: 139 const ObserverList<ObserverType>& list_; 140 size_t index_; 141 size_t max_index_; 142 }; 143 144 private: 145 typedef std::vector<ObserverType*> ListType; 146 147 void Compact() const { 148 typename ListType::iterator it = observers_.begin(); 149 while (it != observers_.end()) { 150 if (*it) { 151 ++it; 152 } else { 153 it = observers_.erase(it); 154 } 155 } 156 } 157 158 // These are marked mutable to facilitate having NotifyAll be const. 159 mutable ListType observers_; 160 mutable int notify_depth_; 161 NotificationType type_; 162 163 friend class ObserverList::Iterator; 164 165 DISALLOW_EVIL_CONSTRUCTORS(ObserverList); 166 }; 167 168 #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ 169 do { \ 170 ObserverList<ObserverType>::Iterator it(observer_list); \ 171 ObserverType* obs; \ 172 while ((obs = it.GetNext()) != NULL) \ 173 obs->func; \ 174 } while (0) 175 176 #endif // BASE_OBSERVER_LIST_H__ 177