Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
tools.hpp
Go to the documentation of this file.
1
5#ifndef USER_MODE_TOOLS_H
6#define USER_MODE_TOOLS_H
7
8#include <cstdint>
9#include <cstring>
10#include <utility>
11#include <optional>
12#include <tuple>
13
16
17#ifndef LMBD_CPP17
18#error "File requires -DLMBD_CPP17 to explicitly enables C++17 features"
19#endif
20
21namespace lampda::modes {
22
24template<typename Mode> static constexpr bool is_mode = std::is_base_of_v<BasicMode, Mode>;
25
26//
27// StateTyOf
28// - returns StateTy if defined
29// - or else return EmptyState
30//
31
33struct NoState
34{
35};
36
38template<typename Mode,
39 typename StateTy = typename Mode::StateTy,
40 bool isDefault = std::is_same_v<StateTy, BasicMode::StateTy> || (sizeof(StateTy) == 0),
41 typename RetTy = std::conditional_t<isDefault, NoState, StateTy>>
42static constexpr auto stateTyOfImpl(int) -> RetTy;
43
45template<typename> static constexpr auto stateTyOfImpl(...) -> NoState;
46
48template<typename Mode> using StateTyOf = decltype(stateTyOfImpl<Mode>(0));
49
50//
51// Store
52//
53
55struct NoStoreId
56{
57};
58
60enum class NoStoreHere : uint16_t
61{
62 noKeyDefined // placeholder (should not be used)
63};
64
66template<typename Mode,
67 typename EnumTy = typename Mode::Store,
68 bool isDefault = (Mode::storeId == BasicMode::storeId),
69 typename RetTy = std::conditional_t<isDefault, NoStoreHere, EnumTy>>
70static constexpr auto storeEnumOfImpl(int) -> RetTy;
71
73template<typename> static constexpr auto storeEnumOfImpl(...) -> NoStoreHere;
74
76template<typename Mode> using StoreEnumOf = decltype(storeEnumOfImpl<Mode>(0));
77
79namespace details {
80
81//
82// unroll
83//
84
86template<class CbTy, uint8_t... Indexes>
87static constexpr void LMBD_INLINE unroll_impl(CbTy&& cb, std::integer_sequence<uint8_t, Indexes...>)
88{
89 (cb(std::integral_constant<uint8_t, Indexes> {}), ...);
90}
91
93template<uint8_t N, class CbTy> static constexpr void LMBD_INLINE unroll(CbTy&& cb)
94{
95 constexpr auto Indexes = std::make_integer_sequence<uint8_t, N>();
96 unroll_impl(
97 [&](auto I) LMBD_INLINE {
98 return cb(std::integral_constant<uint8_t, decltype(I)::value> {});
99 },
100 Indexes);
101}
102
103//
104// forEach & anyOf & allOf
105//
106
108template<typename TupleTy, uint8_t TupleSz = std::tuple_size_v<TupleTy>> struct forEach
109{
111 template<template<class> class QueryStruct, bool hasError = false> static constexpr bool any()
112 {
113 bool acc = false;
114 if constexpr (!hasError)
115 {
116 unroll<TupleSz>([&](auto Idx) {
117 acc |= QueryStruct<std::tuple_element_t<Idx, TupleTy>>::value;
118 });
119 }
120 return acc;
121 }
122
124 template<template<class> class QueryStruct, bool hasError = false> static constexpr bool all()
125 {
126 bool acc = true;
127 if constexpr (!hasError)
128 {
129 unroll<TupleSz>([&](auto Idx) {
130 acc &= QueryStruct<std::tuple_element_t<Idx, TupleTy>>::value;
131 });
132 }
133 else
134 {
135 return false;
136 }
137 return acc;
138 }
139
141 template<template<class> class QueryStruct, bool hasError = false> static constexpr auto asTable()
142 {
143 // collect all values as table
144 std::array<bool, TupleSz> acc {};
145 if constexpr (!hasError)
146 {
147 unroll<TupleSz>([&](auto Idx) {
148 constexpr size_t I = decltype(Idx)::value;
149 acc[I] = QueryStruct<std::tuple_element_t<Idx, TupleTy>>::value;
150 });
151 }
152 return acc;
153 }
154
156 template<template<class> class QueryStruct, bool hasError = false> static constexpr size_t getMaxTableSize()
157 {
158 size_t acc = 0;
159 if constexpr (!hasError)
160 {
161 unroll<TupleSz>([&](auto Idx) {
162 size_t sz = QueryStruct<std::tuple_element_t<Idx, TupleTy>>::value.size();
163 if (sz > acc)
164 acc = sz;
165 });
166 }
167 return acc;
168 }
169
171 template<template<class> class QueryStruct, size_t MaxSz, bool hasError = false> static constexpr auto asTable2D()
172 {
173 // collect all values as table
174 std::array<std::array<bool, MaxSz>, TupleSz> acc {};
175 if constexpr (!hasError)
176 {
177 unroll<TupleSz>([&](auto Idx) {
178 constexpr size_t I = decltype(Idx)::value;
179
180 auto& remote = QueryStruct<std::tuple_element_t<Idx, TupleTy>>::value;
181 for (size_t J = 0; J < remote.size() && J < MaxSz; ++J)
182 {
183 acc[I][J] = remote[J];
184 }
185 });
186 }
187 return acc;
188 }
189};
190
192template<typename TupleTy, bool hasError = false> struct anyOf
193{
194 template<typename Ty> struct QHasSunset
195 {
197 static constexpr bool value = Ty::hasSunsetAnimation;
198 };
199
200 template<typename Ty> struct QHasBright
201 {
203 static constexpr bool value = Ty::hasBrightCallback;
204 };
205
206 template<typename Ty> struct QCustomRamp
207 {
209 static constexpr bool value = Ty::hasCustomRamp;
210 };
211
212 template<typename Ty> struct QButtonUI
213 {
215 static constexpr bool value = Ty::hasButtonCustomUI;
216 };
217
218 template<typename Ty> struct QHasSystem
219 {
221 static constexpr bool value = Ty::hasSystemCallbacks;
222 };
223
224 template<typename Ty> struct QUserThread
225 {
227 static constexpr bool value = Ty::requireUserThread;
228 };
229
230 // booleans we need
231 static constexpr bool hasSunsetAnimation = forEach<TupleTy>::template any<QHasSunset, hasError>();
232 static constexpr bool hasBrightCallback = forEach<TupleTy>::template any<QHasBright, hasError>();
233 static constexpr bool hasCustomRamp = forEach<TupleTy>::template any<QCustomRamp, hasError>();
234 static constexpr bool hasButtonCustomUI = forEach<TupleTy>::template any<QButtonUI, hasError>();
235 static constexpr bool hasSystemCallbacks = forEach<TupleTy>::template any<QHasSystem, hasError>();
236 static constexpr bool requireUserThread = forEach<TupleTy>::template any<QUserThread, hasError>();
237
238 // as table
239 static constexpr auto everySunsetCallback = forEach<TupleTy>::template asTable<QHasSunset, hasError>();
240 static constexpr auto everyBrightCallback = forEach<TupleTy>::template asTable<QHasBright, hasError>();
241 static constexpr auto everyCustomRamp = forEach<TupleTy>::template asTable<QCustomRamp, hasError>();
242 static constexpr auto everyButtonCustomUI = forEach<TupleTy>::template asTable<QButtonUI, hasError>();
243 static constexpr auto everySystemCallbacks = forEach<TupleTy>::template asTable<QHasSystem, hasError>();
244 static constexpr auto everyRequireUserThread = forEach<TupleTy>::template asTable<QUserThread, hasError>();
245};
246
248template<typename TupleTy, bool hasError = false> struct asTableFor
249{
250 template<typename Ty> struct QHasSunset
251 {
253 static constexpr auto value = Ty::everySunsetCallback;
254 };
255
256 template<typename Ty> struct QHasBright
257 {
259 static constexpr auto value = Ty::everyBrightCallback;
260 };
261
262 template<typename Ty> struct QCustomRamp
263 {
265 static constexpr auto value = Ty::everyCustomRamp;
266 };
267
268 template<typename Ty> struct QButtonUI
269 {
271 static constexpr auto value = Ty::everyButtonCustomUI;
272 };
273
274 template<typename Ty> struct QHasSystem
275 {
277 static constexpr auto value = Ty::everySystemCallbacks;
278 };
279
280 template<typename Ty> struct QUserThread
281 {
283 static constexpr auto value = Ty::everyRequireUserThread;
284 };
285
286 static constexpr size_t maxTableSz = forEach<TupleTy>::template getMaxTableSize<QHasBright, hasError>();
287
289 static constexpr auto everySunsetCallback = forEach<TupleTy>::template asTable2D<QHasSunset, maxTableSz, hasError>();
291 static constexpr auto everyBrightCallback = forEach<TupleTy>::template asTable2D<QHasBright, maxTableSz, hasError>();
293 static constexpr auto everyCustomRamp = forEach<TupleTy>::template asTable2D<QCustomRamp, maxTableSz, hasError>();
295 static constexpr auto everyButtonCustomUI = forEach<TupleTy>::template asTable2D<QButtonUI, maxTableSz, hasError>();
297 static constexpr auto everySystemCallbacks = forEach<TupleTy>::template asTable2D<QHasSystem, maxTableSz, hasError>();
299 static constexpr auto everyRequireUserThread =
300 forEach<TupleTy>::template asTable2D<QUserThread, maxTableSz, hasError>();
301};
302
304template<typename TupleTy, bool hasError = false> struct allOf
305{
306 template<typename Ty> struct QIsMode
307 {
309 static constexpr bool value = is_mode<Ty>;
310 };
311
312 template<typename Ty> struct QStateOk
313 {
315 static constexpr bool value = std::is_default_constructible_v<StateTyOf<Ty>>;
316 };
317
319 static constexpr bool inheritsFromBasicMode = forEach<TupleTy>::template all<QIsMode, hasError>();
321 static constexpr bool stateDefaultConstructible = forEach<TupleTy>::template all<QStateOk, hasError>();
322};
323
324//
325// StateTyFor & StateTyFrom
326//
327
329template<typename... Modes> using StateTyFor = std::tuple<std::optional<StateTyOf<Modes>>...>;
330
332template<typename... Modes> static constexpr auto stateTyFromImpl(std::tuple<Modes...>*) -> StateTyFor<Modes...>;
333
335template<typename AsTuple> using StateTyFrom = decltype(stateTyFromImpl((AsTuple*)0));
336
337//
338// ModeBelongsTo & GroupBelongsTo
339//
340
341template<typename Item, typename... Items> static constexpr bool belongsToImpl(std::tuple<Items...>*)
342{
343 return (std::is_same_v<Item, Items> || ...);
344};
345
347template<typename Mode, typename AllModes> static constexpr bool ModeBelongsTo = belongsToImpl<Mode>((AllModes*)0);
348
350template<typename Group, typename AllGroups> static constexpr bool GroupBelongsTo = belongsToImpl<Group>((AllGroups*)0);
351
352//
353// GroupIdFrom & ModeIdFrom
354//
355
356template<typename Mode, typename AllGroups> static constexpr int groupIdFromImpl()
357{
358 int acc = -1;
359 constexpr uint8_t N = std::tuple_size_v<AllGroups>;
360 unroll<N>([&](auto Idx) {
361 constexpr uint8_t groupId = decltype(Idx)::value;
362 using GroupHere = std::tuple_element_t<groupId, AllGroups>;
363 using AllModesHere = typename GroupHere::AllModesTy;
364 if (acc != -1)
365 return;
366
367 // make GroupIdFrom<Group, AllGroups> return the proper groupId
368 if constexpr (std::is_same_v<Mode, GroupHere>)
369 {
370 acc = groupId;
371
372 // save groupId if Mode was found in Group
373 }
374 else if constexpr (ModeBelongsTo<Mode, AllModesHere>)
375 {
376 acc = groupId;
377 }
378 });
379 return acc;
380}
381
382template<typename Mode, typename AllGroups, int groupId> static constexpr int modeIdFromImpl()
383{
384 if constexpr (groupId < 0)
385 {
386 return -1;
387 }
388 else
389 {
390 using GroupHere = std::tuple_element_t<groupId, AllGroups>;
391 using AllModesHere = typename GroupHere::AllModesTy;
392
393 // early exit for calls to ModeIdFrom<Group, AllGroups, groupId>
394 if (std::is_same_v<Mode, GroupHere>)
395 {
396 return -1;
397 }
398
399 int acc = -1;
400 constexpr uint8_t N = std::tuple_size_v<AllModesHere>;
401 unroll<N>([&](auto Idx) {
402 constexpr uint8_t modeId = decltype(Idx)::value;
403 using ModeHere = std::tuple_element_t<modeId, AllModesHere>;
404 if (acc != -1)
405 return;
406
407 // save modeId if Mode found at that position in Group
408 if constexpr (std::is_same_v<Mode, ModeHere>)
409 {
410 acc = modeId;
411 }
412 });
413
414 return acc;
415 }
416}
417
419template<typename Mode, typename AllGroups> static constexpr int GroupIdFrom = groupIdFromImpl<Mode, AllGroups>();
420
422template<typename Mode, typename AllGroups, int GroupId = GroupIdFrom<Mode, AllGroups>>
423static constexpr int ModeIdFrom = modeIdFromImpl<Mode, AllGroups, GroupId>();
424
425//
426// ModeExists
427//
428
429template<typename Mode, typename AllGroups> static constexpr bool testIfModeExistsImpl()
430{
431 constexpr uint8_t NbGroups {std::tuple_size_v<AllGroups>};
432
433 bool acc = false;
434 unroll<NbGroups>([&](auto Idx) {
435 using GroupHere = std::tuple_element_t<Idx, AllGroups>;
436 using AllModes = typename GroupHere::AllModesTy;
437 acc |= ModeBelongsTo<Mode, AllModes>;
438 });
439
440 return acc;
441}
442
444template<typename Mode, typename AllGroups> static constexpr bool ModeExists = testIfModeExistsImpl<Mode, AllGroups>();
445
447template<typename Ctx> using LocalStoreOf = typename std::remove_cv_t<std::remove_reference_t<Ctx>>::LocalStore;
448
453template<size_t NBytes, class To, class From>
454static inline std::enable_if_t<NBytes <= sizeof(To) && NBytes <= sizeof(From) && std::is_trivially_copyable_v<To> &&
455 std::is_trivially_copyable_v<From>,
456 void>
457 LMBD_INLINE bit_cast(To& dst, const From& src) noexcept
458{
459 std::memcpy(&dst, &src, NBytes);
460}
461
462} // namespace details
463
464} // namespace lampda::modes
465
466#endif
Contains shorthand macro definitions.
Basic interface types to implement custom user modes.
Contains basic interface types to implement custom user modes.
Definition: control_fixed_modes.hpp:12
static constexpr uint32_t storeId
Store identifier for persistent storage (optional)
Definition: mode_type.hpp:265