michael@0: // Copyright (c) 2011 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef BASE_OBSERVER_LIST_H__ michael@0: #define BASE_OBSERVER_LIST_H__ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "base/basictypes.h" michael@0: #include "base/logging.h" michael@0: #include "base/memory/weak_ptr.h" michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: // michael@0: // OVERVIEW: michael@0: // michael@0: // A container for a list of observers. Unlike a normal STL vector or list, michael@0: // this container can be modified during iteration without invalidating the michael@0: // iterator. So, it safely handles the case of an observer removing itself michael@0: // or other observers from the list while observers are being notified. michael@0: // michael@0: // TYPICAL USAGE: michael@0: // michael@0: // class MyWidget { michael@0: // public: michael@0: // ... michael@0: // michael@0: // class Observer { michael@0: // public: michael@0: // virtual void OnFoo(MyWidget* w) = 0; michael@0: // virtual void OnBar(MyWidget* w, int x, int y) = 0; michael@0: // }; michael@0: // michael@0: // void AddObserver(Observer* obs) { michael@0: // observer_list_.AddObserver(obs); michael@0: // } michael@0: // michael@0: // void RemoveObserver(Observer* obs) { michael@0: // observer_list_.RemoveObserver(obs); michael@0: // } michael@0: // michael@0: // void NotifyFoo() { michael@0: // FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); michael@0: // } michael@0: // michael@0: // void NotifyBar(int x, int y) { michael@0: // FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); michael@0: // } michael@0: // michael@0: // private: michael@0: // ObserverList observer_list_; michael@0: // }; michael@0: // michael@0: // michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: template michael@0: class ObserverListThreadSafe; michael@0: michael@0: template michael@0: class ObserverListBase michael@0: : public base::SupportsWeakPtr > { michael@0: public: michael@0: // Enumeration of which observers are notified. michael@0: enum NotificationType { michael@0: // Specifies that any observers added during notification are notified. michael@0: // This is the default type if non type is provided to the constructor. michael@0: NOTIFY_ALL, michael@0: michael@0: // Specifies that observers added while sending out notification are not michael@0: // notified. michael@0: NOTIFY_EXISTING_ONLY michael@0: }; michael@0: michael@0: // An iterator class that can be used to access the list of observers. See michael@0: // also the FOR_EACH_OBSERVER macro defined below. michael@0: class Iterator { michael@0: public: michael@0: Iterator(ObserverListBase& list) michael@0: : list_(list.AsWeakPtr()), michael@0: index_(0), michael@0: max_index_(list.type_ == NOTIFY_ALL ? michael@0: std::numeric_limits::max() : michael@0: list.observers_.size()) { michael@0: ++list_->notify_depth_; michael@0: } michael@0: michael@0: ~Iterator() { michael@0: if (list_.get() && --list_->notify_depth_ == 0) michael@0: list_->Compact(); michael@0: } michael@0: michael@0: ObserverType* GetNext() { michael@0: if (!list_.get()) michael@0: return NULL; michael@0: ListType& observers = list_->observers_; michael@0: // Advance if the current element is null michael@0: size_t max_index = std::min(max_index_, observers.size()); michael@0: while (index_ < max_index && !observers[index_]) michael@0: ++index_; michael@0: return index_ < max_index ? observers[index_++] : NULL; michael@0: } michael@0: michael@0: private: michael@0: base::WeakPtr > list_; michael@0: size_t index_; michael@0: size_t max_index_; michael@0: }; michael@0: michael@0: ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} michael@0: explicit ObserverListBase(NotificationType type) michael@0: : notify_depth_(0), type_(type) {} michael@0: michael@0: // Add an observer to the list. An observer should not be added to michael@0: // the same list more than once. michael@0: void AddObserver(ObserverType* obs) { michael@0: if (std::find(observers_.begin(), observers_.end(), obs) michael@0: != observers_.end()) { michael@0: NOTREACHED() << "Observers can only be added once!"; michael@0: return; michael@0: } michael@0: observers_.push_back(obs); michael@0: } michael@0: michael@0: // Remove an observer from the list if it is in the list. michael@0: void RemoveObserver(ObserverType* obs) { michael@0: typename ListType::iterator it = michael@0: std::find(observers_.begin(), observers_.end(), obs); michael@0: if (it != observers_.end()) { michael@0: if (notify_depth_) { michael@0: *it = 0; michael@0: } else { michael@0: observers_.erase(it); michael@0: } michael@0: } michael@0: } michael@0: michael@0: bool HasObserver(ObserverType* observer) const { michael@0: for (size_t i = 0; i < observers_.size(); ++i) { michael@0: if (observers_[i] == observer) michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: void Clear() { michael@0: if (notify_depth_) { michael@0: for (typename ListType::iterator it = observers_.begin(); michael@0: it != observers_.end(); ++it) { michael@0: *it = 0; michael@0: } michael@0: } else { michael@0: observers_.clear(); michael@0: } michael@0: } michael@0: michael@0: protected: michael@0: size_t size() const { return observers_.size(); } michael@0: michael@0: void Compact() { michael@0: observers_.erase( michael@0: std::remove(observers_.begin(), observers_.end(), michael@0: static_cast(NULL)), observers_.end()); michael@0: } michael@0: michael@0: private: michael@0: friend class ObserverListThreadSafe; michael@0: michael@0: typedef std::vector ListType; michael@0: michael@0: ListType observers_; michael@0: int notify_depth_; michael@0: NotificationType type_; michael@0: michael@0: friend class ObserverListBase::Iterator; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(ObserverListBase); michael@0: }; michael@0: michael@0: template michael@0: class ObserverList : public ObserverListBase { michael@0: public: michael@0: typedef typename ObserverListBase::NotificationType michael@0: NotificationType; michael@0: michael@0: ObserverList() {} michael@0: explicit ObserverList(NotificationType type) michael@0: : ObserverListBase(type) {} michael@0: michael@0: ~ObserverList() { michael@0: // When check_empty is true, assert that the list is empty on destruction. michael@0: if (check_empty) { michael@0: ObserverListBase::Compact(); michael@0: DCHECK_EQ(ObserverListBase::size(), 0U); michael@0: } michael@0: } michael@0: michael@0: bool might_have_observers() const { michael@0: return ObserverListBase::size() != 0; michael@0: } michael@0: }; michael@0: michael@0: #define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \ michael@0: do { \ michael@0: if ((observer_list).might_have_observers()) { \ michael@0: ObserverListBase::Iterator \ michael@0: it_inside_observer_macro(observer_list); \ michael@0: ObserverType* obs; \ michael@0: while ((obs = it_inside_observer_macro.GetNext()) != NULL) \ michael@0: obs->func; \ michael@0: } \ michael@0: } while (0) michael@0: michael@0: #endif // BASE_OBSERVER_LIST_H__