uTL
micro Template library
W:/Work/Software/Libraries/utl/include/utl/meta/typelist.h

A class template that just holds a parameter pack.The idea came from MPL's sequence concept [link1 1] and from N4115 [link2 2]. In addition to N4115's name "packer" we just prefer a name which is object, not a subject. This way the name gives the feeling of a container and smells like Python.

In addition to tuple we lack members, so typelist could serve as an empty base class, and an object of the ultimate type could always be instantiated (even if the parameter typelist contains void or some type that lacks a default constructor).

using l1 = typelist<int, void*, double, void>;
l1 a {};

boost::hana [link3 3] suggests a more powerful scheme were type invariant structures can be used for metaprograming also. This lib does not need (yet) this kind of power (we afraid the responsibility that comes along). So a simple python-like list with some extra vector-like element access functionalities and no iterators is good enough(for now).

[1]: https://www.boost.org/doc/ [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html [3]: https://github.com/boostorg/hana

#ifndef __utl_meta_typelist_h__
#define __utl_meta_typelist_h__
#include <utl/core/impl.h>
namespace utl {
namespace meta {
template <typename... Ts>
struct typelist {
using type = typelist;
static constexpr size_t size() noexcept {
return sizeof...(Ts);
}
static constexpr bool empty() noexcept {
return (sizeof...(Ts) == 0);
}
// ======= times utility =======
private:
template <typename... > struct cat_ { };
template <typename... L1, typename... L2>
struct cat_<typelist<L1...>, typelist<L2...>> {
using type = typelist<L1..., L2...>;
};
template <size_t N, typename ...T>
struct times_ {
//static_assert( N >= 0, "Cannot make typelist of negative length" );
using type = eval<
cat_<
eval<times_<N/2, T...>>,
eval<times_<N - N/2, T...>>
>
>;
};
template <typename ...T>
struct times_<1, T...> {
using type = typelist<T...>;
};
template <typename ...T>
struct times_<0, T...> {
using type = typelist<>;
};
public:
template<size_t N>
using times = eval<
times_<N, Ts...>
>;
};
template <typename List>
using size = size_<List::size()>;
template <typename List>
using empty = bool_<List::empty()>;
template <typename T1, typename T2>
using pair = typelist<T1, T2>;
template <size_t N, typename ...Ts>
using repeat_c = typename typelist<Ts...>::template times<N>;
template <typename N, typename ...Ts>
using repeat = repeat_c<N::type::value, Ts...>;
namespace apply_impl {
template <typename Fn, typename Seq>
struct apply_ { };
template<typename Fn, typename ...List>
struct apply_<Fn, typelist<List...>> {
using type = invoke<Fn, List...>;
};
template <typename Fn, typename T, T... Is>
struct apply_<Fn, integer_sequence<T, Is...>> {
using type = invoke<Fn, integral_<T, Is>...>;
};
}
template <typename Fn, typename Seq>
using apply = apply_impl::apply_<Fn, Seq>;
template <typename Fn, typename Seq>
using apply_t = eval <apply<Fn, Seq>>;
/*
* ========= element access ========
*/
namespace at_impl {
template <typename T> struct _add_pointer { using type = T*; };
template <typename T> using add_pointer = eval < _add_pointer <T> >;
template <typename ...>
struct at_head_ { };
template <typename... voids>
struct at_head_ <typelist<voids...>> {
// successful selection N voids, one T* and the rest
template <typename T> static constexpr T select(voids..., T*, ...);
// selection on error
static constexpr nil_ select (...);
};
template<typename List, index_t N>
struct at_ { };
template<typename... List, index_t N>
struct at_<typelist<List...>, N> {
using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
using type = decltype(
head_::select(static_cast<add_pointer<List>>(nullptr)...) //< pass all as List*...
);
};
}
template <typename List, index_t N>
using at_c = eval<
at_impl::at_<List, N>
>;
template <typename List, typename N>
using at = at_c<List, N::type::value>;
namespace front_impl {
template <typename L>
struct front_ { };
template <typename Head, typename... Tail>
struct front_<typelist<Head, Tail...>> {
using type = Head;
};
}
template <typename List>
using front = eval<
front_impl::front_<List>
>;
namespace back_impl {
template <typename List>
struct back_ { };
template <typename Head, typename... Tail>
struct back_<typelist<Head, Tail...>> {
using type = at_c <
typelist<Head, Tail...>, sizeof...(Tail)
>;
};
}
template <typename List>
using back = eval<
back_impl::back_<List>
>;
/*
* ========= typelist operations =========
*/
namespace cat_impl {
template <typename... Lists>
struct cat_ { };
template <>
struct cat_<> {
using type = typelist<>;
};
template <typename... L1>
struct cat_<typelist<L1...>> {
using type = typelist<L1...>;
};
template <typename... L1, typename... L2>
struct cat_<typelist<L1...>, typelist<L2...>> {
using type = typelist<L1..., L2...>;
};
template <typename... L1, typename... L2, typename... Ln>
struct cat_<typelist<L1...>, typelist<L2...>, Ln...>
: cat_ <typelist<L1..., L2...>, Ln...> { };
}
template <typename... Lists>
using cat = eval<
cat_impl::cat_<Lists...>
>;
namespace fold_impl {
// fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
template<typename, typename, typename>
struct fold_ { }; // ill formed
// recursive call
template<typename Head, typename... Tail,
typename V,
typename Fn>
struct fold_<typelist<Head, Tail...>, V, Fn> {
// recursive call of fold_ by consuming typelist and invoking Fn
using type = eval<
fold_<
typelist<Tail...>,
invoke<Fn, V, Head>,
Fn
>
>;
};
// termination call
template<typename V0, typename Fn>
struct fold_<typelist<>, V0, Fn> {
using type = V0;
};
}
template <typename List, typename V, typename Fn>
using fold = eval<fold_impl::fold_<List, V, Fn>>;
template <typename List, typename V, typename Fn>
using accumulate = fold<List, V, Fn>;
namespace rev_fold_impl {
// rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
template<typename, typename, typename>
struct rev_fold_ { }; // ill formed
// recursive call
template<typename Head, typename... Tail,
typename V,
typename Fn>
struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
// recursive call inside invoke. This way the 2nd argument of Fn
// becoming the recursive "thing", inside Fn<>
using type = invoke <
Fn, Head, eval<
rev_fold_ <
typelist<Tail...>,
V,
Fn
>>
>;
};
// pre-termination call
template<typename Tail, typename V, typename Fn>
struct rev_fold_ <typelist<Tail>, V, Fn> {
using type = invoke<Fn, Tail, V>;
};
// termination call
template<typename V, typename Fn>
struct rev_fold_ <typelist<>, V, Fn> {
using type = V;
};
}
template <typename List, typename V, typename Fn>
using rev_fold = eval<
rev_fold_impl::rev_fold_<List, V, Fn>
>;
template <typename List, typename... Ts>
using push_front = eval<
bind_front<quote<typelist>, Ts...>, List
>
>;
template <typename List, typename... Ts>
using push_back = eval<
bind_back<quote<typelist>, Ts...>, List
>
>;
namespace reverse_impl {
template <typename List, typename V = typelist<>>
struct reverse_ {
using type = fold<List, V, quote<push_front>>;
};
}
template <typename List>
using reverse = eval<
reverse_impl::reverse_<List>
>;
namespace pop_front_impl {
template <typename List>
struct pop_front_ { };
template <typename Head, typename... Tail>
struct pop_front_<typelist <Head, Tail...>> {
using type = typelist<Tail...>;
};
}
template <typename List>
using pop_front = eval<
pop_front_impl::pop_front_<List>
>;
namespace pop_back_impl {
template <typename List>
struct pop_back_ {
using type = reverse<
pop_front<reverse<List>>
>;
};
}
template <typename List>
using pop_back = eval <
pop_back_impl::pop_back_<List>
>;
namespace transform_impl {
template <typename, typename = void>
struct transform_ { };
template <typename... Ts, typename Fn>
struct transform_<typelist<typelist<Ts...>, Fn>,
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
using type = typelist<
invoke_t<Fn, Ts>...
>;
};
template <typename... Ts0, typename... Ts1, typename Fn>
struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
using type = typelist<
invoke_t<Fn, Ts0, Ts1>...
>;
};
}
template <typename... Args>
using transform = eval<
transform_impl::transform_<typelist<Args...>>
>;
namespace transform_lazy_impl {
template <typename, typename = void>
struct transform_lazy_ { };
// Match for Unary Fn with one typelist
template <typename... Ts, typename Fn>
struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
using type = typelist<
invoke<Fn, Ts>...
>;
};
// Match for Binary Fn with two typelists
template <typename... Ts0, typename... Ts1, typename Fn>
struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
using type = typelist<
invoke<Fn, Ts0, Ts1>...
>;
};
}
template <typename... Args>
transform_lazy_impl::transform_lazy_<typelist<Args...>>
>;
namespace find_if_impl {
template <typename, typename, index_t>
struct find_if_ { };
template<typename Head, typename... Tail, typename Fn, index_t N>
struct find_if_<typelist<Head, Tail...>, Fn, N> {
// Recursive call to find_if_ until Fn returns true_
using type = if_ <
invoke_t<Fn, Head>,
index_<N>, // done, return current index
eval<find_if_< // not done, re-call find_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
>;
};
// When empty or when we are one place after the last item return Npos
template<typename Fn, index_t N>
struct find_if_<typelist<>, Fn, N> {
using type = Npos;
};
}
template<typename List, typename Pred>
using find_if = eval<
find_if_impl::find_if_<List, Pred, 0>
>;
template <typename List, typename T>
using find = find_if<List, same_as<T>>;
namespace seek_if_impl {
template <typename, typename, index_t>
struct seek_if_ { };
template<typename Head, typename... Tail, typename Fn, index_t N>
struct seek_if_<typelist<Head, Tail...>, Fn, N> {
// recursive call to seek_if_ until Fn returns true_
using type = if_ <
invoke_t<Fn, Head>,
typelist<Head, Tail...>, // done, return the typelist starting from here
eval<seek_if_< // not done, re-call seek_if_ with the Tail...
typelist<Tail...>, Fn, N+1>
>
>;
};
// When empty or when we are one place after the last item return empty typelist
template<typename Fn, index_t N>
struct seek_if_<typelist<>, Fn, N> {
using type = typelist<>;
};
}
template <typename List, typename Pred>
using seek_if = eval<
seek_if_impl::seek_if_<List, Pred, 0>
>;
template <typename List, typename T>
using seek = seek_if <List, same_as<T>>;
namespace count_if_impl {
template <typename, typename, size_t>
struct count_if_ { };
template<typename Head, typename... Tail, typename Fn, size_t N>
struct count_if_<typelist<Head, Tail...>, Fn, N> {
// Recursive call to count_if_ up to the end of List, counting all invokes of Fn
// returning true_
using type = if_ <
invoke_t<Fn, Head>,
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
>,
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
>
>;
};
// At the end of the List return the counter
template<typename Fn, size_t N>
struct count_if_<typelist<>, Fn, N> {
using type = size_<N>;
};
}
template <typename List, typename Pred>
using count_if = eval<
count_if_impl::count_if_<List, Pred, 0>
>;
template <typename List, typename T>
using count = count_if<List, same_as<T>>;
namespace filter_impl {
template <typename, typename, typename>
struct filter_ { };
template<typename Head, typename... Tail, typename Fn, typename L>
struct filter_<typelist<Head, Tail...>, Fn, L> {
// Recursive call to filter_ up to the end of the List, creating a new list
// of items for which the invoke of Fn returns true_
using type = if_ <
invoke_t <Fn, Head>,
eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
>;
};
// At the end return the produced list
template<typename Fn, typename L>
struct filter_<typelist<>, Fn, L> {
using type = L;
};
}
template <typename List, typename Pred>
using filter = eval<
filter_impl::filter_<List, Pred, typelist<>>
>;
namespace replace_if_impl {
template <typename, typename, typename, typename>
struct replace_if_ { };
template <typename Head, typename... Tail, typename Fn, typename T, typename Ret>
struct replace_if_<typelist<Head, Tail...>, Fn, T, Ret> {
// Recursive call to replace_if_ up to the end of the List, creating a new list
// of items based on invocation of Fn
using type = if_ <
invoke_t<Fn, Head>,
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
>;
};
// At the end return the produced list
template <typename Fn, typename T, typename Ret>
struct replace_if_ <typelist<>, Fn, T, Ret> {
using type = Ret;
};
}
template<typename List, typename Pred, typename T>
using replace_if = eval<
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
>;
template <typename List, typename T, typename U>
using replace = eval <
replace_if <List, same_as<T>, U>
>;
template <typename List, typename Pred>
using all_of = if_ <
empty <List>,
filter <List, compose<quote<not_>, Pred>>
>
>;
template <typename List, typename Pred>
using any_of = not_<
empty<filter <List, Pred>>
>;
template <typename List, typename Pred>
using none_of = empty<
filter <List, Pred>
>;
}}
#endif /* __utl_meta_typelist_h__ */