Sygaldry
Loading...
Searching...
No Matches
sygac-endpoints.hpp
1#pragma once
2/*
3Copyright 2023 Travis J. West, https://traviswest.ca, Input Devices and Music
4Interaction Laboratory (IDMIL), Centre for Interdisciplinary Research in Music
5Media and Technology (CIRMMT), McGill University, Montréal, Canada, and Univ.
6Lille, Inria, CNRS, Centrale Lille, UMR 9189 CRIStAL, F-59000 Lille, France
7
8SPDX-License-Identifier: MIT
9*/
10
11#include <concepts>
12#include "sygah-consteval.hpp"
13
14namespace sygaldry {
15
19
23
24template<typename T>
25concept has_range = requires
26{
27 std::decay_t<T>::range().min;
28 std::decay_t<T>::range().max;
29 std::decay_t<T>::range().init;
30};
31
32template<has_range T>
33constexpr auto get_range(const T&) { return T::range(); }
34
35template<has_range T>
36_consteval auto get_range() { return std::decay_t<T>::range(); }
37template <typename T, typename Y>
39 = requires (T t) { static_cast<Y>(t); }
40 && requires (Y y) { T{y}; }
41 && requires (T t, Y y) { t = y; }
42 && requires (T a, T b, Y c) { a = b = c; }
43 ;
44
45template<typename T, typename Y>
46concept similar_to = strict_similar_to<std::remove_cvref_t<T>, std::remove_cvref_t<Y>>;
47template <typename T>
48concept has_value_variable = requires (T t)
49{
50 t.value;
51 requires similar_to<T, decltype(t.value)>;
52};
53
54template <typename T>
55concept has_value_method = requires (T t)
56{
57 t.value();
58 requires similar_to<T, decltype(t.value())>;
59};
60
61template <typename T>
64 && std::default_initializable<std::remove_cvref_t<T>>;
65template<typename T>
66concept BoolishFlag = requires (T t)
67{
68 bool(t);
69 t = T{}; // this is expected to be false when converted to bool
70};
71
72template<typename T>
73concept UpdatedFlag = requires (T t)
74{
75 t.updated;
76 requires std::same_as<bool, decltype(t.updated)>;
77};
78
79template<typename T> concept Flag = BoolishFlag<T> || UpdatedFlag<T>;
80
81template<typename T>
82concept _occasional_value = requires (T t)
83{
84 *t;
85 T{*t};
86 *t = *t;
87} && Flag<T>;
88
89template<typename T>
91template<typename T>
92concept Bang = requires (T t)
93{
94 requires std::is_enum_v<decltype(T::bang)>;
95} && Flag<T>;
96template<typename T>
98
99template<ClearableFlag T>
100constexpr void clear_flag(T& t)
101{
102 if constexpr (UpdatedFlag<T>) t.updated = false;
103 else if constexpr (BoolishFlag<T>) t = T{};
104}
105
106template<ClearableFlag T>
107constexpr bool flag_state_of(T& t)
108{
109 if constexpr (UpdatedFlag<T>) return t.updated;
110 else if constexpr (BoolishFlag<T>) return bool(t);
111}
112
113template<ClearableFlag T>
114constexpr void set_flag(T& t)
115{
116 if constexpr (UpdatedFlag<T>) t.updated = true;
117 else if constexpr (BoolishFlag<T>) t = true;
118}
119
120template <typename T>
122
123template <has_value T>
124auto& value_of(T& v)
125{
126 static_assert(PersistentValue<T> || OccasionalValue<T>, "value_of: Neither PersistentValue nor OccasionalValue. Did we add a new kind?");
127 if constexpr (PersistentValue<T>)
128 {
129 static_assert(has_value_variable<T> || has_value_method<T>, "value_of: PersistentValue with no method or variable. Did we add a new kind?");
130 if constexpr (has_value_variable<T>) return v.value;
131 else if constexpr (has_value_method<T>) return v.value();
132 else return 0;
133 }
134 else if constexpr (OccasionalValue<T>)
135 {
136 return *v;
137 }
138 else return 0;
139}
140
141template<has_value T>
142const auto& value_of(const T& v)
143{
144 return value_of(const_cast<T&>(v));
145}
146
147template <has_value T>
148auto& set_value(T& v, const auto& arg)
149{
150 if constexpr (requires {value_of(v).fill(arg);})
151 {
152 value_of(v).fill(arg);
153 if constexpr (ClearableFlag<T>) set_flag(v);
154 }
155 else v = arg;
156 return v;
157}
158template<has_value T>
159using value_t = std::remove_cvref_t<decltype(value_of(std::declval<T&>()))>;
160
161template<typename T> concept string_like = requires (T t, const char * s)
162{
163 t = s;
164};
165
166template<typename T> concept array_like = not string_like<T> && requires (T t)
167{
168 t[0];
169 t.size();
170} && std::same_as<std::remove_cvref_t<decltype(std::tuple_size_v<T>)>, std::size_t>;
171
172template<array_like T>
173_consteval auto size()
174{
175 return std::tuple_size_v<T>;
176}
177
178template<typename T> struct _element_type {};
179template<typename T> requires (array_like<value_t<T>>)
181{
182 using type = std::remove_cvref_t<decltype(std::declval<T>()[0])>;
183};
184template<typename T> requires (has_value<T> && not array_like<value_t<T>>)
185struct _element_type<T> { using type = value_t<T>; };
186template<has_value T> using element_t = typename _element_type<T>::type;
187#define tagged(TAG) template<typename T> concept tagged_##TAG\
188 = std::is_enum_v<decltype(T::TAG)>\
189 || std::is_enum_v<typename T::TAG>
190tagged(write_only); // don't display or output this endpoint's value
191tagged(session_data); // store this endpoint's value across sessions, e.g. across power cycles on an embedded system
192#undef tagged
193template<typename T>
194void initialize_endpoint(T& ep)
195{
196 if constexpr (not has_range<T>) return;
197 else set_value(ep, get_range(ep).init);
198}
199
202
203}
Definition sygac-endpoints.hpp:92
Definition sygac-endpoints.hpp:66
Definition sygac-endpoints.hpp:97
Definition sygac-endpoints.hpp:79
Definition sygac-endpoints.hpp:90
Definition sygac-endpoints.hpp:63
Definition sygac-endpoints.hpp:73
Definition sygac-endpoints.hpp:82
Definition sygac-endpoints.hpp:166
Definition sygac-endpoints.hpp:25
Definition sygac-endpoints.hpp:55
Definition sygac-endpoints.hpp:48
Definition sygac-endpoints.hpp:121
Definition sygac-endpoints.hpp:46
Definition sygac-endpoints.hpp:39
Definition sygac-endpoints.hpp:161
Definition sygac-endpoints.hpp:178