| // Copyright Peter Dimov 2015-2021. | |
| // Copyright Matt Borland 2021. | |
| // Use, modification and distribution are subject to the | |
| // Boost Software License, Version 1.0. (See accompanying file | |
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
| // | |
| // Template metaprogramming classes and functions to replace MPL | |
| // Source: http://www.pdimov.com/cpp2/simple_cxx11_metaprogramming.html | |
| // Source: https://github.com/boostorg/mp11/ | |
| #ifndef BOOST_MATH_TOOLS_MP | |
| #define BOOST_MATH_TOOLS_MP | |
| #include <boost/math/tools/config.hpp> | |
| #include <boost/math/tools/type_traits.hpp> | |
| #include <boost/math/tools/cstdint.hpp> | |
| namespace boost { namespace math { namespace tools { namespace meta_programming { | |
| // Types: | |
| // Typelist | |
| template<typename... T> | |
| struct mp_list {}; | |
| // Size_t | |
| template<boost::math::size_t N> | |
| using mp_size_t = boost::math::integral_constant<boost::math::size_t, N>; | |
| // Boolean | |
| template<bool B> | |
| using mp_bool = boost::math::integral_constant<bool, B>; | |
| // Identity | |
| template<typename T> | |
| struct mp_identity | |
| { | |
| using type = T; | |
| }; | |
| // Turns struct into quoted metafunction | |
| template<template<typename...> class F> | |
| struct mp_quote_trait | |
| { | |
| template<typename... T> | |
| using fn = typename F<T...>::type; | |
| }; | |
| namespace detail { | |
| // Size | |
| template<typename L> | |
| struct mp_size_impl {}; | |
| template<template<typename...> class L, typename... T> // Template template parameter must use class | |
| struct mp_size_impl<L<T...>> | |
| { | |
| using type = boost::math::integral_constant<boost::math::size_t, sizeof...(T)>; | |
| }; | |
| } | |
| template<typename T> | |
| using mp_size = typename detail::mp_size_impl<T>::type; | |
| namespace detail { | |
| // Front | |
| template<typename L> | |
| struct mp_front_impl {}; | |
| template<template<typename...> class L, typename T1, typename... T> | |
| struct mp_front_impl<L<T1, T...>> | |
| { | |
| using type = T1; | |
| }; | |
| } | |
| template<typename T> | |
| using mp_front = typename detail::mp_front_impl<T>::type; | |
| namespace detail { | |
| // At | |
| // TODO - Use tree based lookup for larger typelists | |
| // http://odinthenerd.blogspot.com/2017/04/tree-based-lookup-why-kvasirmpl-is.html | |
| template<typename L, boost::math::size_t> | |
| struct mp_at_c {}; | |
| template<template<typename...> class L, typename T0, typename... T> | |
| struct mp_at_c<L<T0, T...>, 0> | |
| { | |
| using type = T0; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename... T> | |
| struct mp_at_c<L<T0, T1, T...>, 1> | |
| { | |
| using type = T1; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T...>, 2> | |
| { | |
| using type = T2; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T...>, 3> | |
| { | |
| using type = T3; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T...>, 4> | |
| { | |
| using type = T4; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T...>, 5> | |
| { | |
| using type = T5; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T...>, 6> | |
| { | |
| using type = T6; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T...>, 7> | |
| { | |
| using type = T7; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename T8, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T...>, 8> | |
| { | |
| using type = T8; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename T8, typename T9, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>, 9> | |
| { | |
| using type = T9; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename T8, typename T9, typename T10, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>, 10> | |
| { | |
| using type = T10; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename T8, typename T9, typename T10, typename T11, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T...>, 11> | |
| { | |
| using type = T11; | |
| }; | |
| template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, | |
| typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename... T> | |
| struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T...>, 12> | |
| { | |
| using type = T12; | |
| }; | |
| } | |
| template<typename L, boost::math::size_t Index> | |
| using mp_at_c = typename detail::mp_at_c<L, Index>::type; | |
| template<typename L, typename Index> | |
| using mp_at = typename detail::mp_at_c<L, Index::value>::type; | |
| // Back | |
| template<typename L> | |
| using mp_back = mp_at_c<L, mp_size<L>::value - 1>; | |
| namespace detail { | |
| // Push back | |
| template<typename L, typename... T> | |
| struct mp_push_back_impl {}; | |
| template<template<typename...> class L, typename... U, typename... T> | |
| struct mp_push_back_impl<L<U...>, T...> | |
| { | |
| using type = L<U..., T...>; | |
| }; | |
| } | |
| template<typename L, typename... T> | |
| using mp_push_back = typename detail::mp_push_back_impl<L, T...>::type; | |
| namespace detail { | |
| // Push front | |
| template<typename L, typename... T> | |
| struct mp_push_front_impl {}; | |
| template<template<typename...> class L, typename... U, typename... T> | |
| struct mp_push_front_impl<L<U...>, T...> | |
| { | |
| using type = L<T..., U...>; | |
| }; | |
| } | |
| template<typename L, typename... T> | |
| using mp_push_front = typename detail::mp_push_front_impl<L, T...>::type; | |
| namespace detail{ | |
| // If | |
| template<bool C, typename T, typename... E> | |
| struct mp_if_c_impl{}; | |
| template<typename T, typename... E> | |
| struct mp_if_c_impl<true, T, E...> | |
| { | |
| using type = T; | |
| }; | |
| template<typename T, typename E> | |
| struct mp_if_c_impl<false, T, E> | |
| { | |
| using type = E; | |
| }; | |
| } | |
| template<bool C, typename T, typename... E> | |
| using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type; | |
| template<typename C, typename T, typename... E> | |
| using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type; | |
| namespace detail { | |
| // Find if | |
| template<typename L, template<typename...> class P> | |
| struct mp_find_if_impl {}; | |
| template<template<typename...> class L, template<typename...> class P> | |
| struct mp_find_if_impl<L<>, P> | |
| { | |
| using type = mp_size_t<0>; | |
| }; | |
| template<typename L, template<typename...> class P> | |
| struct mp_find_if_impl_2 | |
| { | |
| using r = typename mp_find_if_impl<L, P>::type; | |
| using type = mp_size_t<1 + r::value>; | |
| }; | |
| template<template<typename...> class L, typename T1, typename... T, template<typename...> class P> | |
| struct mp_find_if_impl<L<T1, T...>, P> | |
| { | |
| using type = typename mp_if<P<T1>, mp_identity<mp_size_t<0>>, mp_find_if_impl_2<mp_list<T...>, P>>::type; | |
| }; | |
| } | |
| template<typename L, template<typename...> class P> | |
| using mp_find_if = typename detail::mp_find_if_impl<L, P>::type; | |
| template<typename L, typename Q> | |
| using mp_find_if_q = mp_find_if<L, Q::template fn>; | |
| namespace detail { | |
| // Append | |
| template<typename... L> | |
| struct mp_append_impl {}; | |
| template<> | |
| struct mp_append_impl<> | |
| { | |
| using type = mp_list<>; | |
| }; | |
| template<template<typename...> class L, typename... T> | |
| struct mp_append_impl<L<T...>> | |
| { | |
| using type = L<T...>; | |
| }; | |
| template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2> | |
| struct mp_append_impl<L1<T1...>, L2<T2...>> | |
| { | |
| using type = L1<T1..., T2...>; | |
| }; | |
| template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, | |
| template<typename...> class L3, typename... T3> | |
| struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>> | |
| { | |
| using type = L1<T1..., T2..., T3...>; | |
| }; | |
| template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, | |
| template<typename...> class L3, typename... T3, template<typename...> class L4, typename... T4> | |
| struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>> | |
| { | |
| using type = L1<T1..., T2..., T3..., T4...>; | |
| }; | |
| template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, | |
| template<typename...> class L3, typename... T3, template<typename...> class L4, typename... T4, | |
| template<typename...> class L5, typename... T5, typename... Lr> | |
| struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>, L5<T5...>, Lr...> | |
| { | |
| using type = typename mp_append_impl<L1<T1..., T2..., T3..., T4..., T5...>, Lr...>::type; | |
| }; | |
| } | |
| template<typename... L> | |
| using mp_append = typename detail::mp_append_impl<L...>::type; | |
| namespace detail { | |
| // Remove if | |
| template<typename L, template<typename...> class P> | |
| struct mp_remove_if_impl{}; | |
| template<template<typename...> class L, typename... T, template<typename...> class P> | |
| struct mp_remove_if_impl<L<T...>, P> | |
| { | |
| template<typename U> | |
| struct _f | |
| { | |
| using type = mp_if<P<U>, mp_list<>, mp_list<U>>; | |
| }; | |
| using type = mp_append<L<>, typename _f<T>::type...>; | |
| }; | |
| } | |
| template<typename L, template<class...> class P> | |
| using mp_remove_if = typename detail::mp_remove_if_impl<L, P>::type; | |
| template<typename L, typename Q> | |
| using mp_remove_if_q = mp_remove_if<L, Q::template fn>; | |
| template<typename T, T... Index> | |
| struct integer_sequence {}; | |
| template<boost::math::size_t... Index> | |
| using index_sequence = integer_sequence<boost::math::size_t, Index...>; | |
| namespace detail { | |
| template<bool C, typename T, typename E> | |
| struct iseq_if_c_impl {}; | |
| template<typename T, typename F> | |
| struct iseq_if_c_impl<true, T, F> | |
| { | |
| using type = T; | |
| }; | |
| template<typename T, typename F> | |
| struct iseq_if_c_impl<false, T, F> | |
| { | |
| using type = F; | |
| }; | |
| template<bool C, typename T, typename F> | |
| using iseq_if_c = typename iseq_if_c_impl<C, T, F>::type; | |
| template<typename T> | |
| struct iseq_identity | |
| { | |
| using type = T; | |
| }; | |
| template<typename T1, typename T2> | |
| struct append_integer_sequence {}; | |
| template<typename T, T... Index, T... J> | |
| struct append_integer_sequence<integer_sequence<T, Index...>, integer_sequence<T, J...>> | |
| { | |
| using type = integer_sequence<T, Index..., (J + sizeof...(Index))...>; | |
| }; | |
| template<typename T, T N> | |
| struct make_integer_sequence_impl; | |
| template<typename T, T N> | |
| class make_integer_sequence_impl_ | |
| { | |
| private: | |
| static_assert(N >= 0, "N must not be negative"); | |
| static constexpr T M = N / 2; | |
| static constexpr T R = N % 2; | |
| using seq1 = typename make_integer_sequence_impl<T, M>::type; | |
| using seq2 = typename append_integer_sequence<seq1, seq1>::type; | |
| using seq3 = typename make_integer_sequence_impl<T, R>::type; | |
| using seq4 = typename append_integer_sequence<seq2, seq3>::type; | |
| public: | |
| using type = seq4; | |
| }; | |
| template<typename T, T N> | |
| struct make_integer_sequence_impl | |
| { | |
| using type = typename iseq_if_c<N == 0, | |
| iseq_identity<integer_sequence<T>>, | |
| iseq_if_c<N == 1, iseq_identity<integer_sequence<T, 0>>, | |
| make_integer_sequence_impl_<T, N>>>::type; | |
| }; | |
| } // namespace detail | |
| template<typename T, T N> | |
| using make_integer_sequence = typename detail::make_integer_sequence_impl<T, N>::type; | |
| template<boost::math::size_t N> | |
| using make_index_sequence = make_integer_sequence<boost::math::size_t, N>; | |
| template<typename... T> | |
| using index_sequence_for = make_integer_sequence<boost::math::size_t, sizeof...(T)>; | |
| }}}} // namespaces | |
| #endif // BOOST_MATH_TOOLS_MP |