Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2002)

Unified Diff: base/observer_list.h

Issue 2340583005: Base ObserverList: Add basic support for standard C++ iterators. (Closed)
Patch Set: Add a comment on MSVC. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | base/observer_list_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/observer_list.h
diff --git a/base/observer_list.h b/base/observer_list.h
index afe1f46cd6e31bfaa0456cec8614fd73f3cd0e1e..a8159a57dc639a7876af696d4a09cd88d5270a67 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -46,11 +46,14 @@
// }
//
// 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_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
+// for (FooList::iterator i = observer_list.begin(),
+// e = observer_list.end(); i != e; ++i)
+// i->OnBar(this, x, y);
// }
//
// private:
@@ -80,20 +83,60 @@ 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 {
dcheng 2016/10/03 07:29:18 Derive from std::iterator.
loyso (OOO) 2016/10/04 03:46:57 This comment conflicts with your previous comment
loyso (OOO) 2016/10/04 04:12:02 Also, please notice that ObserverList isn't a C++
dcheng 2016/10/04 23:53:39 As discussed offline, this does work (e.g. https:/
public:
- explicit Iterator(ObserverListBase<ObserverType>* list);
- ~Iterator();
+ Iter();
+ explicit Iter(ContainerType* list);
+ ~Iter();
+
+ // Deprecated.
ObserverType* GetNext();
+ // 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++();
+ ObserverType* operator->() const;
+ ObserverType& operator*() const;
+
private:
- WeakPtr<ObserverListBase<ObserverType>> list_;
+ ObserverType* GetCurrent() const;
+
+ size_t GetNonNullIndex() const;
+
+ size_t clamped_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() {
+ // An optimization: do not involve weak pointers for empty list.
+ // Note: can't use ?: operator here due to some MSVC bug (unit tests fail)
+ if (observers_.empty())
+ return iterator();
+ return iterator(this);
+ }
+ iterator end() { return iterator(); }
+
+ using const_iterator = Iter<const ObserverListBase<ObserverType>>;
+ const_iterator begin() const {
+ if (observers_.empty())
+ return const_iterator();
+ 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 +156,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 +165,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_() {}
dcheng 2016/10/03 07:29:18 Nit: write 0 explicitly here forconsistency.
loyso (OOO) 2016/10/04 03:46:57 Done.
+
+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 +190,81 @@ 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())
- 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_])
+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++() {
+ if (list_) {
++index_;
- return index_ < max_index ? observers[index_++] : nullptr;
+ index_ = GetNonNullIndex();
+ }
+ return *this;
+}
+
+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>::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;
+ size_t index = GetNonNullIndex();
+ return index < clamped_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 = clamped_max_index();
+ while (index < max_index && !list_->observers_[index])
+ ++index;
+ return index;
+}
+
+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 +314,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>
@@ -233,6 +343,7 @@ class ObserverList : public ObserverListBase<ObserverType> {
}
};
+// Deprecated. Use the range-based for loop instead.
#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
do { \
if ((observer_list).might_have_observers()) { \
dcheng 2016/10/03 07:29:18 Can we structure the macro so we can use the new r
loyso (OOO) 2016/10/04 03:46:57 No, we can't. Some places use GetNext method and I
dcheng 2016/10/04 23:53:39 As discussed offline, let's switch the macro to us
loyso (OOO) 2016/10/05 07:24:42 Done.
« no previous file with comments | « no previous file | base/observer_list_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698