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"
14template <
size_t N,
int Strategy>
20 template <
class T,
class... Ts>
21 static constexpr std::array<std::decay_t<T>,
sizeof...(Ts) + 1> makeVisitorArray(T&& t, Ts&&... ts) {
23 {std::forward<T>(t), std::forward<Ts>(ts)...}
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)...);
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...>...);
35 template <
class Ret,
class Fn,
class... Args>
36 static constexpr decltype(
auto) callers = makeCallers<Ret, Fn, Args...>(std::make_index_sequence<N>());
38 template <
class Ret,
class Fn,
class... Args>
39 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
40 static_assert(N > 256);
41 return callers<Ret, Fn, Args...>[idx](std::forward<Fn>(fn), std::forward<Args>(args)...);
47 template <
class Ret,
class Fn,
class... Args>
48 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
49 return std::forward<Fn>(fn).template operator()<0>(std::forward<Args>(args)...);
54#define LL_VISIT_CASE(n) \
56 if constexpr ((n) < N) { \
57 return std::forward<Fn>(fn).template operator()<(n)>(std::forward<Args>(args)...); \
62#define LL_VISIT_STAMP(stamper, n) \
63 static_assert(N > (n) / 4 && N <= (n)); \
65 stamper(0, LL_VISIT_CASE); \
70#define LL_STAMP4(n, x) \
75#define LL_STAMP16(n, x) \
77 LL_STAMP4(n + 4, x); \
78 LL_STAMP4(n + 8, x); \
80#define LL_STAMP64(n, x) \
82 LL_STAMP16(n + 16, x); \
83 LL_STAMP16(n + 32, x); \
85#define LL_STAMP256(n, x) \
87 LL_STAMP64(n + 64, x); \
88 LL_STAMP64(n + 128, x); \
89 LL_STAMP64(n + 192, x)
91#define LL_STAMP(n, x) x(LL_STAMP##n, n)
95 template <
class Ret,
class Fn,
class... Args>
96 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
98 LL_STAMP(4, LL_VISIT_STAMP);
104 template <
class Ret,
class Fn,
class... Args>
105 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
107 LL_STAMP(16, LL_VISIT_STAMP);
113 template <
class Ret,
class Fn,
class... Args>
114 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
116 LL_STAMP(64, LL_VISIT_STAMP);
122 template <
class Ret,
class Fn,
class... Args>
123 static constexpr Ret impl(
size_t idx, Fn&& fn, Args&&... args) {
125 LL_STAMP(256, LL_VISIT_STAMP);
138template <
class Fn,
class... Args>
139using VisitIndexResultT =
decltype((std::declval<Fn>().template operator()<0>(std::declval<Args>()...)));
141template <
class Group, auto Id>
146 friend consteval auto isDefined(
tag) {
return true; }
148 friend consteval auto isDefined(
tag);
150 template <
class Tag =
tag,
auto = isDefined(
Tag{})>
151 static consteval auto exists(
auto) {
155 static consteval auto exists(...) {
return GenerateTag(),
false; }
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...>());
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>());
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...>>(
184 std::forward<Fn>(fn),
185 std::forward<Args>(args)...
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)...);
196template <
class... Ts>
200 static constexpr bool contains = (std::is_same_v<T, Ts> || ...);
202 template <
template <
class>
class T>
203 static constexpr bool all = (T<Ts>::value && ...);
205 template <
template <
class>
class T>
206 static constexpr bool any = (T<Ts>::value || ...);
208 static constexpr size_t size =
sizeof...(Ts);
210 template <
template <
class>
class W>
213 template <
template <
class>
class M>
223 using get = traits::get_type_t<N + 1, void, Ts...>;
225 template <
template <
class...>
class U>
229 static void constexpr forEach(Fn&& func) {
230 unrollType<Ts...>(func);
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>();
245template <
typename FR,
typename... PRs>
246 requires std::is_reference_v<FR> && (std::is_reference_v<PRs> && ...)
248 using R = std::invoke_result_t<FR, PRs...>;
249 static_assert(!std::is_reference_v<R>,
"F must return by value");
251 inline static constexpr bool excepts =
noexcept(std::invoke(std::declval<FR>(), std::declval<PRs>()...));
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)...);
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);
265 return static_cast<FR
>(f);
268 using invokable_t =
decltype(to_invokable(std::declval<FR>(), std::declval<PRs>()...));
269 invokable_t invokable;
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)...)) {}
276 constexpr operator R()
noexcept(excepts) {
278 static_cast<std::conditional_t<std::is_lvalue_reference_v<FR>, invokable_t&, invokable_t&&
>>(invokable)
281 constexpr R operator()()
noexcept(excepts) {
return this->
operator R(); }
283 constexpr elide() =
delete;
288 elide const volatile* operator&()
const volatile =
delete;
289 template <
typename U>
290 void operator,(U&&) =
delete;
292template <
typename F,
typename... Params>
293elide(F&&, Params&&...) ->
elide<F&&, Params&&...>;
Definition TypeTraits.h:37