OGLplus  (0.59.0) a C++ wrapper for rendering APIs

value_with_history.hpp
Go to the documentation of this file.
1 
9 #ifndef EAGINE_VALUE_WITH_HISTORY_HPP
10 #define EAGINE_VALUE_WITH_HISTORY_HPP
11 
12 #include "compare.hpp"
13 #include "valid_if/decl.hpp"
14 #include <cmath>
15 #include <utility>
16 
17 namespace eagine {
18 //------------------------------------------------------------------------------
19 template <typename T>
20 static constexpr auto
21 value_with_history_changed(const T& a, const T& b) noexcept -> bool {
22  return !are_equal(a, b);
23 }
24 
25 template <typename T>
26 static constexpr auto
27 value_with_history_delta(const T& new_value, const T& old_value) noexcept {
28  return new_value - old_value;
29 }
30 
31 static constexpr auto
32 value_with_history_delta(bool new_value, bool old_value) noexcept -> int {
33  return int(new_value) - int(old_value);
34 }
35 
36 template <typename T>
37 static constexpr auto
38 value_with_history_distance(const T& new_value, const T& old_value) noexcept {
39  using std::abs;
40  return abs(value_with_history_delta(new_value, old_value));
41 }
42 //------------------------------------------------------------------------------
50 template <typename T, std::size_t N>
52 public:
54  constexpr value_with_history_storage() = default;
55 
57  template <typename... I, typename = std::enable_if_t<sizeof...(I) == N>>
58  constexpr value_with_history_storage(I&&... initial)
59  : _values{T(initial)...} {}
60 
62  constexpr value_with_history_storage(const T& initial) noexcept {
63  for(std::size_t i = 0; i < N; ++i) {
64  _values[i] = initial;
65  }
66  }
67 
69  constexpr auto get(std::size_t i) const noexcept -> const T& {
70  EAGINE_ASSERT(i < N);
71  return _values[i];
72  }
73 
75  void set(std::size_t i, const T& value) noexcept {
76  EAGINE_ASSERT(i < N);
77  _values[i] = value;
78  }
79 
82  void make_history() noexcept {
83  for(std::size_t i = 1; i < N; ++i) {
84  _values[N - i] = _values[N - i - 1];
85  }
86  }
87 
90  void sync() noexcept {
91  for(std::size_t i = 1; i < N; ++i) {
92  _values[i] = _values[0];
93  }
94  }
95 
96 private:
97  T _values[N]{};
98 };
99 //------------------------------------------------------------------------------
100 template <typename Transform, typename... T, std::size_t N>
101 static inline auto transform_stored_values(
102  Transform transform_op,
103  const value_with_history_storage<T, N>&... v) {
104  value_with_history_storage<
105  decltype(std::declval<Transform>()(std::declval<T>()...)),
106  N>
107  result;
108 
109  for(std::size_t i = 0; i < N; ++i) {
110  result.set(i, transform_op(v.get(i)...));
111  }
112  return result;
113 }
114 //------------------------------------------------------------------------------
115 template <typename Delta, typename T, std::size_t N>
116 static inline auto differentiate_stored_values(
117  Delta delta_op,
118  const value_with_history_storage<T, N>& v) {
119  value_with_history_storage<
120  decltype(std::declval<Delta>()(std::declval<T>(), std::declval<T>())),
121  N - 1>
122  result;
123 
124  for(std::size_t i = 1; i < N; ++i) {
125  result.set(i - 1, delta_op(v.get(i - 1), v.get(i)));
126  }
127  return result;
128 }
129 //------------------------------------------------------------------------------
130 template <typename U, typename T, std::size_t N>
131 static inline auto
132 convert_stored_values(const value_with_history_storage<T, N>& storage) {
133  return transform_stored_values([](const T& v) { return U(v); }, storage);
134 }
135 //------------------------------------------------------------------------------
140 template <typename T, std::size_t N>
142 public:
144  : _values{storage} {}
145 
147  template <typename... I>
148  constexpr value_with_history(I&&... initial)
149  : _values{std::forward<I>(initial)...} {}
150 
152  auto values() const noexcept -> const value_with_history_storage<T, N>& {
153  return _values;
154  }
155 
158  auto get() const noexcept {
159  return values().get(0);
160  }
161 
165  auto value() const noexcept {
166  return values().get(0);
167  }
168 
172  auto old_value() const noexcept {
173  return values().get(1);
174  }
175 
179  auto value(bool old) const noexcept {
180  return old ? old_value() : value();
181  }
182 
185  operator T() const noexcept {
186  return value();
187  }
188 
189  template <typename U, typename... P>
190  operator valid_if<U, P...>() const noexcept {
191  return {U(value())};
192  }
193 
195  auto delta() const noexcept {
196  return value_with_history_delta(value(), old_value());
197  }
198 
200  auto deltas() const noexcept {
201  return value_with_history<decltype(delta()), N - 1>(
202  differentiate_stored_values(
203  [](const T& n, const T& o) {
204  return value_with_history_delta(n, o);
205  },
206  values()));
207  }
208 
210  auto distance() const noexcept {
211  return value_with_history_distance(value(), old_value());
212  }
213 
215  auto changed() const noexcept -> bool {
216  return value_with_history_changed(old_value(), value());
217  }
218 
220  template <typename U>
221  auto as() const {
222  return value_with_history<U, N>(convert_stored_values<U>(values()));
223  }
224 
227  void sync() {
228  this->values().sync();
229  }
230 
231 protected:
232  auto values() noexcept -> value_with_history_storage<T, N>& {
233  return _values;
234  }
235 
236  auto _update_value(const T& new_value) noexcept -> bool {
237 
238  if(value_with_history_changed(values().get(0), new_value)) {
239  values().make_history();
240  values().set(0, new_value);
241  return true;
242  }
243  return false;
244  }
245 
246  auto _advance_value(const T& delta_value) noexcept -> bool {
247  values().make_history();
248  values().set(0, values().get(0) + delta_value);
249  return true;
250  }
251 
252  value_with_history() = default;
253 
254  explicit value_with_history(const T& initial) noexcept
255  : _values(initial) {}
256 
257 private:
258  static_assert(N >= 2, "at least two values are required");
259  value_with_history_storage<T, N> _values;
260 };
261 //------------------------------------------------------------------------------
262 template <typename Transform, typename... T, std::size_t N>
263 static inline auto
264 transform(Transform transform_op, const value_with_history<T, N>&... v) {
265  return value_with_history<
266  decltype(std::declval<Transform>()(std::declval<T>()...)),
267  N>(transform_stored_values(transform_op, v.values()...));
268 }
269 //------------------------------------------------------------------------------
270 template <typename T1, typename T2, std::size_t N>
271 static inline auto operator*(
272  const value_with_history<T1, N>& v1,
273  const value_with_history<T2, N>& v2) noexcept {
274  return transform(
275  [](const T1& t1, const T2& t2) { return t1 * t2; }, v1, v2);
276 }
277 //------------------------------------------------------------------------------
278 template <typename T1, typename T2, std::size_t N>
279 static inline auto operator/(
280  const value_with_history<T1, N>& v1,
281  const value_with_history<T2, N>& v2) noexcept {
282  return transform(
283  [](const T1& t1, const T2& t2) { return t1 / t2; }, v1, v2);
284 }
285 //------------------------------------------------------------------------------
290 template <typename T, std::size_t N>
292 public:
294  constexpr variable_with_history() noexcept = default;
295 
297  constexpr variable_with_history(const T& initial) noexcept
298  : value_with_history<T, N>(initial) {}
299 
301  auto assign(const T& new_value) -> bool {
302  return this->_update_value(new_value);
303  }
304 
306  auto advance(const T& delta_value) -> bool {
307  return this->_advance_value(delta_value);
308  }
309 };
310 //------------------------------------------------------------------------------
311 template <typename T, typename... P, std::size_t N>
312 class variable_with_history<valid_if<T, P...>, N>
313  : public value_with_history<T, N> {
314 public:
315  constexpr variable_with_history(const valid_if<T, P...>& initial) noexcept
316  : value_with_history<T, N>(initial.value()) {}
317 
318  auto assign(const valid_if<T, P...>& new_value) -> bool {
319  return this->_update_value(new_value.value());
320  }
321 
322  auto advance(const valid_if<T, P...>& delta_value) -> bool {
323  return this->_advance_value(delta_value.value());
324  }
325 };
326 //------------------------------------------------------------------------------
327 } // namespace eagine
328 
329 #endif // EAGINE_VALUE_WITH_HISTORY_HPP
auto values() const noexcept -> const value_with_history_storage< T, N > &
Returns a reference to the value storage.
Definition: value_with_history.hpp:152
void set(std::size_t i, const T &value) noexcept
Sets the i-th revision of the stored value (0 = current value).
Definition: value_with_history.hpp:75
auto distance() const noexcept
Returns the distance between the current and the previous revisions.
Definition: value_with_history.hpp:210
Base storage class for values and variables with history.
Definition: value_with_history.hpp:51
constexpr value_with_history_storage(I &&... initial)
Initializes the individual revisions of the value.
Definition: value_with_history.hpp:58
Common code is placed in this namespace.
Definition: eagine.hpp:21
auto value() const noexcept
Returns the current revision of the value.
Definition: value_with_history.hpp:165
auto changed() const noexcept -> bool
Indicates if the current and previous revisions differ.
Definition: value_with_history.hpp:215
void sync() noexcept
Synchronize the historic revisions to the current value.
Definition: value_with_history.hpp:90
Primary template for conditionally valid values.
Definition: decl.hpp:49
constexpr value_with_history(I &&... initial)
Initialized the individual revisions of this value.
Definition: value_with_history.hpp:148
void sync()
Synchronize the historic revisions to the current value.
Definition: value_with_history.hpp:227
constexpr auto get(std::size_t i) const noexcept -> const T &
Returns the i-th revision of the stored value (0 = current value).
Definition: value_with_history.hpp:69
auto delta() const noexcept
Returns the difference between the current and the previous revision.
Definition: value_with_history.hpp:195
auto as() const
Returns this with the values cast to new type U.
Definition: value_with_history.hpp:221
Class for read-only values with history.
Definition: value_with_history.hpp:141
void make_history() noexcept
Move the stored revisions by one, to make place for new value.
Definition: value_with_history.hpp:82
auto value(bool old) const noexcept
Returns the current or previous revision of the value.
Definition: value_with_history.hpp:179
constexpr value_with_history_storage(const T &initial) noexcept
Initializes all revisions with the same initial value.
Definition: value_with_history.hpp:62
auto old_value() const noexcept
Returns the previous revision of the value.
Definition: value_with_history.hpp:172
auto deltas() const noexcept
Returns the differences between the adjacent revisions.
Definition: value_with_history.hpp:200
auto advance(const T &delta_value) -> bool
Shifts the revisions and advanced the current value by given delta.
Definition: value_with_history.hpp:306
constexpr value_with_history_storage()=default
Default constructor.
constexpr variable_with_history() noexcept=default
Default constructor.
auto get() const noexcept
Returns the current revision of the value.
Definition: value_with_history.hpp:158
constexpr variable_with_history(const T &initial) noexcept
Initialize the all revisions to the initial value.
Definition: value_with_history.hpp:297
auto assign(const T &new_value) -> bool
Shifts the revisions and assigns a new value.
Definition: value_with_history.hpp:301
Class for mutable variables with history.
Definition: value_with_history.hpp:291

Copyright © 2015-2021 Matúš Chochlík.
<chochlik -at -gmail.com>
Documentation generated on Tue Apr 13 2021 by Doxygen (version 1.8.17).