This repository was archived by the owner on Apr 27, 2026. It is now read-only.
forked from StrikerX3/Ymir
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathobservable.hpp
More file actions
131 lines (109 loc) · 4.15 KB
/
observable.hpp
File metadata and controls
131 lines (109 loc) · 4.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#pragma once
/**
@file
@brief Defines `util::Observable`, a type that implements the Observable design pattern.
*/
#include <cstdint>
#include <functional>
#include <type_traits>
#include <vector>
namespace util {
/// @brief An observable type stores a value of type `T` and allows other objects to observe and react to changes.
///
/// Observer functions run immediately after they're added to the observer and on the act of changing the value.
/// Be aware of this behavior to handle multithreaded scenarios properly.
///
/// @tparam T the type of the value
template <typename T>
class Observable {
public:
/// @brief The observer function type.
///
/// The value is passed by value if it fits in a pointer/register, otherwise it is passed by const reference.
using Observer = std::conditional_t<sizeof(T) <= sizeof(uintptr_t), void(T), void(const T &)>;
/// @brief Copy-constructs an observable from a value.
/// @param[in] value the value
Observable(const T &value)
: m_value(value) {}
/// @brief Move-constructs an observable from a value.
/// @param[in] value the value
Observable(T &&value) {
std::swap(value, m_value);
}
Observable() = default; ///< Default constructor
Observable(const Observable &) = delete; ///< Deleted copy constructor
Observable(Observable &&) = default; ///< Default move constructor
Observable &operator=(const Observable &) = delete; ///< Deleted copy assignment operator
Observable &operator=(Observable &&) = default; ///< Default move assignment operator
/// @brief Assigns the value to this observable and notifies all observers of the change.
/// @param[in] value the new value
/// @return a reference to this observable
Observable &operator=(T value) {
m_value = value;
Notify();
return *this;
}
/// @brief Accesses members of the value contained in this observable wrapper.
/// @return a pointer to the contained value
T *operator->() {
return &m_value;
}
/// @brief Accesses members of the value contained in this observable wrapper.
/// @return a `const` pointer to the contained value
const T *operator->() const {
return &m_value;
}
/// @brief Dereferences the value contained in this observable wrapper.
/// @return a reference to the contained value
T &operator*() {
return m_value;
}
/// @brief Dereferences the value contained in this observable wrapper.
/// @return a `const` reference to the contained value
const T &operator*() const {
return m_value;
}
/// @brief Adds an observer to this observable.
/// @param[in] observer the observer to add
void Observe(std::function<Observer> &&observer) {
m_fnObservers.emplace_back(std::move(observer));
}
/// @brief Adds an observer to this observable and immediately invokes the function with the current value.
/// @param[in] observer the observer to add
void ObserveAndNotify(std::function<Observer> &&observer) {
observer(m_value);
m_fnObservers.emplace_back(std::move(observer));
}
/// @brief Adds a simple observer to this observable that copies the value to the given reference.
///
/// Also copies the current value to the given reference.
///
/// @param[in] valueRef a reference to the value to be kept in sync with the value in this observer
void Observe(T &valueRef) {
m_valObservers.emplace_back(&valueRef);
valueRef = m_value;
}
/// @brief Notifies all observers of the current value.
void Notify() {
for (auto &observer : m_fnObservers) {
observer(m_value);
}
for (auto *observer : m_valObservers) {
*observer = m_value;
}
}
/// @brief Gets the current value.
/// @return the current value
T Get() const {
return m_value;
}
/// @brief Casts an observable into the underlying value.
operator T() const {
return m_value;
}
private:
T m_value;
std::vector<std::function<Observer>> m_fnObservers;
std::vector<T *> m_valObservers;
};
} // namespace util