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 "stl.hh"
6
7#include <vector>
8#include <cassert>
9
10namespace openmsx {
11
16template<typename T> class Subject
17{
18public:
19 Subject(const Subject&) = delete;
20 Subject(Subject&&) = delete;
21 Subject& operator=(const Subject&) = delete;
23
24 void attach(Observer<T>& observer);
25 void detach(Observer<T>& observer);
26 [[nodiscard]] bool anyObservers() const { return !observers.empty(); }
27
28protected:
29 Subject() = default;
31 void notify() const;
32
33private:
34 enum NotifyState {
35 IDLE, // no notify in progress
36 IN_PROGRESS, // notify in progress, no detach
37 DETACH, // notify in progress, some observer(s) have been detached
38 };
39
40 mutable std::vector<Observer<T>*> observers; // unordered
41 mutable NotifyState notifyState = IDLE;
42};
43
44template<typename T> Subject<T>::~Subject()
45{
46 assert(notifyState == IDLE);
47 for (auto copy = observers; auto& o : copy) {
48 o->subjectDeleted(*static_cast<const T*>(this));
49 }
50 assert(observers.empty());
51}
52
53template<typename T> void Subject<T>::attach(Observer<T>& observer)
54{
55 assert(notifyState == IDLE);
56 observers.push_back(&observer);
57}
58
59template<typename T> void Subject<T>::detach(Observer<T>& observer)
60{
61 auto it = rfind_unguarded(observers, &observer);
62 if (notifyState == IDLE) {
63 move_pop_back(observers, it);
64 } else {
65 *it = nullptr; // mark for removal
66 notifyState = DETACH; // schedule actual removal pass
67 }
68}
69
70template<typename T> void Subject<T>::notify() const
71{
72 assert(notifyState == IDLE);
73 notifyState = IN_PROGRESS;
74
75 for (auto& o : observers) {
76 try {
77 o->update(*static_cast<const T*>(this));
78 } catch (...) {
79 assert(false && "Observer::update() shouldn't throw");
80 }
81 }
82
83 if (notifyState == DETACH) {
84 std::erase(observers, nullptr);
85 }
86 notifyState = IDLE;
87}
88
89} // namespace openmsx
90
91#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:17
void detach(Observer< T > &observer)
Definition Subject.hh:59
Subject(Subject &&)=delete
Subject & operator=(Subject &&)=delete
void notify() const
Definition Subject.hh:70
Subject(const Subject &)=delete
Subject()=default
void attach(Observer< T > &observer)
Definition Subject.hh:53
bool anyObservers() const
Definition Subject.hh:26
Subject & operator=(const Subject &)=delete
This file implemented 3 utility functions:
Definition Autofire.cc:11
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