mitteLib
Loading...
Searching...
No Matches
observable.hpp
Go to the documentation of this file.
1//
2// Created by spak on 10/29/21.
3//
4
5#ifndef MITTELIB_OBSERVABLE_HPP
6#define MITTELIB_OBSERVABLE_HPP
7
8#include <functional>
9#include <mutex>
10#include <vector>
11
12namespace mlab {
13
14 template <class T>
15 class observe;
16
17 template <class T>
18 class observable_ref;
19
20 template <class T>
21 class observable_cref;
22
23 template <class T>
24 class observable {
25 public:
26 using read_value_type = std::conditional_t<std::is_trivially_copyable_v<T>, T, T const &>;
27 using read_observer_fn = std::function<void(read_value_type)>;
28 using write_observer_fn = std::function<void(read_value_type, read_value_type)>;
29
30 inline observable();
31
32 inline explicit observable(T t);
33
34 inline operator read_value_type() const;
35
36 inline observable &operator=(T t);
37
38 friend class observe<T>;
39
40 [[nodiscard]] observe<T> do_observe(read_observer_fn read_fn, write_observer_fn write_fn);
41
42 [[nodiscard]] observable_ref<T> ref();
43 [[nodiscard]] observable_cref<T> cref() const;
44
45 private:
46 [[nodiscard]] std::size_t append_observer(std::pair<read_observer_fn, write_observer_fn> observers);
47 void delete_observer(std::size_t idx);
48
50 mutable std::recursive_mutex _lock;
51 std::vector<std::pair<read_observer_fn, write_observer_fn>> _observers;
52 };
53
54 template <class T>
56 protected:
58
59 public:
60 friend class observe<T>;
61
63
64 inline explicit observable_cref(observable<T> const &ref);
65
66 inline operator read_value_type() const;
67 };
68
69 template <class T>
70 class observable_ref : public observable_cref<T> {
71 using observable_cref<T>::_ref;
72
73 public:
74 friend class observe<T>;
75
79
80 using observable_cref<T>::operator read_value_type;
81
82 inline explicit observable_ref(observable<T> &ref);
83
84 inline observable_ref<T> &operator=(T t);
85
86 [[nodiscard]] observe<T> do_observe(read_observer_fn read_fn, write_observer_fn write_fn);
87 };
88
89
90 template <class T>
91 class observe {
93 std::size_t _idx = std::numeric_limits<std::size_t>::max();
94
95 public:
96 observe() = default;
97 observe(observe const &) = delete;
98 observe(observe &&other) noexcept;
99 observe &operator=(observe const &) = delete;
100 observe &operator=(observe &&other) noexcept;
101 ~observe();
102
103 void deregister();
104
105 observe(observable<T> &obs_value,
106 typename observable<T>::read_observer_fn read_fn,
107 typename observable<T>::write_observer_fn write_fn);
108 observe(observable_ref<T> &obs_value_ref,
109 typename observable<T>::read_observer_fn read_fn,
110 typename observable<T>::write_observer_fn write_fn);
111 };
112}// namespace mlab
113
114namespace mlab {
115
116 template <class T>
117 observable<T>::observable(T t) : _value{std::forward<T>(t)} {}
118
119 template <class T>
121
122 template <class T>
123 std::size_t observable<T>::append_observer(std::pair<read_observer_fn, write_observer_fn> observers) {
124 auto guard = std::scoped_lock{_lock};
125 _observers.template emplace_back(std::move(observers));
126 return _observers.size() - 1;
127 }
128
129 template <class T>
130 void observable<T>::delete_observer(std::size_t idx) {
131 auto guard = std::scoped_lock{_lock};
132 _observers.at(idx) = {nullptr, nullptr};
133 }
134
135 template <class T>
137 auto guard = std::scoped_lock{_lock};
138 for (auto &[r_fn, w_fn] : _observers) {
139 if (r_fn) {
140 r_fn(_value);
141 }
142 }
143 return _value;
144 }
145
146 template <class T>
148 auto guard = std::scoped_lock{_lock};
149 for (auto &[r_fn, w_fn] : _observers) {
150 if (w_fn) {
151 w_fn(_value, t);
152 }
153 }
154 if constexpr (std::is_trivially_copyable_v<T>) {
155 _value = t;
156 } else {
157 _value = std::move(t);
158 }
159 return *this;
160 }
161
162 template <class T>
164 deregister();
165 }
166
167 template <class T>
169 return {*this, std::move(read_fn), std::move(write_fn)};
170 }
171
172 template <class T>
174 if (_obs_value != nullptr and _idx < std::numeric_limits<std::size_t>::max()) {
175 _obs_value->delete_observer(_idx);
176 _idx = std::numeric_limits<std::size_t>::max();
177 _obs_value = nullptr;
178 }
179 }
180
181 template <class T>
182 observe<T>::observe(observe &&other) noexcept : observe{} {
183 *this = std::move(other);
184 }
185
186 template <class T>
188 std::swap(_obs_value, other._obs_value);
189 std::swap(_idx, other._idx);
190 return *this;
191 }
192
193 template <class T>
195 typename observable<T>::write_observer_fn write_fn) : _obs_value{&obs_value},
196 _idx{obs_value.append_observer({std::move(read_fn), std::move(write_fn)})} {}
197
198 template <class T>
200 typename observable<T>::write_observer_fn write_fn) : _obs_value{&obs_value_ref._ref},
201 _idx{obs_value_ref._ref.append_observer({std::move(read_fn), std::move(write_fn)})} {}
202
203
204 template <class T>
208
209 template <class T>
213
214 template <class T>
216
217 template <class T>
219
220 template <class T>
222 return _ref;
223 }
224
225 template <class T>
227 const_cast<observable<T> &>(_ref) = std::forward<T>(t);
228 return *this;
229 }
230
231 template <class T>
233 return const_cast<observable<T> &>(_ref).do_observe(std::move(read_fn), std::move(write_fn));
234 }
235}// namespace mlab
236
237#endif//MITTELIB_OBSERVABLE_HPP
Definition observable.hpp:55
observable_cref(observable< T > const &ref)
Definition observable.hpp:215
typename observable< T >::read_value_type read_value_type
Definition observable.hpp:62
observable< T > const & _ref
Definition observable.hpp:57
Definition observable.hpp:70
observe< T > do_observe(read_observer_fn read_fn, write_observer_fn write_fn)
Definition observable.hpp:232
typename observable< T >::read_observer_fn read_observer_fn
Definition observable.hpp:77
observable_ref< T > & operator=(T t)
Definition observable.hpp:226
typename observable< T >::write_observer_fn write_observer_fn
Definition observable.hpp:78
observable_ref(observable< T > &ref)
Definition observable.hpp:218
typename observable_cref< T >::read_value_type read_value_type
Definition observable.hpp:76
Definition observable.hpp:24
std::recursive_mutex _lock
Definition observable.hpp:50
std::size_t append_observer(std::pair< read_observer_fn, write_observer_fn > observers)
Definition observable.hpp:123
observable_cref< T > cref() const
Definition observable.hpp:210
T _value
Definition observable.hpp:49
observable & operator=(T t)
Definition observable.hpp:147
observable_ref< T > ref()
Definition observable.hpp:205
std::function< void(read_value_type, read_value_type)> write_observer_fn
Definition observable.hpp:28
void delete_observer(std::size_t idx)
Definition observable.hpp:130
std::function< void(read_value_type)> read_observer_fn
Definition observable.hpp:27
observable()
Definition observable.hpp:120
observe< T > do_observe(read_observer_fn read_fn, write_observer_fn write_fn)
Definition observable.hpp:168
std::conditional_t< std::is_trivially_copyable_v< T >, T, T const & > read_value_type
Definition observable.hpp:26
std::vector< std::pair< read_observer_fn, write_observer_fn > > _observers
Definition observable.hpp:51
Definition observable.hpp:91
observe & operator=(observe const &)=delete
observe(observe const &)=delete
~observe()
Definition observable.hpp:163
observable< T > * _obs_value
Definition observable.hpp:92
void deregister()
Definition observable.hpp:173
observe()=default
std::size_t _idx
Definition observable.hpp:93
Definition log.cpp:8