825 lines
26 KiB
C++
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
|