diff options
| author | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
|---|---|---|
| committer | Joel Klinghed <the_jk@spawned.biz> | 2021-11-17 22:34:57 +0100 |
| commit | 6232d13f5321b87ddf12a1aa36b4545da45f173d (patch) | |
| tree | 23f3316470a14136debd9d02f9e920ca2b06f4cc /src/observer_list.hh | |
Travel3: Simple image and video display site
Reads the images and videos from filesystem and builds a site in
memroy.
Diffstat (limited to 'src/observer_list.hh')
| -rw-r--r-- | src/observer_list.hh | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/src/observer_list.hh b/src/observer_list.hh new file mode 100644 index 0000000..86cdc03 --- /dev/null +++ b/src/observer_list.hh @@ -0,0 +1,148 @@ +#ifndef OBSERVER_LIST_HH +#define OBSERVER_LIST_HH + +#include "common.hh" + +#include <algorithm> +#include <vector> + +template<typename T> +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<T*> observers_; + unsigned active_{0}; + unsigned deleted_{0}; +}; + +#endif // OBSERVER_LIST_HH |
