Chromium Code Reviews| Index: base/observer_list.h |
| diff --git a/base/observer_list.h b/base/observer_list.h |
| index afe1f46cd6e31bfaa0456cec8614fd73f3cd0e1e..a4e7f80364c00c415bd2d4010a23c14b2d682e7c 100644 |
| --- a/base/observer_list.h |
| +++ b/base/observer_list.h |
| @@ -46,10 +46,21 @@ |
| // } |
| // |
| // void NotifyFoo() { |
| -// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); |
| +// for (auto& observer : observer_list_) |
| +// observer.OnFoo(this); |
| // } |
| // |
| // void NotifyBar(int x, int y) { |
| +// for (FooList::iterator i = observer_list.begin(), |
| +// e = observer_list.end(); i != e; ++i) |
| +// i->OnBar(this, x, y); |
| +// } |
| +// |
| +// void NotifyFooDeprecated() { |
| +// FOR_EACH_OBSERVER(Observer, observer_list_, OnFoo(this)); |
| +// } |
| +// |
| +// void NotifyBarDeprecated(int x, int y) { |
| // FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y)); |
| // } |
| // |
| @@ -80,20 +91,51 @@ class ObserverListBase |
| NOTIFY_EXISTING_ONLY |
| }; |
| - // An iterator class that can be used to access the list of observers. See |
| - // also the FOR_EACH_OBSERVER macro defined below. |
| - class Iterator { |
| + // An iterator class that can be used to access the list of observers. |
| + template <class ContainerType> |
| + class Iter { |
| public: |
| - explicit Iterator(ObserverListBase<ObserverType>* list); |
| - ~Iterator(); |
| + Iter(); |
| + explicit Iter(ContainerType* list); |
| + ~Iter(); |
| + |
| ObserverType* GetNext(); |
| + ObserverType* GetCurrent() const; |
| + void Advance(); |
| + |
| + // A workaround for C2244. MSVC requires fully qualified type name for |
| + // return type on a function definition to match a function declaration. |
| + using ThisType = |
| + typename ObserverListBase<ObserverType>::template Iter<ContainerType>; |
| + |
| + bool operator!=(const Iter& other) const; |
| + ThisType& operator++(); |
| + ThisType operator++(int); |
|
dcheng
2016/09/16 21:44:17
Do we need to provide both prefix and postfix vers
|
| + ObserverType* operator->() const; |
| + ObserverType& operator*() const; |
| + |
| private: |
| - WeakPtr<ObserverListBase<ObserverType>> list_; |
| + size_t GetNonNullIndex() const; |
| + |
| + size_t checked_max_index() const { |
| + return std::min(max_index_, list_->observers_.size()); |
| + } |
| + WeakPtr<ContainerType> list_; |
| size_t index_; |
| size_t max_index_; |
| }; |
| + using Iterator = Iter<ObserverListBase<ObserverType>>; |
| + |
| + using iterator = Iter<ObserverListBase<ObserverType>>; |
| + iterator begin() { return iterator(this); } |
| + iterator end() { return iterator(); } |
| + |
| + using const_iterator = Iter<const ObserverListBase<ObserverType>>; |
| + const_iterator begin() const { return const_iterator(this); } |
| + const_iterator end() const { return const_iterator(); } |
| + |
| ObserverListBase() : notify_depth_(0), type_(NOTIFY_ALL) {} |
| explicit ObserverListBase(NotificationType type) |
| : notify_depth_(0), type_(type) {} |
| @@ -113,7 +155,8 @@ class ObserverListBase |
| protected: |
| size_t size() const { return observers_.size(); } |
| - void Compact(); |
| + // Defragments the list despite const. |
| + void Compact() const; |
| private: |
| friend class ObserverListThreadSafe<ObserverType>; |
| @@ -121,18 +164,24 @@ class ObserverListBase |
| typedef std::vector<ObserverType*> ListType; |
| ListType observers_; |
| - int notify_depth_; |
| + mutable int notify_depth_; |
| NotificationType type_; |
| - friend class ObserverListBase::Iterator; |
| + template <class ContainerType> |
| + friend class Iter; |
| DISALLOW_COPY_AND_ASSIGN(ObserverListBase); |
| }; |
| template <class ObserverType> |
| -ObserverListBase<ObserverType>::Iterator::Iterator( |
| - ObserverListBase<ObserverType>* list) |
| - : list_(list->AsWeakPtr()), |
| +template <class ContainerType> |
| +ObserverListBase<ObserverType>::Iter<ContainerType>::Iter() |
| + : index_(), max_index_() {} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +ObserverListBase<ObserverType>::Iter<ContainerType>::Iter(ContainerType* list) |
| + : list_(const_cast<ObserverListBase<ObserverType>*>(list)->AsWeakPtr()), |
| index_(0), |
| max_index_(list->type_ == NOTIFY_ALL ? std::numeric_limits<size_t>::max() |
| : list->observers_.size()) { |
| @@ -140,21 +189,95 @@ ObserverListBase<ObserverType>::Iterator::Iterator( |
| } |
| template <class ObserverType> |
| -ObserverListBase<ObserverType>::Iterator::~Iterator() { |
| +template <class ContainerType> |
| +ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() { |
| if (list_.get() && --list_->notify_depth_ == 0) |
| list_->Compact(); |
| } |
| template <class ObserverType> |
| -ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() { |
| - if (!list_.get()) |
| +template <class ContainerType> |
| +bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=( |
| + const Iter& other) const { |
| + return GetCurrent() != other.GetCurrent(); |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +typename ObserverListBase<ObserverType>::template Iter<ContainerType>& |
| + ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() { |
| + Advance(); |
| + return *this; |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +typename ObserverListBase<ObserverType>::template Iter<ContainerType> |
| + ObserverListBase<ObserverType>::Iter<ContainerType>::operator++(int) { |
| + Iter previous(*this); |
| + Advance(); |
| + return previous; |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::operator->() |
| + const { |
| + return GetCurrent(); |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +ObserverType& ObserverListBase<ObserverType>::Iter<ContainerType>::operator*() |
| + const { |
| + ObserverType* current = GetCurrent(); |
| + DCHECK(current); |
| + return *current; |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetCurrent() |
| + const { |
| + if (!list_) |
| return nullptr; |
| - ListType& observers = list_->observers_; |
| - // Advance if the current element is null |
| - size_t max_index = std::min(max_index_, observers.size()); |
| - while (index_ < max_index && !observers[index_]) |
| - ++index_; |
| - return index_ < max_index ? observers[index_++] : nullptr; |
| + size_t index = GetNonNullIndex(); |
| + return index < checked_max_index() ? list_->observers_[index] : nullptr; |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +size_t ObserverListBase<ObserverType>::Iter<ContainerType>::GetNonNullIndex() |
| + const { |
| + size_t index = index_; |
| + size_t max_index = checked_max_index(); |
| + while (index < max_index && !list_->observers_[index]) |
| + ++index; |
| + return index; |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +void ObserverListBase<ObserverType>::Iter<ContainerType>::Advance() { |
| + if (!list_) |
| + return; |
| + |
| + ++index_; |
| + index_ = GetNonNullIndex(); |
| +} |
| + |
| +template <class ObserverType> |
| +template <class ContainerType> |
| +ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetNext() { |
| + if (!list_) |
| + return nullptr; |
| + |
| + ObserverType* current = GetCurrent(); |
| + |
| + index_ = GetNonNullIndex(); |
| + ++index_; |
| + |
| + return current; |
| } |
| template <class ObserverType> |
| @@ -204,10 +327,10 @@ void ObserverListBase<ObserverType>::Clear() { |
| } |
| template <class ObserverType> |
| -void ObserverListBase<ObserverType>::Compact() { |
| - observers_.erase( |
| - std::remove(observers_.begin(), observers_.end(), nullptr), |
| - observers_.end()); |
| +void ObserverListBase<ObserverType>::Compact() const { |
| + auto& observers = const_cast<ListType&>(observers_); |
| + observers.erase(std::remove(observers.begin(), observers.end(), nullptr), |
| + observers.end()); |
| } |
| template <class ObserverType, bool check_empty = false> |