#ifndef OBSERVER_LIST_HH #define OBSERVER_LIST_HH #include "common.hh" #include #include template class ObserverList { public: class iterator { public: iterator() : list_(nullptr), index_(0), end_(0) {} ~iterator() { if (list_) list_->release(); } iterator(iterator const& it) : list_(it.list_), index_(it.index_), end_(it.end_) { if (list_) { list_->aquire(); while (index_ < end_ && !list_->observers_[index_]) ++index_; } } iterator& operator=(iterator const& it) { if (list_ != it.list_) { if (list_) list_->release(); list_ = it.list_; if (list_) list_->aquire(); } index_ = it.index_; end_ = it.end_; return *this; } explicit operator bool() { return index_ < end_; } T& operator*() { return *list_->observers_[index_]; } T* operator->() { return list_->observers_[index_]; } iterator operator++(int) { iterator ret(*this); ++(*this); return ret; } iterator& operator++() { if (index_ < end_) { do { ++index_; } while (index_ < end_ && !list_->observers_[index_]); } return *this; } private: friend class ObserverList; iterator(ObserverList* list, size_t index, size_t end) : list_(list), index_(index), end_(end) { list_->aquire(); while (index_ < end_ && !list_->observers_[index_]) ++index_; } ObserverList* list_; size_t index_; size_t end_; }; ObserverList() = default; ~ObserverList() { assert(active_ == 0); } bool empty() const { return observers_.empty(); } void add(T* observer) { assert(std::find(observers_.begin(), observers_.end(), observer) == observers_.end()); observers_.push_back(observer); } void remove(T* observer) { auto it = std::find(observers_.begin(), observers_.end(), observer); if (it != observers_.end()) { if (active_) { *it = nullptr; ++deleted_; } else { observers_.erase(it); } } else { assert(false); } } iterator notify() { return iterator(this, 0, observers_.size()); } private: void aquire() { ++active_; } void release() { assert(active_ > 0); --active_; if (active_ == 0 && deleted_) cleanup(); } void cleanup() { size_t i = observers_.size(); while (deleted_ && i > 0) { --i; if (!observers_[i]) { --deleted_; observers_.erase(observers_.begin() + i); } } assert(deleted_ == 0); } std::vector observers_; unsigned active_{0}; unsigned deleted_{0}; }; #endif // OBSERVER_LIST_HH