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