LeviLamina
Loading...
Searching...
No Matches
Meta.h
1#pragma once
2
3#include <cstddef>
4#include <utility>
5
6#include "ll/api/base/CompilerPredefine.h"
7#include "ll/api/base/Concepts.h"
8#include "ll/api/base/Macro.h"
9#include "ll/api/base/StdInt.h"
10#include "ll/api/base/TypeTraits.h"
11
12namespace ll::meta {
13namespace detail {
14template <size_t N, int Strategy>
16
17template <size_t N>
18struct VisitStrategy<N, -1> {
19 // Fallback strategy for visitations with too many total states for the following "switch" strategies.
20 template <class T, class... Ts>
21 static constexpr std::array<std::decay_t<T>, sizeof...(Ts) + 1> makeVisitorArray(T&& t, Ts&&... ts) {
22 return {
23 {std::forward<T>(t), std::forward<Ts>(ts)...}
24 };
25 }
26 template <class Ret, class Fn, size_t I, class... Args>
27 static constexpr Ret invokeVisitor(Fn&& fn, Args&&... args) {
28 return std::forward<Fn>(fn).template operator()<I>(std::forward<Args>(args)...);
29 }
30
31 template <class Ret, class Fn, class... Args, size_t... Ns>
32 static constexpr decltype(auto) makeCallers(std::integer_sequence<size_t, Ns...>) {
33 return makeVisitorArray(&invokeVisitor<Ret, Fn, Ns, Args...>...);
34 }
35 template <class Ret, class Fn, class... Args>
36 static constexpr decltype(auto) callers = makeCallers<Ret, Fn, Args...>(std::make_index_sequence<N>());
37
38 template <class Ret, class Fn, class... Args>
39 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) { // dispatch a visitation with many potential states
40 static_assert(N > 256);
41 return callers<Ret, Fn, Args...>[idx](std::forward<Fn>(fn), std::forward<Args>(args)...);
42 }
43};
44
45template <size_t N>
46struct VisitStrategy<N, 0> {
47 template <class Ret, class Fn, class... Args>
48 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) { // dispatch a visitation with 4^0 potential states
49 return std::forward<Fn>(fn).template operator()<0>(std::forward<Args>(args)...);
50 }
51};
52
53#ifndef LL_VISIT_CASE
54#define LL_VISIT_CASE(n) \
55 case (n): \
56 if constexpr ((n) < N) { \
57 return std::forward<Fn>(fn).template operator()<(n)>(std::forward<Args>(args)...); \
58 } \
59 LL_UNREACHABLE; \
60 [[fallthrough]]
61
62#define LL_VISIT_STAMP(stamper, n) \
63 static_assert(N > (n) / 4 && N <= (n)); \
64 switch (idx) { \
65 stamper(0, LL_VISIT_CASE); \
66 default: \
67 LL_UNREACHABLE; \
68 }
69
70#define LL_STAMP4(n, x) \
71 x(n); \
72 x(n + 1); \
73 x(n + 2); \
74 x(n + 3)
75#define LL_STAMP16(n, x) \
76 LL_STAMP4(n, x); \
77 LL_STAMP4(n + 4, x); \
78 LL_STAMP4(n + 8, x); \
79 LL_STAMP4(n + 12, x)
80#define LL_STAMP64(n, x) \
81 LL_STAMP16(n, x); \
82 LL_STAMP16(n + 16, x); \
83 LL_STAMP16(n + 32, x); \
84 LL_STAMP16(n + 48, x)
85#define LL_STAMP256(n, x) \
86 LL_STAMP64(n, x); \
87 LL_STAMP64(n + 64, x); \
88 LL_STAMP64(n + 128, x); \
89 LL_STAMP64(n + 192, x)
90
91#define LL_STAMP(n, x) x(LL_STAMP##n, n)
92
93template <size_t N>
94struct VisitStrategy<N, 1> {
95 template <class Ret, class Fn, class... Args>
96 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) {
97 // dispatch a visitation with 4^1 potential states
98 LL_STAMP(4, LL_VISIT_STAMP);
99 }
100};
101
102template <size_t N>
103struct VisitStrategy<N, 2> {
104 template <class Ret, class Fn, class... Args>
105 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) {
106 // dispatch a visitation with 4^2 potential states
107 LL_STAMP(16, LL_VISIT_STAMP);
108 }
109};
110
111template <size_t N>
112struct VisitStrategy<N, 3> {
113 template <class Ret, class Fn, class... Args>
114 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) {
115 // dispatch a visitation with 4^3 potential states
116 LL_STAMP(64, LL_VISIT_STAMP);
117 }
118};
119
120template <size_t N>
121struct VisitStrategy<N, 4> {
122 template <class Ret, class Fn, class... Args>
123 static constexpr Ret impl(size_t idx, Fn&& fn, Args&&... args) {
124 // dispatch a visitation with 4^4 potential states
125 LL_STAMP(256, LL_VISIT_STAMP);
126 }
127};
128
129#undef LL_VISIT_CASE
130#undef LL_VISIT_STAMP
131#undef LL_STAMP
132#undef LL_STAMP256
133#undef LL_STAMP64
134#undef LL_STAMP16
135#undef LL_STAMP4
136#endif
137
138template <class Fn, class... Args>
139using VisitIndexResultT = decltype((std::declval<Fn>().template operator()<0>(std::declval<Args>()...)));
140
141template <class Group, auto Id>
143 using tag = TypeCounter;
144
145 struct GenerateTag {
146 friend consteval auto isDefined(tag) { return true; }
147 };
148 friend consteval auto isDefined(tag);
149
150 template <class Tag = tag, auto = isDefined(Tag{})>
151 static consteval auto exists(auto) {
152 return true;
153 }
154
155 static consteval auto exists(...) { return GenerateTag(), false; }
156};
157} // namespace detail
158
159template <size_t N>
160struct PriorityTag : PriorityTag<N - 1> {};
161template <>
162struct PriorityTag<0> {};
163
164template <class... Ts, class Fn>
165constexpr void unrollType(Fn&& fn) {
166 [&]<size_t... I>(std::index_sequence<I...>) {
167 (void(std::forward<Fn>(fn).template operator()<Ts, I>()), ...);
168 }(std::index_sequence_for<Ts...>());
169}
170
171template <size_t N, class Fn>
172constexpr void unroll(Fn&& fn) {
173 [&]<size_t... I>(std::index_sequence<I...>) {
174 (void(std::forward<Fn>(fn).template operator()<I>()), ...);
175 }(std::make_index_sequence<N>());
176}
177
178template <size_t N, class Fn, class... Args>
179constexpr decltype(auto) visitIndex(size_t index, Fn&& fn, Args&&... args) {
180 constexpr int strategy = N == 1 ? 0 : N <= 4 ? 1 : N <= 16 ? 2 : N <= 64 ? 3 : N <= 256 ? 4 : -1;
181 using Strategy = typename detail::VisitStrategy<N, strategy>;
182 return (Strategy::template impl<detail::VisitIndexResultT<Fn, Args...>>(
183 index,
184 std::forward<Fn>(fn),
185 std::forward<Args>(args)...
186 ));
187}
188
189template <class Ret, size_t N, class Fn, class... Args>
190constexpr Ret visitIndex(size_t index, Fn&& fn, Args&&... args) {
191 constexpr int strategy = N == 1 ? 0 : N <= 4 ? 1 : N <= 16 ? 2 : N <= 64 ? 3 : N <= 256 ? 4 : -1;
192 using Strategy = typename detail::VisitStrategy<N, strategy>;
193 return Strategy::template impl<Ret>(index, std::forward<Fn>(fn), std::forward<Args>(args)...);
194}
195
196template <class... Ts>
197class TypeList {
198public:
199 template <class T>
200 static constexpr bool contains = (std::is_same_v<T, Ts> || ...);
201
202 template <template <class> class T>
203 static constexpr bool all = (T<Ts>::value && ...);
204
205 template <template <class> class T>
206 static constexpr bool any = (T<Ts>::value || ...);
207
208 static constexpr size_t size = sizeof...(Ts);
209
210 template <template <class> class W>
211 using wrap = TypeList<W<Ts>...>;
212
213 template <template <class> class M>
215
216 template <class T>
217 using push_back = TypeList<Ts..., T>;
218
219 template <class T>
220 using push_front = TypeList<T, Ts...>;
221
222 template <size_t N>
223 using get = traits::get_type_t<N + 1, void, Ts...>;
224
225 template <template <class...> class U>
226 using to = U<Ts...>;
227
228 template <class Fn>
229 static void constexpr forEach(Fn&& func) {
230 unrollType<Ts...>(func);
231 }
232 template <class T>
233 static constexpr size_t index = traits::index_of<T, Ts...>::value;
234};
235
236template <class Group, class T, auto Id = int64{}>
237[[maybe_unused]] consteval auto uniqueId() {
238 if constexpr (detail::TypeCounter<Group, Id>::exists(Id)) {
239 return uniqueId<Group, T, Id + 1>();
240 } else {
241 return Id;
242 }
243}
244
245template <typename FR, typename... PRs>
246 requires std::is_reference_v<FR> && (std::is_reference_v<PRs> && ...)
247class elide {
248 using R = std::invoke_result_t<FR, PRs...>;
249 static_assert(!std::is_reference_v<R>, "F must return by value");
250
251 inline static constexpr bool excepts = noexcept(std::invoke(std::declval<FR>(), std::declval<PRs>()...));
252
253 static constexpr decltype(auto) to_invokable(FR f, PRs... args) noexcept {
254 using F = std::remove_reference_t<FR>;
255 using DF = std::remove_pointer_t<F>;
256 if constexpr (sizeof...(PRs)) {
257 return [&f, &args...]() noexcept(excepts) -> decltype(auto) {
258 return std::invoke(static_cast<FR>(f), static_cast<PRs>(args)...);
259 };
260 } else if constexpr (std::is_function_v<DF>) {
261 return static_cast<DF*>(f);
262 } else if constexpr (std::is_trivial_v<F> && sizeof(F) <= sizeof(void*)) {
263 return static_cast<F>(f);
264 } else {
265 return static_cast<FR>(f);
266 }
267 }
268 using invokable_t = decltype(to_invokable(std::declval<FR>(), std::declval<PRs>()...));
269 invokable_t invokable;
270
271public:
272 template <typename F, typename... Params>
273 constexpr explicit elide(F&& arg, Params&&... args) noexcept
274 : invokable(to_invokable(std::forward<F>(arg), std::forward<Params>(args)...)) {}
275
276 constexpr operator R() noexcept(excepts) {
277 return std::invoke(
278 static_cast<std::conditional_t<std::is_lvalue_reference_v<FR>, invokable_t&, invokable_t&&>>(invokable)
279 );
280 }
281 constexpr R operator()() noexcept(excepts) { return this->operator R(); }
282
283 constexpr elide() = delete;
284 constexpr elide(elide const&) = delete;
285 constexpr elide(elide&&) = delete;
286 elide& operator=(elide const&) = delete;
287 elide& operator=(elide&&) = delete;
288 elide const volatile* operator&() const volatile = delete;
289 template <typename U>
290 void operator,(U&&) = delete;
291};
292template <typename F, typename... Params>
293elide(F&&, Params&&...) -> elide<F&&, Params&&...>;
294
295} // namespace ll::meta
Definition Tag.h:39
Definition Meta.h:197
Definition Meta.h:247
Definition Meta.h:160
Definition Meta.h:142
Definition TypeTraits.h:37