Chromium Code Reviews| Index: cc/base/observer_map.h |
| diff --git a/cc/base/observer_map.h b/cc/base/observer_map.h |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f34cba6755434eabe60e82834af8af2b486b9101 |
| --- /dev/null |
| +++ b/cc/base/observer_map.h |
| @@ -0,0 +1,156 @@ |
| +// Copyright 2014 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#ifndef CC_BASE_OBSERVER_MAP_H_ |
| +#define CC_BASE_OBSERVER_MAP_H_ |
| + |
| +#include "base/containers/hash_tables.h" |
| +#include "base/logging.h" |
| + |
| +namespace cc { |
| + |
| +template <class ObserverType, class ObserverDataType> |
|
danakj
2015/09/11 17:56:09
Do you need to use this with multiple ObserverType
mithro-old
2015/09/11 19:03:57
For our use case we probably only have one Observe
|
| +class ObserverMap { |
| + private: |
| + typedef typename base::hash_set<ObserverType*> SetType; |
| + typedef typename base::hash_map<ObserverType*, ObserverDataType*> MapType; |
| + |
| + MapType observers_; |
| + |
| + volatile size_t const_iterators_; |
| + size_t iterators_; |
| + MapType observers_to_add_; |
| + SetType observers_to_remove_; |
| + |
| + public: |
| + ObserverMap() |
| + : observers_(), |
| + const_iterators_(0), |
| + iterators_(0), |
| + observers_to_add_(), |
| + observers_to_remove_() {} |
| + |
| + class iterator : public MapType::iterator { |
| + public: |
| + explicit iterator(typename MapType::iterator it, |
| + ObserverMap<ObserverType, ObserverDataType>* list) |
| + : MapType::iterator(it), list_(list) { |
| + list_->iterators_++; |
| + } |
| + ~iterator() { |
| + DCHECK_GT(list_->iterators_, 0U); |
| + list_->iterators_--; |
| + list_->CompactMaps(); |
| + } |
| + |
| + private: |
| + ObserverMap<ObserverType, ObserverDataType>* list_; |
| + }; |
| + |
| + class const_iterator : public MapType::const_iterator { |
| + public: |
| + explicit const_iterator( |
| + typename MapType::const_iterator it, |
| + const ObserverMap<ObserverType, ObserverDataType>* list) |
| + : MapType::const_iterator(it), |
| + list_( |
| + const_cast<ObserverMap<ObserverType, ObserverDataType>*>(list)) { |
| + list_->const_iterators_++; |
| + } |
| + ~const_iterator() { |
| + DCHECK_GT(list_->const_iterators_, 0U); |
| + list_->const_iterators_--; |
| + } |
| + |
| + private: |
| + ObserverMap<ObserverType, ObserverDataType>* list_; |
| + }; |
| + |
| + void AddObserver(ObserverType* obs) { |
| + DCHECK_EQ(const_iterators_, 0U); |
| + if (observers_to_add_.count(obs) == 0) { |
| + observers_to_add_[obs] = new ObserverDataType(); |
| + } |
| + CompactMaps(); |
| + } |
| + |
| + void RemoveObserver(ObserverType* obs) { |
| + DCHECK_EQ(const_iterators_, 0U); |
| + observers_to_remove_.insert(obs); |
| + CompactMaps(); |
| + } |
| + |
| + bool HasObservers() const { return !observers_.empty(); } |
| + bool HasObserver(ObserverType* const obs) const { |
| + return (*this)[obs] != nullptr; |
| + } |
| + |
| + iterator begin() { return iterator(observers_.begin(), this); } |
| + iterator end() { return iterator(observers_.end(), this); } |
| + |
| + const_iterator cbegin() const { |
| + return const_iterator(const_cast<const MapType*>(&observers_)->begin(), |
| + this); |
| + } |
| + |
| + const_iterator cend() const { |
| + return const_iterator(const_cast<const MapType*>(&observers_)->end(), this); |
| + } |
| + |
| + const_iterator begin() const { return cbegin(); } |
| + const_iterator end() const { return cend(); } |
| + |
| + ObserverDataType* operator[](ObserverType* const obs) { |
| + { |
| + auto it = observers_.find(obs); |
| + if (it != observers_.end()) |
| + return it->second; |
| + } |
| + { |
| + auto it = observers_to_add_.find(obs); |
| + if (it != observers_to_add_.end()) |
| + return it->second; |
| + } |
| + return nullptr; |
| + } |
| + const ObserverDataType* operator[](ObserverType* const obs) const { |
| + { |
| + auto it = observers_.find(obs); |
| + if (it != observers_.end()) |
| + return it->second; |
| + } |
| + { |
| + auto it = observers_to_add_.find(obs); |
| + if (it != observers_to_add_.end()) |
| + return it->second; |
| + } |
| + return nullptr; |
| + } |
| + |
| + private: |
| + void CompactMaps() { |
| + if (iterators_ != 0) |
| + return; |
| + |
| + for (auto it = observers_to_remove_.begin(); |
| + it != observers_to_remove_.end(); it++) { |
| + delete observers_[*it]; |
| + observers_[*it] = nullptr; |
| + observers_.erase(*it); |
| + } |
| + observers_to_remove_.clear(); |
| + |
| + for (auto it = observers_to_add_.begin(); it != observers_to_add_.end(); |
| + it++) { |
| + observers_[it->first] = it->second; |
| + } |
| + observers_to_add_.clear(); |
| + } |
| + |
| + friend class ObserverMapTest; |
| +}; |
| + |
| +} // namespace cc |
| + |
| +#endif // CC_BASE_OBSERVER_MAP_H_ |