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

Unified Diff: base/observer_list.h

Issue 2340583005: Base ObserverList: Add basic support for standard C++ iterators. (Closed)
Patch Set: Remove excessive mutable. Created 4 years, 2 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..7543a98180995fba09e4905e78ad1fab275d8d10 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -11,6 +11,7 @@
#include <limits>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -46,11 +47,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 +84,69 @@ 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();
+
+ // 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;
+ bool operator!=(const Iter& other) const;
+ ThisType& operator++();
+ ObserverType* operator->() const;
+ ObserverType& operator*() const;
+
private:
+ FRIEND_TEST_ALL_PREFIXES(ObserverListTest, BasicStdIterator);
+ FRIEND_TEST_ALL_PREFIXES(ObserverListTest, StdIteratorRemoveFront);
+
+ ObserverType* GetCurrent() const;
+ void EnsureValidIndex();
+
+ size_t clamped_max_index() const {
+ return std::min(max_index_, list_->observers_.size());
+ }
+
+ bool is_end() const { return !list_ || index_ == clamped_max_index(); }
+
WeakPtr<ObserverListBase<ObserverType>> list_;
+ // When initially constructed and each time the iterator is incremented,
+ // |index_| is guaranteed to point to a non-null index if the iterator
+ // has not reached the end of the ObserverList.
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) {}
@@ -124,37 +177,108 @@ class ObserverListBase
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_(0), max_index_(0) {}
+
+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()) {
+ EnsureValidIndex();
+ DCHECK(list_);
++list_->notify_depth_;
}
template <class ObserverType>
-ObserverListBase<ObserverType>::Iterator::~Iterator() {
- if (list_.get() && --list_->notify_depth_ == 0)
+template <class ContainerType>
+ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
+ if (list_ && --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 {
+ if (is_end() && other.is_end())
+ return true;
+ return list_.get() == other.list_.get() && index_ == other.index_;
+}
+
+template <class ObserverType>
+template <class ContainerType>
+bool ObserverListBase<ObserverType>::Iter<ContainerType>::operator!=(
+ const Iter& other) const {
+ return !operator==(other);
+}
+
+template <class ObserverType>
+template <class ContainerType>
+typename ObserverListBase<ObserverType>::template Iter<ContainerType>&
+ ObserverListBase<ObserverType>::Iter<ContainerType>::operator++() {
+ if (list_) {
+ ++index_;
+ EnsureValidIndex();
+ }
+ 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;
- 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_])
+ return index_ < clamped_max_index() ? list_->observers_[index_] : nullptr;
+}
+
+template <class ObserverType>
+template <class ContainerType>
+void ObserverListBase<ObserverType>::Iter<ContainerType>::EnsureValidIndex() {
+ if (!list_)
+ return;
+
+ size_t max_index = clamped_max_index();
+ while (index_ < max_index && !list_->observers_[index_])
++index_;
- return index_ < max_index ? observers[index_++] : nullptr;
+}
+
+template <class ObserverType>
+template <class ContainerType>
+ObserverType* ObserverListBase<ObserverType>::Iter<ContainerType>::GetNext() {
+ EnsureValidIndex();
+ ObserverType* current = GetCurrent();
+ operator++();
+ return current;
}
template <class ObserverType>
@@ -205,9 +329,8 @@ void ObserverListBase<ObserverType>::Clear() {
template <class ObserverType>
void ObserverListBase<ObserverType>::Compact() {
- observers_.erase(
- std::remove(observers_.begin(), observers_.end(), nullptr),
- observers_.end());
+ observers_.erase(std::remove(observers_.begin(), observers_.end(), nullptr),
+ observers_.end());
}
template <class ObserverType, bool check_empty = false>
@@ -233,15 +356,11 @@ class ObserverList : public ObserverListBase<ObserverType> {
}
};
-#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
- do { \
- if ((observer_list).might_have_observers()) { \
- typename base::ObserverListBase<ObserverType>::Iterator \
- it_inside_observer_macro(&observer_list); \
- ObserverType* obs; \
- while ((obs = it_inside_observer_macro.GetNext()) != nullptr) \
- obs->func; \
- } \
+// Deprecated. Use the range-based for loop instead.
+#define FOR_EACH_OBSERVER(ObserverType, observer_list, func) \
+ do { \
+ for (ObserverType & o : observer_list) \
+ o.func; \
} while (0)
} // namespace base
« 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