summaryrefslogtreecommitdiff
path: root/base/observer_list.h
diff options
context:
space:
mode:
Diffstat (limited to 'base/observer_list.h')
-rw-r--r--base/observer_list.h170
1 files changed, 35 insertions, 135 deletions
diff --git a/base/observer_list.h b/base/observer_list.h
index 0572ba6500..afe1f46cd6 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -11,7 +11,6 @@
#include <limits>
#include <vector>
-#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
@@ -47,14 +46,11 @@
// }
//
// void NotifyFoo() {
-// for (auto& observer : observer_list_)
-// observer.OnFoo(this);
+// FOR_EACH_OBSERVER(Observer, observer_list_, 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);
+// FOR_EACH_OBSERVER(Observer, observer_list_, OnBar(this, x, y));
// }
//
// private:
@@ -84,66 +80,20 @@ class ObserverListBase
NOTIFY_EXISTING_ONLY
};
- // An iterator class that can be used to access the list of observers.
- template <class ContainerType>
- class Iter {
+ // An iterator class that can be used to access the list of observers. See
+ // also the FOR_EACH_OBSERVER macro defined below.
+ class Iterator {
public:
- Iter();
- explicit Iter(ContainerType* list);
- ~Iter();
-
- // 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;
+ explicit Iterator(ObserverListBase<ObserverType>* list);
+ ~Iterator();
+ ObserverType* GetNext();
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) {}
@@ -174,99 +124,37 @@ class ObserverListBase
int notify_depth_;
NotificationType type_;
- template <class ContainerType>
- friend class Iter;
+ friend class ObserverListBase::Iterator;
DISALLOW_COPY_AND_ASSIGN(ObserverListBase);
};
template <class ObserverType>
-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()),
+ObserverListBase<ObserverType>::Iterator::Iterator(
+ ObserverListBase<ObserverType>* list)
+ : list_(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>
-template <class ContainerType>
-ObserverListBase<ObserverType>::Iter<ContainerType>::~Iter() {
- if (list_ && --list_->notify_depth_ == 0)
+ObserverListBase<ObserverType>::Iterator::~Iterator() {
+ if (list_.get() && --list_->notify_depth_ == 0)
list_->Compact();
}
template <class ObserverType>
-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_)
+ObserverType* ObserverListBase<ObserverType>::Iterator::GetNext() {
+ if (!list_.get())
return nullptr;
- 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_])
+ 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;
}
template <class ObserverType>
@@ -317,8 +205,9 @@ 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>
@@ -344,6 +233,17 @@ 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; \
+ } \
+ } while (0)
+
} // namespace base
#endif // BASE_OBSERVER_LIST_H_