engine/dep/include/ctti/detail/meta.hpp
2024-12-02 18:48:18 -06:00

825 lines
26 KiB
C++

#ifndef CTTI_UTILITY_META_H
#define CTTI_UTILITY_META_H
#include <type_traits>
#include <cstddef>
#include <array>
namespace ctti
{
namespace meta
{
template<typename T>
using decay_t = typename std::decay<T>::type;
template<typename... Bs>
struct assert;
template<typename B, typename... Bs>
struct assert<B, Bs...> : assert<Bs...>
{
static_assert(B::value, "Assertion failed");
};
template<>
struct assert<> {};
template<typename T>
using void_t = typename std::conditional<sizeof(T*) >= 0, void, T>::type;
template<typename T>
struct identity
{
using type = T;
};
template<typename Metafunction>
using type_t = typename Metafunction::type;
template<bool Cond, typename T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template<typename MetafunctionClass, typename... Args>
using apply_t = type_t<typename MetafunctionClass::template apply<Args...>>;
template<typename MetafunctionClass, typename Seq>
struct sequence_apply;
template<typename MetafunctionClass,
template<typename...> class Seq, typename... Ts>
struct sequence_apply<MetafunctionClass, Seq<Ts...>>
{
using type = apply_t<MetafunctionClass, Ts...>;
};
template<typename MetafunctionClass, typename Seq>
using sequence_apply_t = type_t<sequence_apply<MetafunctionClass, Seq>>;
template<std::uint8_t I>
using uint8_t = std::integral_constant<std::uint8_t, I>;
template<std::uint16_t I>
using uint16_t = std::integral_constant<std::uint16_t, I>;
template<std::uint32_t I>
using uint32_t = std::integral_constant<std::uint32_t, I>;
template<std::uint64_t I>
using uint64_t = std::integral_constant<std::uint64_t, I>;
template<std::int8_t I>
using int8_t = std::integral_constant<std::int8_t, I>;
template<std::int16_t I>
using int16_t = std::integral_constant<std::int16_t, I>;
template<std::int32_t I>
using int32_t = std::integral_constant<std::int32_t, I>;
template<std::int64_t I>
using int64_t = std::integral_constant<std::int64_t, I>;
template<std::size_t I>
using size_t = std::integral_constant<std::size_t, I>;
template<bool B>
using bool_ = std::integral_constant<bool, B>;
using true_ = bool_<true>;
using false_ = bool_<false>;
template<char C>
using char_ = std::integral_constant<char, C>;
template<typename T, typename = void>
struct is_integral : false_ {};
template<typename T>
struct is_integral<T, void_t<decltype(T::value)>> :
true_
{};
template<typename T, typename = assert<is_integral<T>>>
constexpr decltype(T::value) value()
{
return T::value;
}
template<template<typename...> class Function>
struct defer
{
template<typename... Args>
struct apply
{
template<typename Instance, bool = is_integral<Instance>::value>
struct result
{
using type = Instance;
};
template<typename Instance>
struct result<Instance, false>
{
using type = type_t<Instance>;
};
using type = type_t<result<Function<Args...>>>;
};
};
struct and_
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<Lhs::value && Rhs::value>;
};
};
template<typename Lhs, typename Rhs>
using and_t = apply_t<and_, Lhs, Rhs>;
struct or_
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<Lhs::value || Rhs::value>;
};
};
template<typename Lhs, typename Rhs>
using or_t = apply_t<or_, Lhs, Rhs>;
struct add_
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = std::integral_constant<decltype(Lhs::value + Rhs::value), Lhs::value + Rhs::value>;
};
};
struct div_
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = std::integral_constant<decltype(Lhs::value / Rhs::value), Lhs::value / Rhs::value>;
};
};
template<typename Lhs, typename Rhs>
using add_t = apply_t<add_, Lhs, Rhs>;
template<typename Lhs, typename Rhs>
using div_t = apply_t<div_, Lhs, Rhs>;
struct greater
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<(Lhs::value > Rhs::value)>;
};
};
struct greater_or_equal
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<(Lhs::value >= Rhs::value)>;
};
};
struct less
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<(Lhs::value < Rhs::value)>;
};
};
struct less_or_equal
{
template<typename Lhs, typename Rhs>
struct apply : assert<
is_integral<Lhs>,
is_integral<Rhs>
>
{
using type = bool_<(Lhs::value <= Rhs::value)>;
};
};
template<typename... Ts>
struct list
{
static constexpr std::size_t size = sizeof...(Ts);
};
template<typename... Ts>
constexpr std::size_t list<Ts...>::size;
template<typename List>
struct list_size;
template<template<typename...> class Sequence, typename... Ts>
struct list_size<Sequence<Ts...>> : public size_t<sizeof...(Ts)>
{};
template<char... Chars>
using string = list<std::integral_constant<char, Chars>...>;
template<typename Seq>
struct functor
{
static_assert(sizeof(Seq) != sizeof(Seq), "Type is not a sequence");
};
template<template<typename...> class Seq, typename... Ts>
struct functor<Seq<Ts...>>
{
template<typename... Us>
struct apply
{
using type = Seq<Us...>;
};
template<template<typename...> class Seq2, typename... Us>
struct apply<Seq2<Us...>>
{
using type = Seq<Us...>;
};
};
template<typename Seq, typename... Ts>
using apply_functor = apply_t<functor<Seq>, Ts...>;
template<typename Seq, typename... Ts>
using functor_t = apply_functor<Seq, Ts...>;
template<typename Lhs, typename Rhs>
struct cat;
template<template<typename...> class Seq,
typename... Lhs, typename... Rhs>
struct cat<Seq<Lhs...>, Seq<Rhs...>>
{
using type = Seq<Lhs..., Rhs...>;
};
template<typename Lhs, typename Rhs>
using cat_t = type_t<cat<Lhs, Rhs>>;
template<std::size_t I>
using index_t = std::integral_constant<std::size_t, I>;
template<typename T, T... Values>
using integer_sequence = list<std::integral_constant<T, Values>...>;
template<std::size_t... Is>
using index_sequence = list<index_t<Is>...>;
namespace detail
{
template<typename Left, std::size_t Index, typename Right>
struct split;
template<template<typename...> class Seq, std::size_t Index,
typename... Left, typename Head, typename... Tail>
struct split<Seq<Left...>, Index, Seq<Head, Tail...>>
{
using next = split<Seq<Left..., Head>, Index - 1, Seq<Tail...>>;
using before = typename next::before;
using left = typename next::left;
using head = typename next::head;
using right = typename next::right;
using after = typename next::after;
};
template<template<typename...> class Seq,
typename... Left, typename Head, typename... Tail>
struct split<Seq<Left...>, 0, Seq<Head, Tail...>>
{
using before = Seq<Left...>;
using left = Seq<Left..., Head>;
using head = Head;
using right = Seq<Head, Tail...>;
using after = Seq<Tail...>;
};
template<template<typename...> class Seq,
typename Head>
struct split<Seq<Head>, 0, Seq<>>
{
using before = Seq<>;
using left = Seq<Head>;
using head = Head;
using right = Seq<Head>;
using after = Seq<>;
};
}
template<std::size_t Index, typename... Ts>
using pack_split = detail::split<list<>, Index, list<Ts...>>;
template<std::size_t Index, typename... Ts>
using pack_split_left_t = typename pack_split<Index, Ts...>::left;
template<std::size_t Index, typename... Ts>
using pack_get_t = typename pack_split<Index, Ts...>::head;
template<std::size_t Index, typename... Ts>
using pack_split_right_t = typename pack_split<Index, Ts...>::right;
template<std::size_t Index, typename... Ts>
using pack_split_before_t = typename pack_split<Index, Ts...>::before;
template<std::size_t Index, typename... Ts>
using pack_split_after_t = typename pack_split<Index, Ts...>::after;
template<typename... Ts>
using pack_head_t = pack_get_t<0, Ts...>;
template<typename... Ts>
using pack_tail_t = pack_split_after_t<0, Ts...>;
template<std::size_t Index, typename Seq>
struct split;
template<std::size_t Index, template<typename...> class Seq, typename... Ts>
struct split<Index, Seq<Ts...>>
{
using splitter = detail::split<Seq<>, Index, Seq<Ts...>>;
using before = typename splitter::before;
using left = typename splitter::left;
using head = typename splitter::head;
using right = typename splitter::right;
using after = typename splitter::after;
};
template<std::size_t Index, typename Seq>
using split_left_t = typename split<Index, Seq>::left;
template<std::size_t Index, typename Seq>
using get_t = typename split<Index, Seq>::head;
template<std::size_t Index, typename Seq>
using split_right_t = typename split<Index, Seq>::right;
template<std::size_t Index, typename Seq>
using split_before_t = typename split<Index, Seq>::before;
template<std::size_t Index, typename Seq>
using split_after_t = typename split<Index, Seq>::after;
template<typename Seq>
using head_t = get_t<0, Seq>;
template<typename Seq>
using tail_t = split_after_t<0, Seq>;
template<typename T, typename... Ts>
using pack_prepend_t = list<T, Ts...>;
template<typename T, typename... Ts>
using pack_append_t = list<Ts..., T>;
template<typename T, std::size_t Index, typename... Ts>
using pack_insert_t = cat_t<pack_append_t<pack_split_left_t<Index, Ts...>, T>, pack_split_right_t<Index, Ts...>>;
template<typename T, std::size_t Index, typename... Ts>
using pack_remove_t = cat_t<pack_split_before_t<Index, Ts...>, pack_split_after_t<Index, Ts...>>;
template<typename T, typename Seq>
struct prepend;
template<typename T, template<typename...> class Seq, typename... Ts>
struct prepend<T, Seq<Ts...>>
{
using type = Seq<T, Ts...>;
};
template<typename T, typename Seq>
struct append;
template<typename T, template<typename...> class Seq, typename... Ts>
struct append<T, Seq<Ts...>>
{
using type = Seq<Ts..., T>;
};
template<typename T, typename Seq>
using prepend_t = type_t<prepend<T, Seq>>;
template<typename T, typename Seq>
using append_t = type_t<append<Seq, T>>;
template<typename T, std::size_t Index, typename Seq>
using insert_t = cat_t<append_t<split_left_t<Index, Seq>, T>, split_right_t<Index, Seq>>;
template<typename T, std::size_t Index, typename Seq>
using remove_t = cat_t<split_before_t<Index, Seq>, split_after_t<Index, Seq>>;
namespace detail
{
template<typename Result, typename Lhs, typename Rhs, typename Compare>
struct merge;
template<template<typename...> class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename RhsHead, typename... RhsTail, typename Compare>
struct merge<Sequence<Ts...>, Sequence<LhsHead, LhsTail...>, Sequence<RhsHead, RhsTail...>, Compare>
{
using next_result = typename std::conditional<
apply_t<Compare, LhsHead, RhsHead>::value,
Sequence<Ts..., LhsHead>,
Sequence<Ts..., RhsHead>
>::type;
using next_lhs = typename std::conditional<
apply_t<Compare, LhsHead, RhsHead>::value,
Sequence<LhsTail...>,
Sequence<LhsHead, LhsTail...>
>::type;
using next_rhs = typename std::conditional<
apply_t<Compare, LhsHead, RhsHead>::value,
Sequence<RhsHead, RhsTail...>,
Sequence<RhsTail...>
>::type;
using type = type_t<
merge<
next_result,
next_lhs,
next_rhs,
Compare
>
>;
};
template<template<typename...> class Sequence, typename... Ts, typename LhsHead, typename... LhsTail, typename Compare>
struct merge<Sequence<Ts...>, Sequence<LhsHead, LhsTail...>, Sequence<>, Compare>
{
using type = Sequence<Ts..., LhsHead, LhsTail...>;
};
template<template<typename...> class Sequence, typename... Ts, typename RhsHead, typename... RhsTail, typename Compare>
struct merge<Sequence<Ts...>, Sequence<>, Sequence<RhsHead, RhsTail...>, Compare>
{
using type = Sequence<Ts..., RhsHead, RhsTail...>;
};
template<template<typename...> class Sequence, typename... Ts, typename Compare>
struct merge<Sequence<Ts...>, Sequence<>, Sequence<>, Compare>
{
using type = Sequence<Ts...>;
};
}
template<typename Lhs, typename Rhs, typename Compare = less>
using merge = detail::merge<functor_t<Lhs>, Lhs, Rhs, Compare>;
template<typename Lhs, typename Rhs, typename Compare = less>
using merge_t = type_t<merge<Lhs, Rhs, Compare>>;
namespace detail
{
namespace mergesort
{
template<typename List, typename Compare>
struct mergesort
{
using left = split_left_t< div_t<list_size<List>, int32_t<2>>::value, List>;
using right = split_after_t<div_t<list_size<List>, int32_t<2>>::value, List>;
using left_sorted = type_t<mergesort<left, Compare>>;
using right_sorted = type_t<mergesort<right, Compare>>;
using type = merge_t<left_sorted, right_sorted, Compare>;
};
template<template<typename...> class Sequence, typename Compare>
struct mergesort<Sequence<>, Compare>
{
using type = Sequence<>;
};
template<template<typename...> class Sequence, typename T, typename Compare>
struct mergesort<Sequence<T>, Compare>
{
using type = Sequence<T>;
};
template<template<typename...> class Sequence, typename T, typename U, typename Compare>
struct mergesort<Sequence<T, U>, Compare>
{
template<typename First, typename Second, bool FirstWins = apply_t<Compare, First, Second>::value>
struct apply
{
using type = Sequence<First, Second>;
};
template<typename First, typename Second>
struct apply<First, Second, false>
{
using type = Sequence<Second, First>;
};
using type = type_t<apply<T, U>>;
};
}
}
template<typename List, typename Compare = less>
using sort = detail::mergesort::mergesort<List, Compare>;
template<typename List, typename Compare = less>
using sort_t = type_t<sort<List, Compare>>;
template<typename Key, typename Value>
struct pair
{
using key = Key;
using value = Value;
};
template<typename Pair>
using key_t = typename Pair::key;
template<typename Pair>
using value_t = typename Pair::value;
template<typename... Ts>
struct inherit : Ts... {};
template<typename... Ts>
struct inherit<list<Ts...>> : Ts... {};
namespace detail
{
template<typename Ts>
struct aggregate;
template<template<typename...> class Seq, typename T, typename... Ts>
struct aggregate<Seq<T, Ts...>> : public
aggregate<Seq<Ts...>>
{
aggregate() = delete;
aggregate(const aggregate&) = delete;
aggregate(aggregate&&) = delete;
aggregate& operator=(const aggregate&) = delete;
aggregate& operator=(aggregate&&) = delete;
T member;
};
template<template<typename...> class Seq>
struct aggregate<Seq<>>
{
aggregate() = delete;
aggregate(const aggregate&) = delete;
aggregate(aggregate&&) = delete;
aggregate& operator=(const aggregate&) = delete;
aggregate& operator=(aggregate&&) = delete;
};
}
template<typename... Ts>
using aggregate = ::ctti::meta::detail::aggregate<::ctti::meta::list<Ts...>>;
template<typename...>
struct map;
template<typename... Keys, typename... Values>
struct map<pair<Keys, Values>...>
{
using keys = list<Keys...>;
using values = list<Values...>;
using pairs = list<pair<Keys, Values>...>;
struct key_not_found {};
template<typename Key>
using at_key = type_t<decltype(lookup((inherit<pairs>*)nullptr))>;
private:
template<typename Key, typename Value>
static identity<Value> lookup(pair<Key, Value>*);
template<typename Key>
static identity<key_not_found> lookup(...);
};
template<typename Map>
using keys_t = typename Map::keys;
template<typename Map>
using values_t = typename Map::values;
template<typename Map>
using pairs_t = typename Map::pairs;
template<typename Map, typename Key>
using at_key = typename Map::template at_key<Key>;
template<typename Function, typename... Ts>
struct pack_fmap
{
using type = list<apply_t<Function, Ts>...>;
};
template<typename Function, typename List>
struct fmap;
template<typename Function, template<typename...> class Seq, typename... Ts>
struct fmap<Function, Seq<Ts...>>
{
using type = Seq<apply_t<Function, Ts>...>;
};
namespace detail
{
template<typename Predicate, typename FilteredSeq, typename Seq>
struct filter;
template<typename Predicate,
template<typename...> class Seq, typename... Filtered, typename Head, typename... Tail>
struct filter<Predicate, Seq<Filtered...>, Seq<Head, Tail...>>
{
template<typename _Head = Head, bool = value<apply_t<Predicate, _Head>>()>
struct next
{
using type = Seq<Filtered..., Head>;
};
template<typename _Head>
struct next<_Head, false>
{
using type = Seq<Filtered...>;
};
using type = type_t<filter<Predicate, type_t<next<>>, Seq<Tail...>>>;
};
template<typename Predicate,
template<typename...> class Seq, typename... Filtered>
struct filter<Predicate, Seq<Filtered...>, Seq<>>
{
using type = Seq<Filtered...>;
};
}
template<typename Function, typename Seed, typename Seq>
struct foldl;
template<typename Function, typename Seed,
template<typename...> class Seq, typename Head, typename... Tail>
struct foldl<Function, Seed, Seq<Head, Tail...>>
{
using type = type_t<
foldl<Function,
apply_t<Function, Seed, Head>,
Seq<Tail...>
>
>;
};
template<typename Function, typename Seed,
template<typename...> class Seq>
struct foldl<Function, Seed, Seq<>>
{
using type = Seed;
};
template<typename Function, typename Seed, typename Seq>
struct foldr;
template<typename Function, typename Seed,
template<typename...> class Seq, typename Head, typename... Tail>
struct foldr<Function, Seed, Seq<Head, Tail...>>
{
using type = apply_t<
Function, Head,
type_t<foldr<Function, Seed, Seq<Tail...>>>
>;
};
template<typename Function, typename Seed,
template<typename...> class Seq>
struct foldr<Function, Seed, Seq<>>
{
using type = Seed;
};
template<typename Function, typename... Ts>
using pack_fmap_t = type_t<pack_fmap<Function, Ts...>>;
template<typename Function, typename Seq>
using fmap_t = type_t<fmap<Function, Seq>>;
template<typename Function, typename Seed, typename... Seq>
using pack_foldl = foldl<Function, Seed, list<Seq...>>;
template<typename Function, typename Seed, typename... Seq>
using pack_foldl_t = type_t<pack_foldl<Function, Seed, Seq...>>;
template<typename Function, typename Seed, typename Seq>
using foldl_t = type_t<foldl<Function, Seed, Seq>>;
template<typename Function, typename Seed, typename... Seq>
using pack_foldr = foldr<Function, Seed, list<Seq...>>;
template<typename Function, typename Seed, typename... Seq>
using pack_foldr_t = type_t<pack_foldr<Function, Seed, Seq...>>;
template<typename Function, typename Seed, typename Seq>
using foldr_t = type_t<foldr<Function, Seed, Seq>>;
template<typename Predicate, typename Seq>
using filter = detail::filter<Predicate, apply_functor<Seq>, Seq>;
template<typename Predicate, typename Seq>
using filter_t = type_t<filter<Predicate, Seq>>;
template<typename Predicate, typename... Seq>
using pack_filter = detail::filter<Predicate, list<>, list<Seq...>>;
template<typename Predicate, typename... Seq>
using pack_filter_t = type_t<pack_filter<Predicate, Seq...>>;
template<typename Bs>
using any_of = foldl<or_, false_, Bs>;
template<typename Bs>
using any_of_t = foldl_t<or_, false_, Bs>;
template<typename... Bs>
using pack_any_of = pack_foldl<or_, false_, Bs...>;
template<typename... Bs>
using pack_any_of_t = pack_foldl_t<or_, false_, Bs...>;
template<typename Bs>
using any_of = foldl<or_, false_, Bs>;
template<typename Bs>
using any_of_t = foldl_t<or_, false_, Bs>;
template<typename... Bs>
using pack_any_of = pack_foldl<or_, false_, Bs...>;
template<typename... Bs>
using pack_any_of_t = pack_foldl_t<or_, false_, Bs...>;
template<typename... Seqs>
using join = foldl<defer<cat>, apply_functor<pack_get_t<0, Seqs...>>, apply_functor<pack_get_t<0, Seqs...>, Seqs...>>;
template<typename... Seqs>
using join_t = type_t<join<Seqs...>>;
namespace detail
{
template<template<typename...> class Seq, std::size_t N>
struct make_index_sequence
{
static constexpr std::size_t n = (N % 2) ? ((N - 1) / 2) : (N / 2);
static constexpr std::size_t m = N - n;
struct adder
{
template<typename T>
struct apply
{
using type = apply_t<add_, size_t<n>, T>;
};
};
using type = cat_t<
type_t<make_index_sequence<Seq, n>>,
fmap_t<adder, type_t<make_index_sequence<Seq, m>>>
>;
};
template<template<typename...> class Seq>
struct make_index_sequence<Seq, 1>
{
using type = Seq<size_t<0>>;
};
template<template<typename...> class Seq>
struct make_index_sequence<Seq, 0>
{
using type = Seq<>;
};
}
template<std::size_t N, template<typename...> class Seq = list>
using make_index_sequence = type_t<detail::make_index_sequence<Seq, N>>;
template<typename... Ts>
using make_index_sequence_for = make_index_sequence<sizeof...(Ts)>;
template<typename Seq>
struct to_index_sequence;
template<template<typename...> class Seq, typename... Ts>
struct to_index_sequence<Seq<Ts...>>
{
using type = make_index_sequence<sizeof...(Ts), Seq>;
};
template<typename Seq>
using to_index_sequence_t = type_t<to_index_sequence<Seq>>;
template<typename Seq>
using make_index_sequence_from_sequence = ctti::meta::functor_t<ctti::meta::list<>, ctti::meta::to_index_sequence_t<Seq>>;
namespace detail
{
template<typename Function, typename... Ts, std::size_t... Indices>
void foreach(ctti::meta::list<Ts...>, ctti::meta::index_sequence<Indices...>, Function function)
{
(void)function;
[](...){}(std::array<int, sizeof...(Ts) + 1>{{(function(ctti::meta::identity<Ts>(), ctti::meta::size_t<Indices>()), 0)..., 0}});
}
}
template<typename Sequence, typename Function>
void foreach(Function function)
{
ctti::meta::detail::foreach(ctti::meta::apply_functor<ctti::meta::list<>, Sequence>(), ctti::meta::make_index_sequence_from_sequence<Sequence>(), function);
}
}
}
#endif // CTTI_UTILITY_META_H