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