|
|
@@ -36,7 +36,9 @@ namespace utl { |
|
|
|
namespace meta {
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* A class template that just holds a parameter pack.
|
|
|
|
* \brief
|
|
|
|
* A class template that just holds a parameter pack.
|
|
|
|
*
|
|
|
|
* The idea came from MPL's sequence concept[1] and from N4115[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.
|
|
|
@@ -45,12 +47,15 @@ namespace meta { |
|
|
|
* 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).
|
|
|
|
* ex:
|
|
|
|
* using l1 = typelist<int, void*, double>;
|
|
|
|
* \example
|
|
|
|
* \code
|
|
|
|
* using l1 = typelist<int, void*, double, void>;
|
|
|
|
* l1 a {};
|
|
|
|
* \endcode
|
|
|
|
*
|
|
|
|
* boost::hana[3] suggest 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 comse along). So a simple python-like list with some extra vector-like
|
|
|
|
* responsibility that come 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/
|
|
|
@@ -69,11 +74,43 @@ namespace meta { |
|
|
|
static constexpr bool empty() noexcept {
|
|
|
|
return (sizeof...(Ts) == 0);
|
|
|
|
}
|
|
|
|
// ======= times utility =======
|
|
|
|
private:
|
|
|
|
template<size_t N, typename L, typename ...T>
|
|
|
|
struct times_ { };
|
|
|
|
|
|
|
|
template<size_t N, typename ...L>
|
|
|
|
struct times_<N, typelist<L...>, Ts...> {
|
|
|
|
// append one and recurse
|
|
|
|
using type = type_<
|
|
|
|
if_c <N != 0,
|
|
|
|
times_<N-1, typelist<L..., Ts...>, Ts...>,
|
|
|
|
typelist<L...>
|
|
|
|
>>;
|
|
|
|
};
|
|
|
|
public:
|
|
|
|
/*!
|
|
|
|
* Generate typelist<Ts..., Ts..., ...> of size \c N arguments.
|
|
|
|
* \example
|
|
|
|
* \code
|
|
|
|
* static_assert (
|
|
|
|
* std::is_same<typelist<int, char>::times<2>,
|
|
|
|
* typelist<int, char, int, char>
|
|
|
|
* >, "" );
|
|
|
|
* \endcode
|
|
|
|
* complexity \f$ O(N) \f$
|
|
|
|
*/
|
|
|
|
template<size_t N>
|
|
|
|
using times = type_<
|
|
|
|
times_<N, typelist<>, Ts...>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* An integral constant wrapper that is the size of the \c meta::typelist
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(1) \f$.
|
|
|
|
*
|
|
|
|
* \param List A typelist
|
|
|
|
* \return The size of the typelist
|
|
|
|
*/
|
|
|
@@ -82,7 +119,9 @@ namespace meta { |
|
|
|
|
|
|
|
/*!
|
|
|
|
* An Boolean constant wrapper that returns if the typelist is empty
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(1) \f$.
|
|
|
|
*
|
|
|
|
* \param List A typelist
|
|
|
|
* \return Empty or not
|
|
|
|
*/
|
|
|
@@ -91,46 +130,205 @@ namespace meta { |
|
|
|
|
|
|
|
//! pair
|
|
|
|
//! A special typelist with only 2 Types
|
|
|
|
//! @{
|
|
|
|
template <typename T1, typename T2>
|
|
|
|
using pair = typelist<T1, T2>;
|
|
|
|
|
|
|
|
|
|
|
|
//! repeat
|
|
|
|
//! @{
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* A wrapper to typelist<>::times<> utility for integer argument \p N
|
|
|
|
*/
|
|
|
|
template <size_t N, typename ...Ts>
|
|
|
|
using repeat_c = typename typelist<Ts...>::template times<N>;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* A wrapper to typelist<>::times<> utility for integral_c argument \p N
|
|
|
|
*/
|
|
|
|
template <typename N, typename ...Ts>
|
|
|
|
using repeat = repeat_c<N::type::value, Ts...>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! apply
|
|
|
|
//! like:
|
|
|
|
//! template <class F, class Tuple>
|
|
|
|
//! constexpr decltype(auto) apply(F&& f, Tuple&& t);
|
|
|
|
namespace detail {
|
|
|
|
template <typename Fn, typename Param>
|
|
|
|
/*!
|
|
|
|
* Apply
|
|
|
|
*/
|
|
|
|
//! @{
|
|
|
|
namespace apply_impl {
|
|
|
|
template <typename Fn, typename Seq>
|
|
|
|
struct apply_ { };
|
|
|
|
|
|
|
|
// apply Param =Ret(Args...)
|
|
|
|
template <typename Fn, typename Ret, typename... Args>
|
|
|
|
struct apply_<Fn, Ret(Args...)>
|
|
|
|
: invoke<Fn, Ret, Args...> { };
|
|
|
|
// apply Param = F<Args...>
|
|
|
|
template <typename Fn, template <typename...> class F, typename... Args>
|
|
|
|
struct apply_<Fn, F<Args...>>
|
|
|
|
: invoke<Fn, Args...> { };
|
|
|
|
// apply Param = integer_sequence<T, Is...>
|
|
|
|
//! \p Sequence == typelist<>
|
|
|
|
template<typename Fn, typename ...List>
|
|
|
|
struct apply_<Fn, typelist<List...>> {
|
|
|
|
using type = invoke<Fn, List...>;
|
|
|
|
};
|
|
|
|
//! Sequence == integer_sequence<>
|
|
|
|
template <typename Fn, typename T, T... Is>
|
|
|
|
struct apply_<Fn, integer_sequence<T, Is...>>
|
|
|
|
: invoke<Fn, integral_constant<T, Is>...> { };
|
|
|
|
struct apply_<Fn, integer_sequence<T, Is...>> {
|
|
|
|
using type = invoke<Fn, integral_c<T, Is>...>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Apply the Invocable \p Fn using the types in the type \p Param as arguments.
|
|
|
|
template <typename Fn, typename Param>
|
|
|
|
using apply = detail::apply_<Fn, Param>;
|
|
|
|
/*!
|
|
|
|
* Apply the Invocable \p Fn using the types in the type \p Seq as arguments.
|
|
|
|
* \note
|
|
|
|
* This is the opposed operation of typelist<Ts...>
|
|
|
|
*
|
|
|
|
* If \p Seq == typelist<> then
|
|
|
|
* Unpack typelist and apply to \c Fn
|
|
|
|
* It \p Seq == integer_sequence<> then
|
|
|
|
* Unpack and use the integral_c<> of each integer
|
|
|
|
*/
|
|
|
|
template <typename Fn, typename Seq>
|
|
|
|
using apply = apply_impl::apply_<Fn, Seq>;
|
|
|
|
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ========= element access ========
|
|
|
|
*/
|
|
|
|
//! at: random element access
|
|
|
|
//! @{
|
|
|
|
namespace at_impl {
|
|
|
|
|
|
|
|
template <typename T> struct _as_pointer__ { using type = T*; };
|
|
|
|
template <typename T> struct _as_pointer__<T*> { using type = T*; };
|
|
|
|
template <typename T> using as_pointer_ = type_<
|
|
|
|
_as_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<as_pointer_<List>>(nullptr)...) //< pass all as List*...
|
|
|
|
);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Return the \p N th element in the \c meta::typelist \p List.
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$.
|
|
|
|
*/
|
|
|
|
template <typename List, index_t N>
|
|
|
|
using at_c = type_<
|
|
|
|
at_impl::at_<List, N>
|
|
|
|
>;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Return the \p N th element in the \c meta::typelist \p List.
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$.
|
|
|
|
*/
|
|
|
|
template <typename List, typename N>
|
|
|
|
using at = at_c<List, N::type::value>;
|
|
|
|
//!@}
|
|
|
|
|
|
|
|
|
|
|
|
//! front
|
|
|
|
//! @{
|
|
|
|
namespace front_impl {
|
|
|
|
template <typename L>
|
|
|
|
struct front_ { };
|
|
|
|
|
|
|
|
template <typename Head, typename... Tail>
|
|
|
|
struct front_<typelist<Head, Tail...>> {
|
|
|
|
using type = Head;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Return the first element in \c meta::typelist \p List.
|
|
|
|
//! Complexity \f$ O(1) \f$.
|
|
|
|
template <typename List>
|
|
|
|
using front = type_<
|
|
|
|
front_impl::front_<List>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! back
|
|
|
|
//! @{
|
|
|
|
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)
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Return the last element in \c meta::typelist \p List.
|
|
|
|
//! Complexity \f$ O(N) \f$.
|
|
|
|
template <typename List>
|
|
|
|
using back = type_<
|
|
|
|
back_impl::back_<List>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
/*
|
|
|
|
* ========= typelist operations =========
|
|
|
|
*/
|
|
|
|
|
|
|
|
//! Concatenation
|
|
|
|
//! @{
|
|
|
|
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...> { };
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Transformation that concatenates several lists into a single typelist.
|
|
|
|
* The parameters must all be instantiations of \c meta::typelist.
|
|
|
|
* Complexity: \f$ O(N) \f$
|
|
|
|
* where \f$ N \f$ is the number of lists passed to the algorithm.
|
|
|
|
*/
|
|
|
|
template <typename... Lists>
|
|
|
|
using cat = type_<
|
|
|
|
cat_impl::cat_<Lists...>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
|
|
|
//! fold<List, V, Fn>, rev_fold<List, V, Fn>
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
namespace fold_impl {
|
|
|
|
// fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
|
|
|
|
template<typename, typename, typename>
|
|
|
|
struct fold_ { }; // ill formed
|
|
|
@@ -140,19 +338,42 @@ namespace meta { |
|
|
|
typename V,
|
|
|
|
typename Fn>
|
|
|
|
struct fold_<typelist<Head, Tail...>, V, Fn> {
|
|
|
|
using type = type_<
|
|
|
|
fold_<
|
|
|
|
typelist<Tail...>,
|
|
|
|
invoke<Fn, V, Head>,
|
|
|
|
Fn
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
// recursive call of fold_ by consuming typelist and invoking Fn
|
|
|
|
using type = type_<
|
|
|
|
fold_<
|
|
|
|
typelist<Tail...>,
|
|
|
|
invoke<Fn, V, Head>,
|
|
|
|
Fn
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
// termination call
|
|
|
|
template<typename V0, typename Fn>
|
|
|
|
struct fold_<typelist<>, V0, Fn> {
|
|
|
|
using type = V0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
|
|
|
|
* and initial value \p V
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
* \example
|
|
|
|
* fold<typelist<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
|
|
|
|
* \example
|
|
|
|
* fold<typelist<>, V, F> == V
|
|
|
|
* \param List The list to fold
|
|
|
|
* \param V The initial item feeded to Fn
|
|
|
|
* \param Fn The binary Invocable
|
|
|
|
*/
|
|
|
|
template <typename List, typename V, typename Fn>
|
|
|
|
using fold = type_<fold_impl::fold_<List, V, Fn>>;
|
|
|
|
|
|
|
|
//! accumulate is an stl name for fold
|
|
|
|
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>
|
|
|
@@ -163,17 +384,18 @@ namespace meta { |
|
|
|
typename V,
|
|
|
|
typename Fn>
|
|
|
|
struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
|
|
|
|
using type = invoke <
|
|
|
|
Fn, Head, type_<
|
|
|
|
rev_fold_ <
|
|
|
|
typelist<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, type_<
|
|
|
|
rev_fold_ <
|
|
|
|
typelist<Tail...>,
|
|
|
|
V,
|
|
|
|
Fn
|
|
|
|
>>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
// termination call
|
|
|
|
// pre-termination call
|
|
|
|
template<typename Tail, typename V, typename Fn>
|
|
|
|
struct rev_fold_ <typelist<Tail>, V, Fn> {
|
|
|
|
using type = invoke<Fn, Tail, V>;
|
|
|
@@ -181,239 +403,461 @@ namespace meta { |
|
|
|
// termination call
|
|
|
|
template<typename V, typename Fn>
|
|
|
|
struct rev_fold_ <typelist<>, V, Fn> {
|
|
|
|
using type = invoke<Fn, V>;
|
|
|
|
using type = V;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
|
|
|
|
* transform the \p List to a new one by doing a right fold using binary Invocable \p Fn
|
|
|
|
* and initial value \p V
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
* \example
|
|
|
|
* rev_fold<typelist<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
|
|
|
|
* \example
|
|
|
|
* rev_fold<typelist<>, V, F> == V
|
|
|
|
* \param List The list to fold
|
|
|
|
* \param V The initial item feeded to Fn
|
|
|
|
* \param V The initial item fed to Fn
|
|
|
|
* \param Fn The binary Invocable
|
|
|
|
*/
|
|
|
|
template <typename List, typename V, typename Fn>
|
|
|
|
using fold = type_<detail::fold_<List, V, Fn>>;
|
|
|
|
|
|
|
|
//! accumulate is an stl name for fold
|
|
|
|
template <typename List, typename V, typename Fn>
|
|
|
|
using accumulate = fold<List, V, Fn>;
|
|
|
|
using rev_fold = type_<
|
|
|
|
rev_fold_impl::rev_fold_<List, V, Fn>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
|
|
|
|
* and initial value \p V
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
* \param List The list to fold
|
|
|
|
* \param V The initial item feeded to Fn
|
|
|
|
* \param Fn The binary Invocable
|
|
|
|
* Return a new \c typelist by adding the elements \p Ts to the front of \p List.
|
|
|
|
* Complexity \f$ O(1) \f$
|
|
|
|
*/
|
|
|
|
template <typename List, typename V, typename Fn>
|
|
|
|
using rev_fold = type_<detail::rev_fold_<List, V, Fn>>;
|
|
|
|
//! @}
|
|
|
|
template <typename List, typename... Ts>
|
|
|
|
using push_front = type_<
|
|
|
|
apply <
|
|
|
|
bind_front<quote<typelist>, Ts...>, List
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
|
|
|
|
//! Concatenation
|
|
|
|
/*!
|
|
|
|
* Return a new \c typelist by adding the elements \p Ts to the back of \p List.
|
|
|
|
* Complexity \f$ O(1) \f$
|
|
|
|
*/
|
|
|
|
template <typename List, typename... Ts>
|
|
|
|
using push_back = type_<
|
|
|
|
apply <
|
|
|
|
bind_back<quote<typelist>, Ts...>, List
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
|
|
|
|
//! reverse
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
template <typename... Lists>
|
|
|
|
struct concat_ { };
|
|
|
|
namespace reverse_impl {
|
|
|
|
|
|
|
|
template <>
|
|
|
|
struct concat_<> {
|
|
|
|
using type = typelist<>;
|
|
|
|
template <typename List, typename V = typelist<>>
|
|
|
|
struct reverse_ {
|
|
|
|
using type = fold<List, V, quote<push_front>>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... L1>
|
|
|
|
struct concat_<typelist<L1...>> {
|
|
|
|
using type = typelist<L1...>;
|
|
|
|
};
|
|
|
|
/*!
|
|
|
|
* Return a new \c typelist by reversing the elements in the list \p List.
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*/
|
|
|
|
template <typename List>
|
|
|
|
using reverse = type_<
|
|
|
|
reverse_impl::reverse_<List>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
template <typename... L1, typename... L2>
|
|
|
|
struct concat_<typelist<L1...>, typelist<L2...>> {
|
|
|
|
using type = typelist<L1..., L2...>;
|
|
|
|
};
|
|
|
|
//! pop_front
|
|
|
|
//! @{
|
|
|
|
namespace pop_front_impl {
|
|
|
|
template <typename List>
|
|
|
|
struct pop_front_ { };
|
|
|
|
|
|
|
|
template <typename... L1, typename... L2, typename... L3>
|
|
|
|
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>> {
|
|
|
|
using type = typelist<L1..., L2..., L3...>;
|
|
|
|
template <typename Head, typename... Tail>
|
|
|
|
struct pop_front_<typelist <Head, Tail...>> {
|
|
|
|
using type = typelist<Tail...>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... L1, typename... L2, typename... L3, typename... Rest>
|
|
|
|
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, Rest...>
|
|
|
|
: concat_<typelist<L1..., L2..., L3...>, Rest...> { };
|
|
|
|
|
|
|
|
template <typename... L1, typename... L2,
|
|
|
|
typename... L3, typename... L4,
|
|
|
|
typename... Rest>
|
|
|
|
struct concat_<typelist<L1...>, typelist<L2...>, typelist<L3...>, typelist<L4...>, Rest...>
|
|
|
|
: concat_<typelist<L1..., L2..., L3..., L4...>, Rest...> { };
|
|
|
|
/*!
|
|
|
|
* Return a new \c typelist by removing the first element from the
|
|
|
|
* front of \p List.
|
|
|
|
* Complexity \f$ O(1) \f$
|
|
|
|
*/
|
|
|
|
template <typename List>
|
|
|
|
using pop_front = type_<
|
|
|
|
pop_front_impl::pop_front_<List>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! pop_back
|
|
|
|
//! @{
|
|
|
|
namespace pop_back_impl {
|
|
|
|
template <typename List>
|
|
|
|
struct pop_back_ {
|
|
|
|
using type = reverse<
|
|
|
|
pop_front<reverse<List>>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Transformation that concatenates several lists into a single typelist.
|
|
|
|
* The parameters must all be instantiations of \c meta::typelist.
|
|
|
|
* Complexity: \f$ O(L) \f$
|
|
|
|
* where \f$ L \f$ is the number of lists in the typelist of lists.
|
|
|
|
* Return a new \c typelist by removing the last element from the \p List.
|
|
|
|
* Complexity \f$ O(N) \f$.
|
|
|
|
* \note
|
|
|
|
* This operation, in addition from other push/pop operations, is
|
|
|
|
* heavy(2 reverse operations).
|
|
|
|
*/
|
|
|
|
template <typename... Lists>
|
|
|
|
using concat = type_<detail::concat_<Lists...>>;
|
|
|
|
template <typename List>
|
|
|
|
using pop_back = type_ <
|
|
|
|
pop_back_impl::pop_back_<List>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! Transform
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
namespace transform_impl {
|
|
|
|
template <typename, typename = void>
|
|
|
|
struct transform_ { };
|
|
|
|
|
|
|
|
template <typename... Ts, typename Fn>
|
|
|
|
struct transform_<typelist<typelist<Ts...>, Fn>, void_<invoke<Fn, Ts>...>> {
|
|
|
|
using type = typelist<invoke<Fn, Ts>...>;
|
|
|
|
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_<invoke<Fn, Ts0, Ts1>...>> {
|
|
|
|
using type = typelist<invoke<Fn, Ts0, Ts1>...>;
|
|
|
|
void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
|
|
|
|
using type = typelist<
|
|
|
|
invoke_t<Fn, Ts0, Ts1>...
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace detail
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Transform One or two lists with invocable \c Fn and return a new typelist
|
|
|
|
* Syntax:
|
|
|
|
* 1) transform<List..., Fn> Unary invocable
|
|
|
|
* 2) transform<List1, List2, Fn> Binary invocable
|
|
|
|
* Transformation by applying an invocable \c Fn to one or two lists
|
|
|
|
* and return the resulting typelist
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$.
|
|
|
|
* \example
|
|
|
|
* \code
|
|
|
|
* using l1 = typelist<char, int, ...>;
|
|
|
|
* using l2 = typelist<void, void, ...>;
|
|
|
|
* using r1 = transform<l1, F1>; // F1, unary invocable
|
|
|
|
* using r2 = transform<l1, l2, F2>; // F2, binary invocable
|
|
|
|
* \endcode
|
|
|
|
*/
|
|
|
|
template <typename... Args>
|
|
|
|
using transform = type_<detail::transform_<typelist<Args...>>>;
|
|
|
|
using transform = type_<
|
|
|
|
transform_impl::transform_<typelist<Args...>>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! repeat_n
|
|
|
|
//! Transform lazy
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
template <typename T, size_t>
|
|
|
|
using first_ = T;
|
|
|
|
namespace transform_lazy_impl {
|
|
|
|
template <typename, typename = void>
|
|
|
|
struct transform_lazy_ { };
|
|
|
|
|
|
|
|
template <typename T, typename Ints>
|
|
|
|
struct repeat_n_c_ { };
|
|
|
|
// 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>...
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, size_t... Is>
|
|
|
|
struct repeat_n_c_<T, index_sequence<Is...>> {
|
|
|
|
using type = typelist<first_<T, Is>...>;
|
|
|
|
// 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>...
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Generate typelist<T,T,T...T> of size \c N arguments.
|
|
|
|
* Complexity \f$ O(log N) \f$.
|
|
|
|
*/
|
|
|
|
template <index_t N, typename T = void>
|
|
|
|
using repeat_n_c = type_<detail::repeat_n_c_<T, make_index_sequence<N>>>;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Generate typelist<T,T,T...T> of size \c N::type::value arguments.
|
|
|
|
* Complexity \f$ O(log N) \f$.
|
|
|
|
* Transformation by applying an invocable \c Fn to one or two lists
|
|
|
|
* and return a typelist containing the invocables with their arguments,
|
|
|
|
* not their resulting types.
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \example
|
|
|
|
* \code
|
|
|
|
* using l1 = typelist<char, int, ...>;
|
|
|
|
* using l2 = typelist<void, void, ...>;
|
|
|
|
* using r1 = transform<l1, F1>; // F1, unary invocable
|
|
|
|
* using r2 = transform<l1, l2, F2>; // F2, binary invocable
|
|
|
|
* \endcode
|
|
|
|
*/
|
|
|
|
template <typename N, typename T = void>
|
|
|
|
using repeat_n = repeat_n_c<N::type::value, T>;
|
|
|
|
template <typename... Args>
|
|
|
|
using transform_lazy = type_<
|
|
|
|
transform_lazy_impl::transform_lazy_<typelist<Args...>>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! at
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
|
|
|
|
template <typename VoidPtrs>
|
|
|
|
struct at_impl_;
|
|
|
|
|
|
|
|
template <typename... VoidPtrs>
|
|
|
|
struct at_impl_<typelist<VoidPtrs...>> {
|
|
|
|
static nil_ eval(...);
|
|
|
|
//! find_if, find
|
|
|
|
//! @{
|
|
|
|
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_t_<N>, // done, return current index
|
|
|
|
type_<find_if_< // not done, re-call find_if_ with the Tail...
|
|
|
|
typelist<Tail...>, Fn, N+1>
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T, typename... Us>
|
|
|
|
static T eval(VoidPtrs..., T *, Us *...);
|
|
|
|
// 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 L, index_t N>
|
|
|
|
struct at_ { };
|
|
|
|
/*!
|
|
|
|
* Search for the first \c Item on the \p List for which the predicate \p Pred
|
|
|
|
* returns true_ when `type_<invoke<Pred, Item>>`
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \param List A typelist
|
|
|
|
* \param Pred A Unary invocable predicate
|
|
|
|
* \return An integral constant of index_t with the location of the first match,
|
|
|
|
* or Npos otherwise.
|
|
|
|
*/
|
|
|
|
template<typename List, typename Pred>
|
|
|
|
using find_if = type_<
|
|
|
|
find_if_impl::find_if_<List, Pred, 0>
|
|
|
|
>;
|
|
|
|
|
|
|
|
template <typename... Ts, index_t N>
|
|
|
|
struct at_<typelist<Ts...>, N>
|
|
|
|
: decltype(
|
|
|
|
at_impl_<repeat_n_c<N, void *>>::eval(static_cast<identity<Ts> *>(nullptr)...)
|
|
|
|
) { };
|
|
|
|
} // namespace detail
|
|
|
|
/*!
|
|
|
|
* Search for the first occurrence of type \p T on a \p List
|
|
|
|
*/
|
|
|
|
template <typename List, typename T>
|
|
|
|
using find = find_if<List, same_as<T>>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
/// Return the \p N th element in the \c meta::typelist \p L.
|
|
|
|
/// Complexity \f$ O(1) \f$.
|
|
|
|
template <typename L, index_t N>
|
|
|
|
using at_c = type_<detail::at_<L, N>>;
|
|
|
|
//! seek_if
|
|
|
|
//! @{
|
|
|
|
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
|
|
|
|
type_<seek_if_< // not done, re-call seek_if_ with the Tail...
|
|
|
|
typelist<Tail...>, Fn, N+1>
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
//! Return the \p N th element in the \c meta::typelist \p L.
|
|
|
|
//! Complexity \f$ O(1) \f$.
|
|
|
|
template <typename L, typename N>
|
|
|
|
using at = at_c<L, N::type::value>;
|
|
|
|
//!@}
|
|
|
|
// 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<>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Search for the first \c Item on the \p List for which the predicate \p Pred
|
|
|
|
* returns true_ when `type_<invoke<Pred, Item>>` and return the rest of the \p List
|
|
|
|
* starting from that position as new typelist
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \param List A typelist
|
|
|
|
* \param Pred A Unary invocable predicate
|
|
|
|
* \return An integral constant with the location of the first match, on Npos otherwise
|
|
|
|
*/
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using seek_if = type_<
|
|
|
|
seek_if_impl::seek_if_<List, Pred, 0>
|
|
|
|
>;
|
|
|
|
/*!
|
|
|
|
* Search for the first \c Item on the \p List of type \p T and return the rest
|
|
|
|
* of the \p List starting from that position as new typelist
|
|
|
|
*/
|
|
|
|
template <typename List, typename T>
|
|
|
|
using seek = seek_if <List, same_as<T>>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! front
|
|
|
|
//! count_if
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
template <typename L>
|
|
|
|
struct front_ { };
|
|
|
|
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>,
|
|
|
|
type_<
|
|
|
|
count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
|
|
|
|
>,
|
|
|
|
type_<
|
|
|
|
count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
|
|
|
|
>
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Head, typename... Tail>
|
|
|
|
struct front_<typelist<Head, Tail...>> {
|
|
|
|
using type = Head;
|
|
|
|
// At the end of the List return the counter
|
|
|
|
template<typename Fn, size_t N>
|
|
|
|
struct count_if_<typelist<>, Fn, N> {
|
|
|
|
using type = size_t_<N>;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Return the first element in \c meta::typelist \p L.
|
|
|
|
//! Complexity \f$ O(1) \f$.
|
|
|
|
template <typename L>
|
|
|
|
using front = type_<detail::front_<L>>;
|
|
|
|
/*!
|
|
|
|
* Count all \c Items on the \p List for which the predicate \p Pred
|
|
|
|
* returns true_ when `type_<invoke<Pred, Item>>`
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \param List A typelist
|
|
|
|
* \param Pred A Unary invocable predicate
|
|
|
|
* \return The total count of occurrences as an integral constant of size_t
|
|
|
|
*/
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using count_if = type_<
|
|
|
|
count_if_impl::count_if_<List, Pred, 0>
|
|
|
|
>;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Count all occurrences of type \p T int \p List
|
|
|
|
*/
|
|
|
|
template <typename List, typename T>
|
|
|
|
using count = count_if<List, same_as<T>>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! back
|
|
|
|
//! filter
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
template <typename L>
|
|
|
|
struct back_ { };
|
|
|
|
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>,
|
|
|
|
type_<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
|
|
|
|
type_<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Head, typename... Tail>
|
|
|
|
struct back_<typelist<Head, Tail...>> {
|
|
|
|
using type = at_c<typelist<Head, Tail...>, sizeof...(Tail)>;
|
|
|
|
// At the end return the produced list
|
|
|
|
template<typename Fn, typename L>
|
|
|
|
struct filter_<typelist<>, Fn, L> {
|
|
|
|
using type = L;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
//! Return the last element in \c meta::typelist \p L.
|
|
|
|
//! Complexity \f$ O(1) \f$.
|
|
|
|
template <typename L>
|
|
|
|
using back = type_<detail::back_<L>>;
|
|
|
|
/*!
|
|
|
|
* Return a new typelist with elements, the elements of \p List that satisfy the
|
|
|
|
* invocable \p Pred such that `type_<invoke<Pred, Item>>` is \c true_
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \param List The input typelist
|
|
|
|
* \param Pred A unary invocable predicate
|
|
|
|
*/
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using filter = type_<
|
|
|
|
filter_impl::filter_<List, Pred, typelist<>>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
//! pop_front
|
|
|
|
//! replace
|
|
|
|
//! @{
|
|
|
|
namespace detail {
|
|
|
|
template <typename L>
|
|
|
|
struct pop_front_ { };
|
|
|
|
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>,
|
|
|
|
type_<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
|
|
|
|
type_<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
|
|
|
|
>;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Head, typename... L>
|
|
|
|
struct pop_front_<typelist<Head, L...>> {
|
|
|
|
using type = typelist<L...>;
|
|
|
|
// At the end return the produced list
|
|
|
|
template <typename Fn, typename T, typename Ret>
|
|
|
|
struct replace_if_ <typelist<>, Fn, T, Ret> {
|
|
|
|
using type = Ret;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Return a new \c meta::typelist by removing the first element from the
|
|
|
|
* front of \p L.
|
|
|
|
* Complexity \f$ O(1) \f$.
|
|
|
|
* Return a new typelist where all the instances for which the invocation of\p Pred
|
|
|
|
* returns \c true_, are replaced with \p T
|
|
|
|
*
|
|
|
|
* Complexity \f$ O(N) \f$
|
|
|
|
*
|
|
|
|
* \param List The input typelist
|
|
|
|
* \param Pred A unary invocable predicate
|
|
|
|
* \param T The new type to replace the item of the \p List, when type_<invoke<Pred, Item>>
|
|
|
|
* returns \c true_
|
|
|
|
*/
|
|
|
|
template <typename L>
|
|
|
|
using pop_front = type_<detail::pop_front_<L>>;
|
|
|
|
template<typename List, typename Pred, typename T>
|
|
|
|
using replace_if = type_<
|
|
|
|
replace_if_impl::replace_if_<List, Pred, T, typelist<>>
|
|
|
|
>;
|
|
|
|
|
|
|
|
//! Alias wrapper that returns a new \c typelist where all instances of type \p T have
|
|
|
|
//! been replaced with \p U.
|
|
|
|
template <typename List, typename T, typename U>
|
|
|
|
using replace = type_ <
|
|
|
|
replace_if <List, same_as<T>, U>
|
|
|
|
>;
|
|
|
|
//! @}
|
|
|
|
|
|
|
|
|
|
|
|
//! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the
|
|
|
|
//! \p List is empty and \c false_ otherwise.
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using all_of = empty<
|
|
|
|
filter <List, compose<quote<not_>, Pred>>
|
|
|
|
>;
|
|
|
|
|
|
|
|
//! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List
|
|
|
|
//! and \c false_ otherwise.
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using any_of = not_<
|
|
|
|
empty<filter <List, Pred>>
|
|
|
|
>;
|
|
|
|
|
|
|
|
//! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List
|
|
|
|
//! or if the \p List is empty and \c false otherwise.
|
|
|
|
template <typename List, typename Pred>
|
|
|
|
using none_of = empty<
|
|
|
|
filter <List, Pred>
|
|
|
|
>;
|
|
|
|
|
|
|
|
}}
|
|
|
|
|
|
|
|
//! @}
|
|
|
|