Skip to content
LeviMC
English
AutoLightDark
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 <bool&>
166
167template <class... Ts, class Fn>
168constexpr void unrollType(Fn&& fn) {
169 [&]<size_t... I>(std::index_sequence<I...>) {
170 (void(std::forward<Fn>(fn).template operator()<Ts, I>()), ...);
171 }(std::index_sequence_for<Ts...>());
172}
173
174template <size_t N, class Fn>
175constexpr void unroll(Fn&& fn) {
176 [&]<size_t... I>(std::index_sequence<I...>) {
177 (void(std::forward<Fn>(fn).template operator()<I>()), ...);
178 }(std::make_index_sequence<N>());
179}
180
181template <size_t N, class Fn, class... Args>
182constexpr decltype(auto) visitIndex(size_t index, Fn&& fn, Args&&... args) {
183 constexpr int strategy = N == 1 ? 0 : N <= 4 ? 1 : N <= 16 ? 2 : N <= 64 ? 3 : N <= 256 ? 4 : -1;
184 using Strategy = typename detail::VisitStrategy<N, strategy>;
185 return (Strategy::template impl<detail::VisitIndexResultT<Fn, Args...>>(
186 index,
187 std::forward<Fn>(fn),
188 std::forward<Args>(args)...
189 ));
190}
191
192template <class Ret, size_t N, class Fn, class... Args>
193constexpr Ret visitIndex(size_t index, Fn&& fn, Args&&... args) {
194 constexpr int strategy = N == 1 ? 0 : N <= 4 ? 1 : N <= 16 ? 2 : N <= 64 ? 3 : N <= 256 ? 4 : -1;
195 using Strategy = typename detail::VisitStrategy<N, strategy>;
196 return Strategy::template impl<Ret>(index, std::forward<Fn>(fn), std::forward<Args>(args)...);
197}
198
199template <class... Ts>
200class TypeList {
201public:
202 template <class T>
203 static constexpr bool contains = (std::is_same_v<T, Ts> || ...);
204
205 template <template <class> class T>
206 static constexpr bool all = (T<Ts>::value && ...);
207
208 template <template <class> class T>
209 static constexpr bool any = (T<Ts>::value || ...);
210
211 static constexpr size_t size = sizeof...(Ts);
212
213 template <template <class> class W>
214 using wrap = TypeList<W<Ts>...>;
215
216 template <template <class> class M>
217 using map = TypeList<typename M<Ts>::type...>;
218
219 template <class T>
220 using push_back = TypeList<Ts..., T>;
221
222 template <class T>
223 using push_front = TypeList<T, Ts...>;
224
225 template <size_t N>
226 using get = traits::get_type_t<N + 1, void, Ts...>;
227
228 template <template <class...> class U>
229 using to = U<Ts...>;
230
231 template <class Fn>
232 static void constexpr forEach(Fn&& func) {
233 unrollType<Ts...>(func);
234 }
235 template <class T>
236 static constexpr size_t index = traits::index_of<T, Ts...>::value;
237};
238
239template <class Group, class T, auto Id = int64{}>
240[[maybe_unused]] consteval auto uniqueId() {
241 if constexpr (detail::TypeCounter<Group, Id>::exists(Id)) {
242 return uniqueId<Group, T, Id + 1>();
243 } else {
244 return Id;
245 }
246}
247
248template <typename FR, typename... PRs>
249 requires std::is_reference_v<FR> && (std::is_reference_v<PRs> && ...)
250class elide {
251 using R = std::invoke_result_t<FR, PRs...>;
252 static_assert(!std::is_reference_v<R>, "F must return by value");
253
254 inline static constexpr bool excepts = noexcept(std::invoke(std::declval<FR>(), std::declval<PRs>()...));
255
256 static constexpr decltype(auto) to_invokable(FR f, PRs... args) noexcept {
257 using F = std::remove_reference_t<FR>;
258 using DF = std::remove_pointer_t<F>;
259 if constexpr (sizeof...(PRs)) {
260 return [&f, &args...]() noexcept(excepts) -> decltype(auto) {
261 return std::invoke(static_cast<FR>(f), static_cast<PRs>(args)...);
262 };
263 } else if constexpr (std::is_function_v<DF>) {
264 return static_cast<DF*>(f);
265 } else if constexpr (std::is_trivial_v<F> && sizeof(F) <= sizeof(void*)) {
266 return static_cast<F>(f);
267 } else {
268 return static_cast<FR>(f);
269 }
270 }
271 using invokable_t = decltype(to_invokable(std::declval<FR>(), std::declval<PRs>()...));
272 invokable_t invokable;
273
274public:
275 template <typename F, typename... Params>
276 constexpr explicit elide(F&& arg, Params&&... args) noexcept
277 : invokable(to_invokable(std::forward<F>(arg), std::forward<Params>(args)...)) {}
278
279 constexpr operator R() noexcept(excepts) {
280 return std::invoke(
281 static_cast<std::conditional_t<std::is_lvalue_reference_v<FR>, invokable_t&, invokable_t&&>>(invokable)
282 );
283 }
284 constexpr R operator()() noexcept(excepts) { return this->operator R(); }
285
286 constexpr elide() = delete;
287 constexpr elide(elide const&) = delete;
288 constexpr elide(elide&&) = delete;
289 elide& operator=(elide const&) = delete;
290 elide& operator=(elide&&) = delete;
291 elide const volatile* operator&() const volatile = delete;
292 template <typename U>
293 void operator,(U&&) = delete;
294};
295template <typename F, typename... Params>
296elide(F&&, Params&&...) -> elide<F&&, Params&&...>;
297
298} // namespace ll::meta
Definition Tag.h:42
Definition Meta.h:200
Definition Meta.h:250
Definition Meta.h:160
Definition Meta.h:142
Definition TypeTraits.h:40