openMSX
Subject.hh
Go to the documentation of this file.
1#ifndef SUBJECT_HH
2#define SUBJECT_HH
3
4#include "Observer.hh"
5#include "ranges.hh"
6#include "stl.hh"
7
8#include <vector>
9#include <cassert>
10
11namespace openmsx {
12
17template<typename T> class Subject
18{
19public:
20 Subject(const Subject&) = delete;
21 Subject(Subject&&) = delete;
22 Subject& operator=(const Subject&) = delete;
24
25 void attach(Observer<T>& observer);
26 void detach(Observer<T>& observer);
27 [[nodiscard]] bool anyObservers() const { return !observers.empty(); }
28
29protected:
30 Subject() = default;
32 void notify() const;
33
34private:
35 enum NotifyState {
36 IDLE, // no notify in progress
37 IN_PROGRESS, // notify in progress, no detach
38 DETACH, // notify in progress, some observer(s) have been detached
39 };
40
41 mutable std::vector<Observer<T>*> observers; // unordered
42 mutable NotifyState notifyState = IDLE;
43};
44
45template<typename T> Subject<T>::~Subject()
46{
47 assert(notifyState == IDLE);
48 for (auto copy = observers; auto& o : copy) {
49 o->subjectDeleted(*static_cast<const T*>(this));
50 }
51 assert(observers.empty());
52}
53
54template<typename T> void Subject<T>::attach(Observer<T>& observer)
55{
56 assert(notifyState == IDLE);
57 observers.push_back(&observer);
58}
59
60template<typename T> void Subject<T>::detach(Observer<T>& observer)
61{
62 auto it = rfind_unguarded(observers, &observer);
63 if (notifyState == IDLE) {
64 move_pop_back(observers, it);
65 } else {
66 *it = nullptr; // mark for removal
67 notifyState = DETACH; // schedule actual removal pass
68 }
69}
70
71template<typename T> void Subject<T>::notify() const
72{
73 assert(notifyState == IDLE);
74 notifyState = IN_PROGRESS;
75
76 for (auto& o : observers) {
77 try {
78 o->update(*static_cast<const T*>(this));
79 } catch (...) {
80 assert(false && "Observer::update() shouldn't throw");
81 }
82 }
83
84 if (notifyState == DETACH) {
85 observers.erase(ranges::remove(observers, nullptr), observers.end());
86 }
87 notifyState = IDLE;
88}
89
90} // namespace openmsx
91
92#endif
Generic Gang-of-Four Observer class, templatized edition.
Definition Observer.hh:10
Generic Gang-of-Four Subject class of the Observer pattern, templatized edition.
Definition Subject.hh:18
void detach(Observer< T > &observer)
Definition Subject.hh:60
Subject(Subject &&)=delete
Subject & operator=(Subject &&)=delete
void notify() const
Definition Subject.hh:71
Subject(const Subject &)=delete
Subject()=default
void attach(Observer< T > &observer)
Definition Subject.hh:54
bool anyObservers() const
Definition Subject.hh:27
Subject & operator=(const Subject &)=delete
This file implemented 3 utility functions:
Definition Autofire.cc:11
auto remove(ForwardRange &&range, const T &value)
Definition ranges.hh:291
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
Definition stl.hh:137
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
Definition stl.hh:112