| 1 | // Copyright Peter Dimov 2015-2021. |
| 2 | // Copyright Matt Borland 2021. |
| 3 | // Use, modification and distribution are subject to the |
| 4 | // Boost Software License, Version 1.0. (See accompanying file |
| 5 | // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 6 | // |
| 7 | // Template metaprogramming classes and functions to replace MPL |
| 8 | // Source: http://www.pdimov.com/cpp2/simple_cxx11_metaprogramming.html |
| 9 | // Source: https://github.com/boostorg/mp11/ |
| 10 | |
| 11 | #ifndef BOOST_MATH_TOOLS_MP |
| 12 | #define BOOST_MATH_TOOLS_MP |
| 13 | |
| 14 | #include <type_traits> |
| 15 | #include <cstddef> |
| 16 | #include <utility> |
| 17 | |
| 18 | namespace boost { namespace math { namespace tools { namespace meta_programming { |
| 19 | |
| 20 | // Types: |
| 21 | // Typelist |
| 22 | template<typename... T> |
| 23 | struct mp_list {}; |
| 24 | |
| 25 | // Size_t |
| 26 | template<std::size_t N> |
| 27 | using mp_size_t = std::integral_constant<std::size_t, N>; |
| 28 | |
| 29 | // Boolean |
| 30 | template<bool B> |
| 31 | using mp_bool = std::integral_constant<bool, B>; |
| 32 | |
| 33 | // Identity |
| 34 | template<typename T> |
| 35 | struct mp_identity |
| 36 | { |
| 37 | using type = T; |
| 38 | }; |
| 39 | |
| 40 | // Turns struct into quoted metafunction |
| 41 | template<template<typename...> class F> |
| 42 | struct mp_quote_trait |
| 43 | { |
| 44 | template<typename... T> |
| 45 | using fn = typename F<T...>::type; |
| 46 | }; |
| 47 | |
| 48 | namespace detail { |
| 49 | // Size |
| 50 | template<typename L> |
| 51 | struct mp_size_impl {}; |
| 52 | |
| 53 | template<template<typename...> class L, typename... T> // Template template parameter must use class |
| 54 | struct mp_size_impl<L<T...>> |
| 55 | { |
| 56 | using type = std::integral_constant<std::size_t, sizeof...(T)>; |
| 57 | }; |
| 58 | } |
| 59 | |
| 60 | template<typename T> |
| 61 | using mp_size = typename detail::mp_size_impl<T>::type; |
| 62 | |
| 63 | namespace detail { |
| 64 | // Front |
| 65 | template<typename L> |
| 66 | struct mp_front_impl {}; |
| 67 | |
| 68 | template<template<typename...> class L, typename T1, typename... T> |
| 69 | struct mp_front_impl<L<T1, T...>> |
| 70 | { |
| 71 | using type = T1; |
| 72 | }; |
| 73 | } |
| 74 | |
| 75 | template<typename T> |
| 76 | using mp_front = typename detail::mp_front_impl<T>::type; |
| 77 | |
| 78 | namespace detail { |
| 79 | // At |
| 80 | // TODO - Use tree based lookup for larger typelists |
| 81 | // http://odinthenerd.blogspot.com/2017/04/tree-based-lookup-why-kvasirmpl-is.html |
| 82 | template<typename L, std::size_t> |
| 83 | struct mp_at_c {}; |
| 84 | |
| 85 | template<template<typename...> class L, typename T0, typename... T> |
| 86 | struct mp_at_c<L<T0, T...>, 0> |
| 87 | { |
| 88 | using type = T0; |
| 89 | }; |
| 90 | |
| 91 | template<template<typename...> class L, typename T0, typename T1, typename... T> |
| 92 | struct mp_at_c<L<T0, T1, T...>, 1> |
| 93 | { |
| 94 | using type = T1; |
| 95 | }; |
| 96 | |
| 97 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename... T> |
| 98 | struct mp_at_c<L<T0, T1, T2, T...>, 2> |
| 99 | { |
| 100 | using type = T2; |
| 101 | }; |
| 102 | |
| 103 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename... T> |
| 104 | struct mp_at_c<L<T0, T1, T2, T3, T...>, 3> |
| 105 | { |
| 106 | using type = T3; |
| 107 | }; |
| 108 | |
| 109 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename... T> |
| 110 | struct mp_at_c<L<T0, T1, T2, T3, T4, T...>, 4> |
| 111 | { |
| 112 | using type = T4; |
| 113 | }; |
| 114 | |
| 115 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename... T> |
| 116 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T...>, 5> |
| 117 | { |
| 118 | using type = T5; |
| 119 | }; |
| 120 | |
| 121 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 122 | typename... T> |
| 123 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T...>, 6> |
| 124 | { |
| 125 | using type = T6; |
| 126 | }; |
| 127 | |
| 128 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 129 | typename T7, typename... T> |
| 130 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T...>, 7> |
| 131 | { |
| 132 | using type = T7; |
| 133 | }; |
| 134 | |
| 135 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 136 | typename T7, typename T8, typename... T> |
| 137 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T...>, 8> |
| 138 | { |
| 139 | using type = T8; |
| 140 | }; |
| 141 | |
| 142 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 143 | typename T7, typename T8, typename T9, typename... T> |
| 144 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T...>, 9> |
| 145 | { |
| 146 | using type = T9; |
| 147 | }; |
| 148 | |
| 149 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 150 | typename T7, typename T8, typename T9, typename T10, typename... T> |
| 151 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T...>, 10> |
| 152 | { |
| 153 | using type = T10; |
| 154 | }; |
| 155 | |
| 156 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 157 | typename T7, typename T8, typename T9, typename T10, typename T11, typename... T> |
| 158 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T...>, 11> |
| 159 | { |
| 160 | using type = T11; |
| 161 | }; |
| 162 | |
| 163 | template<template<typename...> class L, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, |
| 164 | typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename... T> |
| 165 | struct mp_at_c<L<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T...>, 12> |
| 166 | { |
| 167 | using type = T12; |
| 168 | }; |
| 169 | } |
| 170 | |
| 171 | template<typename L, std::size_t Index> |
| 172 | using mp_at_c = typename detail::mp_at_c<L, Index>::type; |
| 173 | |
| 174 | template<typename L, typename Index> |
| 175 | using mp_at = typename detail::mp_at_c<L, Index::value>::type; |
| 176 | |
| 177 | // Back |
| 178 | template<typename L> |
| 179 | using mp_back = mp_at_c<L, mp_size<L>::value - 1>; |
| 180 | |
| 181 | namespace detail { |
| 182 | // Push back |
| 183 | template<typename L, typename... T> |
| 184 | struct mp_push_back_impl {}; |
| 185 | |
| 186 | template<template<typename...> class L, typename... U, typename... T> |
| 187 | struct mp_push_back_impl<L<U...>, T...> |
| 188 | { |
| 189 | using type = L<U..., T...>; |
| 190 | }; |
| 191 | } |
| 192 | |
| 193 | template<typename L, typename... T> |
| 194 | using mp_push_back = typename detail::mp_push_back_impl<L, T...>::type; |
| 195 | |
| 196 | namespace detail { |
| 197 | // Push front |
| 198 | template<typename L, typename... T> |
| 199 | struct mp_push_front_impl {}; |
| 200 | |
| 201 | template<template<typename...> class L, typename... U, typename... T> |
| 202 | struct mp_push_front_impl<L<U...>, T...> |
| 203 | { |
| 204 | using type = L<T..., U...>; |
| 205 | }; |
| 206 | } |
| 207 | |
| 208 | template<typename L, typename... T> |
| 209 | using mp_push_front = typename detail::mp_push_front_impl<L, T...>::type; |
| 210 | |
| 211 | namespace detail{ |
| 212 | // If |
| 213 | template<bool C, typename T, typename... E> |
| 214 | struct mp_if_c_impl{}; |
| 215 | |
| 216 | template<typename T, typename... E> |
| 217 | struct mp_if_c_impl<true, T, E...> |
| 218 | { |
| 219 | using type = T; |
| 220 | }; |
| 221 | |
| 222 | template<typename T, typename E> |
| 223 | struct mp_if_c_impl<false, T, E> |
| 224 | { |
| 225 | using type = E; |
| 226 | }; |
| 227 | } |
| 228 | |
| 229 | template<bool C, typename T, typename... E> |
| 230 | using mp_if_c = typename detail::mp_if_c_impl<C, T, E...>::type; |
| 231 | |
| 232 | template<typename C, typename T, typename... E> |
| 233 | using mp_if = typename detail::mp_if_c_impl<static_cast<bool>(C::value), T, E...>::type; |
| 234 | |
| 235 | namespace detail { |
| 236 | // Find if |
| 237 | template<typename L, template<typename...> class P> |
| 238 | struct mp_find_if_impl {}; |
| 239 | |
| 240 | template<template<typename...> class L, template<typename...> class P> |
| 241 | struct mp_find_if_impl<L<>, P> |
| 242 | { |
| 243 | using type = mp_size_t<0>; |
| 244 | }; |
| 245 | |
| 246 | template<typename L, template<typename...> class P> |
| 247 | struct mp_find_if_impl_2 |
| 248 | { |
| 249 | using r = typename mp_find_if_impl<L, P>::type; |
| 250 | using type = mp_size_t<1 + r::value>; |
| 251 | }; |
| 252 | |
| 253 | template<template<typename...> class L, typename T1, typename... T, template<typename...> class P> |
| 254 | struct mp_find_if_impl<L<T1, T...>, P> |
| 255 | { |
| 256 | using type = typename mp_if<P<T1>, mp_identity<mp_size_t<0>>, mp_find_if_impl_2<mp_list<T...>, P>>::type; |
| 257 | }; |
| 258 | } |
| 259 | |
| 260 | template<typename L, template<typename...> class P> |
| 261 | using mp_find_if = typename detail::mp_find_if_impl<L, P>::type; |
| 262 | |
| 263 | template<typename L, typename Q> |
| 264 | using mp_find_if_q = mp_find_if<L, Q::template fn>; |
| 265 | |
| 266 | namespace detail { |
| 267 | // Append |
| 268 | template<typename... L> |
| 269 | struct mp_append_impl {}; |
| 270 | |
| 271 | template<> |
| 272 | struct mp_append_impl<> |
| 273 | { |
| 274 | using type = mp_list<>; |
| 275 | }; |
| 276 | |
| 277 | template<template<typename...> class L, typename... T> |
| 278 | struct mp_append_impl<L<T...>> |
| 279 | { |
| 280 | using type = L<T...>; |
| 281 | }; |
| 282 | |
| 283 | template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2> |
| 284 | struct mp_append_impl<L1<T1...>, L2<T2...>> |
| 285 | { |
| 286 | using type = L1<T1..., T2...>; |
| 287 | }; |
| 288 | |
| 289 | template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, |
| 290 | template<typename...> class L3, typename... T3> |
| 291 | struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>> |
| 292 | { |
| 293 | using type = L1<T1..., T2..., T3...>; |
| 294 | }; |
| 295 | |
| 296 | template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, |
| 297 | template<typename...> class L3, typename... T3, template<typename...> class L4, typename... T4> |
| 298 | struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>> |
| 299 | { |
| 300 | using type = L1<T1..., T2..., T3..., T4...>; |
| 301 | }; |
| 302 | |
| 303 | template<template<typename...> class L1, typename... T1, template<typename...> class L2, typename... T2, |
| 304 | template<typename...> class L3, typename... T3, template<typename...> class L4, typename... T4, |
| 305 | template<typename...> class L5, typename... T5, typename... Lr> |
| 306 | struct mp_append_impl<L1<T1...>, L2<T2...>, L3<T3...>, L4<T4...>, L5<T5...>, Lr...> |
| 307 | { |
| 308 | using type = typename mp_append_impl<L1<T1..., T2..., T3..., T4..., T5...>, Lr...>::type; |
| 309 | }; |
| 310 | } |
| 311 | |
| 312 | template<typename... L> |
| 313 | using mp_append = typename detail::mp_append_impl<L...>::type; |
| 314 | |
| 315 | namespace detail { |
| 316 | // Remove if |
| 317 | template<typename L, template<typename...> class P> |
| 318 | struct mp_remove_if_impl{}; |
| 319 | |
| 320 | template<template<typename...> class L, typename... T, template<typename...> class P> |
| 321 | struct mp_remove_if_impl<L<T...>, P> |
| 322 | { |
| 323 | template<typename U> |
| 324 | struct _f |
| 325 | { |
| 326 | using type = mp_if<P<U>, mp_list<>, mp_list<U>>; |
| 327 | }; |
| 328 | |
| 329 | using type = mp_append<L<>, typename _f<T>::type...>; |
| 330 | }; |
| 331 | } |
| 332 | |
| 333 | template<typename L, template<class...> class P> |
| 334 | using mp_remove_if = typename detail::mp_remove_if_impl<L, P>::type; |
| 335 | |
| 336 | template<typename L, typename Q> |
| 337 | using mp_remove_if_q = mp_remove_if<L, Q::template fn>; |
| 338 | |
| 339 | // Index sequence |
| 340 | // Use C++14 index sequence if available |
| 341 | #if defined(__cpp_lib_integer_sequence) && (__cpp_lib_integer_sequence >= 201304) |
| 342 | template<std::size_t... Index> |
| 343 | using index_sequence = std::index_sequence<Index...>; |
| 344 | |
| 345 | template<std::size_t N> |
| 346 | using make_index_sequence = std::make_index_sequence<N>; |
| 347 | |
| 348 | template<typename... T> |
| 349 | using index_sequence_for = std::index_sequence_for<T...>; |
| 350 | |
| 351 | #else |
| 352 | |
| 353 | template<typename T, T... Index> |
| 354 | struct integer_sequence {}; |
| 355 | |
| 356 | template<std::size_t... Index> |
| 357 | using index_sequence = integer_sequence<std::size_t, Index...>; |
| 358 | |
| 359 | namespace detail { |
| 360 | |
| 361 | template<bool C, typename T, typename E> |
| 362 | struct iseq_if_c_impl {}; |
| 363 | |
| 364 | template<typename T, typename F> |
| 365 | struct iseq_if_c_impl<true, T, F> |
| 366 | { |
| 367 | using type = T; |
| 368 | }; |
| 369 | |
| 370 | template<typename T, typename F> |
| 371 | struct iseq_if_c_impl<false, T, F> |
| 372 | { |
| 373 | using type = F; |
| 374 | }; |
| 375 | |
| 376 | template<bool C, typename T, typename F> |
| 377 | using iseq_if_c = typename iseq_if_c_impl<C, T, F>::type; |
| 378 | |
| 379 | template<typename T> |
| 380 | struct iseq_identity |
| 381 | { |
| 382 | using type = T; |
| 383 | }; |
| 384 | |
| 385 | template<typename T1, typename T2> |
| 386 | struct append_integer_sequence {}; |
| 387 | |
| 388 | template<typename T, T... Index, T... J> |
| 389 | struct append_integer_sequence<integer_sequence<T, Index...>, integer_sequence<T, J...>> |
| 390 | { |
| 391 | using type = integer_sequence<T, Index..., (J + sizeof...(Index))...>; |
| 392 | }; |
| 393 | |
| 394 | template<typename T, T N> |
| 395 | struct make_integer_sequence_impl; |
| 396 | |
| 397 | template<typename T, T N> |
| 398 | class make_integer_sequence_impl_ |
| 399 | { |
| 400 | private: |
| 401 | static_assert(N >= 0, "N must not be negative" ); |
| 402 | |
| 403 | static constexpr T M = N / 2; |
| 404 | static constexpr T R = N % 2; |
| 405 | |
| 406 | using seq1 = typename make_integer_sequence_impl<T, M>::type; |
| 407 | using seq2 = typename append_integer_sequence<seq1, seq1>::type; |
| 408 | using seq3 = typename make_integer_sequence_impl<T, R>::type; |
| 409 | using seq4 = typename append_integer_sequence<seq2, seq3>::type; |
| 410 | |
| 411 | public: |
| 412 | using type = seq4; |
| 413 | }; |
| 414 | |
| 415 | template<typename T, T N> |
| 416 | struct make_integer_sequence_impl |
| 417 | { |
| 418 | using type = typename iseq_if_c<N == 0, |
| 419 | iseq_identity<integer_sequence<T>>, |
| 420 | iseq_if_c<N == 1, iseq_identity<integer_sequence<T, 0>>, |
| 421 | make_integer_sequence_impl_<T, N>>>::type; |
| 422 | }; |
| 423 | |
| 424 | } // namespace detail |
| 425 | |
| 426 | template<typename T, T N> |
| 427 | using make_integer_sequence = typename detail::make_integer_sequence_impl<T, N>::type; |
| 428 | |
| 429 | template<std::size_t N> |
| 430 | using make_index_sequence = make_integer_sequence<std::size_t, N>; |
| 431 | |
| 432 | template<typename... T> |
| 433 | using index_sequence_for = make_integer_sequence<std::size_t, sizeof...(T)>; |
| 434 | |
| 435 | #endif |
| 436 | |
| 437 | }}}} // namespaces |
| 438 | |
| 439 | #endif // BOOST_MATH_TOOLS_MP |
| 440 | |