HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
observable.hpp
1// Copyright Take Vos 2020.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "notifier.hpp"
8#include "hires_utc_clock.hpp"
9#include "cast.hpp"
10#include "notifier.hpp"
11#include "detail/observable_value.hpp"
12#include "detail/observable_not.hpp"
13#include <memory>
14#include <functional>
15#include <algorithm>
16
17namespace tt {
18
19template<typename T>
21public:
22 using value_type = T;
23 using notifier_type = notifier<void()>;
24 using callback_type = typename notifier_type::callback_type;
25 using callback_ptr_type = typename notifier_type::callback_ptr_type;
28
29 observable(observable const &other) noexcept : pimpl(other.pimpl)
30 {
31 pimpl_callback = pimpl->subscribe([this]() {
32 this->notifier();
33 });
34 }
35
36 observable &operator=(observable const &other) noexcept
37 {
38 pimpl->unsubscribe(pimpl_callback);
39 pimpl = other.pimpl;
40 pimpl_callback = pimpl->subscribe([this]() {
41 this->notifier();
42 });
43 this->notifier();
44 return *this;
45 }
46
47 // Use the copy constructor and assignment operator.
48 // observable(observable &&other) noexcept = delete;
49 // observable &operator=(observable &&other) noexcept = delete;
50
52 {
53 tt_axiom(pimpl);
54 }
55
56 observable() noexcept :
59 {
60 }
61
62 observable(value_type const &value) noexcept :
65 {
66 }
67
68 observable &operator=(value_type const &value) noexcept
69 {
70 store(value);
71 return *this;
72 }
73
74 observable &operator+=(value_type const &value) noexcept
75 {
76 store(load() + value);
77 return *this;
78 }
79
80 [[nodiscard]] value_type previous_value() const noexcept
81 {
82 tt_axiom(pimpl);
83 return pimpl->previous_value();
84 }
85
88 [[nodiscard]] time_point time_when_last_modified() const noexcept
89 {
90 tt_axiom(pimpl);
91 return pimpl->time_when_last_modified();
92 }
93
96 [[nodiscard]] duration duration_since_last_modified() const noexcept
97 {
98 tt_axiom(pimpl);
99 return pimpl->duration_since_last_modified();
100 }
101
108 [[nodiscard]] float animation_progress(duration animation_duration) const noexcept
109 {
110 tt_axiom(pimpl);
111 return pimpl->animation_progress(animation_duration);
112 }
113
114 [[nodiscard]] bool animating(duration animation_duration) const noexcept
115 {
116 tt_axiom(pimpl);
117 return pimpl->animation_progress(animation_duration) < 1.0f;
118 }
119
120 [[nodiscard]] value_type load() const noexcept
121 {
122 tt_axiom(pimpl);
123 return pimpl->load();
124 }
125
126 [[nodiscard]] value_type operator*() const noexcept
127 {
128 tt_axiom(pimpl);
129 return pimpl->load();
130 }
131
132 [[nodiscard]] value_type load(duration animation_duration) const noexcept
133 {
134 tt_axiom(pimpl);
135 return pimpl->load(animation_duration);
136 }
137
138 bool store(value_type const &new_value) noexcept
139 {
140 tt_axiom(pimpl);
141 return pimpl->store(new_value);
142 }
143
144 template<typename Callback>
145 [[nodiscard]] callback_ptr_type subscribe(Callback &&callback) noexcept
146 {
147 return notifier.subscribe(std::forward<Callback>(callback));
148 }
149
150 void subscribe_ptr(callback_ptr_type const &callback) noexcept
151 {
152 return notifier.subscribe_ptr(callback);
153 }
154
155 void unsubscribe(callback_ptr_type const &callback_ptr) noexcept
156 {
157 return notifier.unsubscribe(callback_ptr);
158 }
159
160 [[nodiscard]] friend observable<bool> operator!(observable const &rhs) noexcept
161 {
162 return std::static_pointer_cast<detail::observable_base<bool>>(std::make_shared<detail::observable_not<bool>>(rhs.pimpl));
163 }
164
165 [[nodiscard]] friend bool operator==(observable const &lhs, observable const &rhs) noexcept
166 {
167 return *lhs == *rhs;
168 }
169
170 [[nodiscard]] friend bool operator==(observable const &lhs, value_type const &rhs) noexcept
171 {
172 return *lhs == rhs;
173 }
174
175 [[nodiscard]] friend bool operator==(value_type const &lhs, observable const &rhs) noexcept
176 {
177 return lhs == *rhs;
178 }
179
180 [[nodiscard]] friend bool operator!=(observable const &lhs, observable const &rhs) noexcept
181 {
182 return *lhs != *rhs;
183 }
184
185 [[nodiscard]] friend bool operator!=(observable const &lhs, value_type const &rhs) noexcept
186 {
187 return *lhs != rhs;
188 }
189
190 [[nodiscard]] friend bool operator!=(value_type const &lhs, observable const &rhs) noexcept
191 {
192 return lhs != *rhs;
193 }
194
195 [[nodiscard]] friend float to_float(observable const &rhs) noexcept
196 {
197 return narrow_cast<float>(rhs.load());
198 }
199
200 [[nodiscard]] friend float to_float(observable const &rhs, duration animation_duration) noexcept
201 {
202 ttlet previous_value = narrow_cast<float>(rhs.previous_value());
203 ttlet current_value = narrow_cast<float>(rhs.load());
204 ttlet animation_progress = rhs.animation_progress(animation_duration);
205 return mix(animation_progress, previous_value, current_value);
206 }
207
208 [[nodiscard]] friend std::string to_string(observable const &rhs) noexcept
209 {
210 return to_string(rhs.load());
211 }
212
213 friend std::ostream &operator<<(std::ostream &lhs, observable const &rhs) noexcept
214 {
215 return lhs << rhs.load();
216 }
217
218private:
219 using pimpl_type = detail::observable_base<value_type>;
220
221 notifier_type notifier;
223 typename pimpl_type::callback_ptr_type pimpl_callback;
224
225 observable(std::shared_ptr<detail::observable_base<value_type>> const &other) noexcept : pimpl(other)
226 {
227 pimpl_callback = pimpl->subscribe([this]() {
228 this->notifier();
229 });
230 }
231
232 observable(std::shared_ptr<detail::observable_base<value_type>> &&other) noexcept : pimpl(std::move(other))
233 {
234 pimpl_callback = pimpl->subscribe([this]() {
235 this->notifier();
236 });
237 }
238
239 observable &operator=(std::shared_ptr<detail::observable_base<value_type>> const &other) noexcept
240 {
241 pimpl->unsubscribe(pimpl_callback);
242 pimpl = other;
243 pimpl_callback = pimpl->subscribe([this]() {
244 this->notifier();
245 });
246
247 this->notifier(this->load());
248 return *this;
249 }
250};
251
252} // namespace tt
Observable abstract base class.
Definition observable_base.hpp:30
Definition observable_value.hpp:13
Definition observable.hpp:20
duration duration_since_last_modified() const noexcept
Duration since the value was last modified.
Definition observable.hpp:96
float animation_progress(duration animation_duration) const noexcept
The relative time since the start of the animation.
Definition observable.hpp:108
time_point time_when_last_modified() const noexcept
Time when the value was modified last.
Definition observable.hpp:88
T make_shared(T... args)
T move(T... args)
T static_pointer_cast(T... args)