Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

879 lines
26 KiB

  1. /*!
  2. * \file typelist.h
  3. * \brief A template parameter "container"
  4. */
  5. #ifndef __utl_meta_typelist_h__
  6. #define __utl_meta_typelist_h__
  7. #include <utl/core/impl.h>
  8. #include <utl/meta/basic.h>
  9. #include <utl/meta/detection.h>
  10. #include <utl/meta/invoke.h>
  11. #include <utl/meta/sfinae.h>
  12. /*!
  13. * \ingroup meta
  14. * \defgroup typelist typelist
  15. *
  16. * The idea came from MPL's sequence concept [1] and from N4115 [2].
  17. * In addition to N4115's name "packer" we just prefer a name which is an object, not a subject.
  18. * This way the name gives the feeling of a container and smells like Python.\n
  19. *
  20. * In addition to tuple we lack members, so typelist could serve as an empty base class,
  21. * and an object of the ultimate type could always be instantiated
  22. * (even if the parameter typelist contains void or some type that lacks
  23. * a default constructor).\n
  24. *
  25. * \code{.cpp}
  26. * using l1 = typelist<int, void*, double, void>;
  27. * l1 a {};
  28. * \endcode
  29. *
  30. * boost::hana [3] suggests a more powerful scheme were type invariant structures can be used
  31. * for metaprograming also. This lib does not need (yet) this kind of power (we afraid the
  32. * responsibility that comes along).\n
  33. * So a simple python-like list with some extra vector-like
  34. * element access functionalities and no iterators is good enough(for now).
  35. *
  36. * [1]: https://www.boost.org/doc/ \n
  37. * [2]: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4115.html \n
  38. * [3]: https://github.com/boostorg/hana \n
  39. */
  40. //! @{
  41. namespace utl {
  42. namespace meta {
  43. /*!
  44. * \brief
  45. * The \c typelist 's implementation container
  46. * \tparam Ts The \a contained types
  47. */
  48. template <typename... Ts>
  49. struct typelist {
  50. using type = typelist; //!< act as identity
  51. //! \return sizeof...(Ts)
  52. static constexpr size_t size() noexcept {
  53. return sizeof...(Ts);
  54. }
  55. //! \return true if empty
  56. static constexpr bool empty() noexcept {
  57. return (sizeof...(Ts) == 0);
  58. }
  59. // ======= times utility =======
  60. private:
  61. template <typename... > struct cat_ { };
  62. template <typename... L1, typename... L2>
  63. struct cat_<typelist<L1...>, typelist<L2...>> {
  64. using type = typelist<L1..., L2...>;
  65. };
  66. template <size_t N, typename ...T>
  67. struct times_ {
  68. //static_assert( N >= 0, "Cannot make typelist of negative length" );
  69. using type = eval<
  70. cat_<
  71. eval<times_<N/2, T...>>,
  72. eval<times_<N - N/2, T...>>
  73. >
  74. >;
  75. };
  76. template <typename ...T>
  77. struct times_<1, T...> {
  78. using type = typelist<T...>;
  79. };
  80. template <typename ...T>
  81. struct times_<0, T...> {
  82. using type = typelist<>;
  83. };
  84. public:
  85. /*!
  86. * Generate typelist<Ts..., Ts..., ...> of size \c N arguments.
  87. *
  88. * \code{.cpp}
  89. * static_assert (
  90. * std::is_same<typelist<int, char>::times<2>,
  91. * typelist<int, char, int, char>
  92. * >, "" );
  93. * \endcode
  94. * complexity \f$ O(logN) \f$
  95. */
  96. template<size_t N>
  97. using times = eval<
  98. times_<N, Ts...>
  99. >;
  100. };
  101. /*!
  102. * An integral constant wrapper that is the size of the \c meta::typelist
  103. *
  104. * Complexity \f$ O(1) \f$.
  105. *
  106. * \tparam List A typelist
  107. * \return The size of the typelist
  108. */
  109. template <typename List>
  110. using size = size_<List::size()>;
  111. /*!
  112. * An Boolean constant wrapper that returns if the typelist is empty
  113. *
  114. * Complexity \f$ O(1) \f$.
  115. *
  116. * \tparam List A typelist
  117. * \return Empty or not
  118. */
  119. template <typename List>
  120. using empty = bool_<List::empty()>;
  121. //! pair
  122. //! A special typelist with only 2 Types
  123. template <typename T1, typename T2>
  124. using pair = typelist<T1, T2>;
  125. //! \name repeat
  126. //! @{
  127. /*!
  128. * A wrapper to typelist<>::times<> utility for integer argument \c N
  129. */
  130. template <size_t N, typename ...Ts>
  131. using repeat_c = typename typelist<Ts...>::template times<N>;
  132. /*!
  133. * A wrapper to typelist<>::times<> utility for integral_c argument \c N
  134. */
  135. template <typename N, typename ...Ts>
  136. using repeat = repeat_c<N::type::value, Ts...>;
  137. //! @}
  138. /*!
  139. * \name Apply
  140. * An analogous to apply() implementation for tuples. We just use
  141. * Our typelist<> and integer_sequence<> types.
  142. */
  143. //! @{
  144. namespace apply_impl {
  145. template <typename Fn, typename Seq>
  146. struct apply_ { };
  147. // Sequence == typelist<>
  148. template<typename Fn, typename ...List>
  149. struct apply_<Fn, typelist<List...>> {
  150. using type = invoke<Fn, List...>;
  151. };
  152. // Sequence == integer_sequence<>
  153. template <typename Fn, typename T, T... Is>
  154. struct apply_<Fn, integer_sequence<T, Is...>> {
  155. using type = invoke<Fn, integral_<T, Is>...>;
  156. };
  157. }
  158. /*!
  159. * \brief
  160. * Apply the Invocable \c Fn using the types in the type \c Seq as arguments.
  161. * \note
  162. * This is the opposed operation of typelist<Ts...>
  163. *
  164. * If \c Seq == typelist<> then unpack typelist and apply to \c Fn \n
  165. * It \c Seq == integer_sequence<> then unpack and use the integral_c<> of each integer
  166. */
  167. template <typename Fn, typename Seq>
  168. using apply = apply_impl::apply_<Fn, Seq>;
  169. template <typename Fn, typename Seq>
  170. using apply_t = eval <apply<Fn, Seq>>;
  171. //! @}
  172. /*
  173. * ========= element access ========
  174. */
  175. //! \name random element access
  176. //! @{
  177. namespace at_impl {
  178. template <typename T> struct _add_pointer { using type = T*; };
  179. template <typename T> using add_pointer = eval < _add_pointer <T> >;
  180. template <typename ...>
  181. struct at_head_ { };
  182. template <typename... voids>
  183. struct at_head_ <typelist<voids...>> {
  184. // successful selection N voids, one T* and the rest
  185. template <typename T> static constexpr T select(voids..., T*, ...);
  186. // selection on error
  187. static constexpr nil_ select (...);
  188. };
  189. template<typename List, index_t N>
  190. struct at_ { };
  191. template<typename... List, index_t N>
  192. struct at_<typelist<List...>, N> {
  193. using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
  194. using type = decltype(
  195. head_::select(static_cast<add_pointer<List>>(nullptr)...) //< pass all as List*...
  196. );
  197. };
  198. }
  199. /*!
  200. * Return the \c N th element in the \c meta::typelist \c List.
  201. *
  202. * Complexity \f$ O(logN) \f$.
  203. */
  204. template <typename List, index_t N>
  205. using at_c = eval<
  206. at_impl::at_<List, N>
  207. >;
  208. /*!
  209. * Return the \c N th element in the \c meta::typelist \c List.
  210. *
  211. * Complexity \f$ O(logN) \f$.
  212. */
  213. template <typename List, typename N>
  214. using at = at_c<List, N::type::value>;
  215. //!@}
  216. //! \name front
  217. //! @{
  218. namespace front_impl {
  219. template <typename L>
  220. struct front_ { };
  221. template <typename Head, typename... Tail>
  222. struct front_<typelist<Head, Tail...>> {
  223. using type = Head;
  224. };
  225. }
  226. //! Return the first element in \c meta::typelist \c List.
  227. //!
  228. //! Complexity \f$ O(1) \f$.
  229. template <typename List>
  230. using front = eval<
  231. front_impl::front_<List>
  232. >;
  233. //! @}
  234. //! \name back
  235. //! @{
  236. namespace back_impl {
  237. template <typename List>
  238. struct back_ { using type = nil_; };
  239. template <typename Head, typename... Tail>
  240. struct back_<typelist<Head, Tail...>> {
  241. using type = at_c <
  242. typelist<Head, Tail...>, sizeof...(Tail)
  243. >;
  244. };
  245. }
  246. //! Return the last element in \c meta::typelist \c List.
  247. //!
  248. //! Complexity \f$ O(N) \f$.
  249. template <typename List>
  250. using back = eval<
  251. back_impl::back_<List>
  252. >;
  253. //! @}
  254. /*
  255. * ========= typelist operations =========
  256. */
  257. //! \name Concatenation
  258. //! @{
  259. namespace cat_impl {
  260. template <typename... Lists>
  261. struct cat_ { };
  262. template <>
  263. struct cat_<> {
  264. using type = typelist<>;
  265. };
  266. template <typename... L1>
  267. struct cat_<typelist<L1...>> {
  268. using type = typelist<L1...>;
  269. };
  270. template <typename... L1, typename... L2>
  271. struct cat_<typelist<L1...>, typelist<L2...>> {
  272. using type = typelist<L1..., L2...>;
  273. };
  274. template <typename... L1, typename... L2, typename... Ln>
  275. struct cat_<typelist<L1...>, typelist<L2...>, Ln...>
  276. : cat_ <typelist<L1..., L2...>, Ln...> { };
  277. }
  278. /*!
  279. * Transformation that concatenates several lists into a single typelist.
  280. * The parameters must all be instantiations of \c meta::typelist.
  281. *
  282. * Complexity: \f$ O(N) \f$
  283. * where \f$ N \f$ is the number of lists passed to the algorithm.
  284. */
  285. template <typename... Lists>
  286. using cat = eval<
  287. cat_impl::cat_<Lists...>
  288. >;
  289. //! @}
  290. //! \name Fold
  291. //! @{
  292. namespace fold_impl {
  293. // fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
  294. template<typename, typename, typename>
  295. struct fold_ { }; // ill formed
  296. // recursive call
  297. template<typename Head, typename... Tail,
  298. typename V,
  299. typename Fn>
  300. struct fold_<typelist<Head, Tail...>, V, Fn> {
  301. // recursive call of fold_ by consuming typelist and invoking Fn
  302. using type = eval<
  303. fold_<
  304. typelist<Tail...>,
  305. invoke<Fn, V, Head>,
  306. Fn
  307. >
  308. >;
  309. };
  310. // termination call
  311. template<typename V0, typename Fn>
  312. struct fold_<typelist<>, V0, Fn> {
  313. using type = V0;
  314. };
  315. }
  316. /*!
  317. * transform the \c List to a new one by doing a left fold using binary Invocable \c Fn
  318. * and initial value \c V
  319. *
  320. * Complexity \f$ O(N) \f$
  321. * \code{.cpp}
  322. * fold<typelist<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
  323. * fold<typelist<>, V, F> == V
  324. * \endcode
  325. * \tparam List The list to fold
  326. * \tparam V The initial item feeded to Fn
  327. * \tparam Fn The binary Invocable
  328. */
  329. template <typename List, typename V, typename Fn>
  330. using fold = eval<fold_impl::fold_<List, V, Fn>>;
  331. //! accumulate is an stl name for fold
  332. template <typename List, typename V, typename Fn>
  333. using accumulate = fold<List, V, Fn>;
  334. namespace rev_fold_impl {
  335. // rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
  336. template<typename, typename, typename>
  337. struct rev_fold_ { }; // ill formed
  338. // recursive call
  339. template<typename Head, typename... Tail,
  340. typename V,
  341. typename Fn>
  342. struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
  343. // recursive call inside invoke. This way the 2nd argument of Fn
  344. // becoming the recursive "thing", inside Fn<>
  345. using type = invoke <
  346. Fn, Head, eval<
  347. rev_fold_ <
  348. typelist<Tail...>,
  349. V,
  350. Fn
  351. >>
  352. >;
  353. };
  354. // pre-termination call
  355. template<typename Tail, typename V, typename Fn>
  356. struct rev_fold_ <typelist<Tail>, V, Fn> {
  357. using type = invoke<Fn, Tail, V>;
  358. };
  359. // termination call
  360. template<typename V, typename Fn>
  361. struct rev_fold_ <typelist<>, V, Fn> {
  362. using type = V;
  363. };
  364. }
  365. /*!
  366. * transform the \c List to a new one by doing a right fold using binary Invocable \c Fn
  367. * and initial value \c V
  368. *
  369. * Complexity \f$ O(N) \f$
  370. * \code{.cpp}
  371. * rev_fold<typelist<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
  372. * rev_fold<typelist<>, V, F> == V
  373. * \endcode
  374. * \tparam List The list to fold
  375. * \tparam V The initial item fed to Fn
  376. * \tparam Fn The binary Invocable
  377. */
  378. template <typename List, typename V, typename Fn>
  379. using rev_fold = eval<
  380. rev_fold_impl::rev_fold_<List, V, Fn>
  381. >;
  382. //! @}
  383. /*!
  384. * Return a new \c typelist by adding the elements \c Ts to the front of \c List.
  385. *
  386. * Complexity \f$ O(1) \f$
  387. */
  388. template <typename List, typename... Ts>
  389. using push_front = eval<
  390. apply <
  391. bind_front<quote<typelist>, Ts...>, List
  392. >
  393. >;
  394. /*!
  395. * Return a new \c typelist by adding the elements \c Ts to the back of \c List.
  396. *
  397. * Complexity \f$ O(1) \f$
  398. */
  399. template <typename List, typename... Ts>
  400. using push_back = eval<
  401. apply <
  402. bind_back<quote<typelist>, Ts...>, List
  403. >
  404. >;
  405. //! \name reverse
  406. //! @{
  407. namespace reverse_impl {
  408. template <typename List, typename V = typelist<>>
  409. struct reverse_ {
  410. using type = fold<List, V, quote<push_front>>;
  411. };
  412. }
  413. /*!
  414. * Return a new \c typelist by reversing the elements in the list \c List.
  415. *
  416. * Complexity \f$ O(N) \f$
  417. */
  418. template <typename List>
  419. using reverse = eval<
  420. reverse_impl::reverse_<List>
  421. >;
  422. //! @}
  423. //! \name pop_front
  424. //! @{
  425. namespace pop_front_impl {
  426. template <typename List>
  427. struct pop_front_ { };
  428. template <typename Head, typename... Tail>
  429. struct pop_front_<typelist <Head, Tail...>> {
  430. using type = typelist<Tail...>;
  431. };
  432. }
  433. /*!
  434. * Return a new \c typelist by removing the first element from the
  435. * front of \c List.
  436. *
  437. * Complexity \f$ O(1) \f$
  438. */
  439. template <typename List>
  440. using pop_front = eval<
  441. pop_front_impl::pop_front_<List>
  442. >;
  443. //! @}
  444. //! \name pop_back
  445. //! @{
  446. namespace pop_back_impl {
  447. template <typename List>
  448. struct pop_back_ {
  449. using type = reverse<
  450. pop_front<reverse<List>>
  451. >;
  452. };
  453. }
  454. /*!
  455. * Return a new \c typelist by removing the last element from the \c List.
  456. *
  457. * Complexity \f$ O(N) \f$.
  458. * \note
  459. * This operation, in addition from other push/pop operations, is
  460. * heavy(2 reverse operations).
  461. */
  462. template <typename List>
  463. using pop_back = eval <
  464. pop_back_impl::pop_back_<List>
  465. >;
  466. //! @}
  467. //! \name Transform
  468. //! @{
  469. namespace transform_impl {
  470. template <typename, typename = void>
  471. struct transform_ { };
  472. template <typename... Ts, typename Fn>
  473. struct transform_<typelist<typelist<Ts...>, Fn>,
  474. void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
  475. using type = typelist<
  476. invoke_t<Fn, Ts>...
  477. >;
  478. };
  479. template <typename... Ts0, typename... Ts1, typename Fn>
  480. struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
  481. void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
  482. using type = typelist<
  483. invoke_t<Fn, Ts0, Ts1>...
  484. >;
  485. };
  486. }
  487. /*!
  488. * Transformation by applying an invocable \c Fn to one or two lists
  489. * and return the resulting typelist
  490. *
  491. * Complexity \f$ O(N) \f$.
  492. * \code{.cpp}
  493. * using l1 = typelist<char, int, ...>;
  494. * using l2 = typelist<void, double, ...>;
  495. * using r1 = transform<l1, F1>; // F1, unary invocable
  496. * using r2 = transform<l1, l2, F2>; // F2, binary invocable
  497. * \endcode
  498. */
  499. template <typename... Args>
  500. using transform = eval<
  501. transform_impl::transform_<typelist<Args...>>
  502. >;
  503. //! @}
  504. //! \name Transform lazy
  505. //! @{
  506. namespace transform_lazy_impl {
  507. template <typename, typename = void>
  508. struct transform_lazy_ { };
  509. // Match for Unary Fn with one typelist
  510. template <typename... Ts, typename Fn>
  511. struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
  512. void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
  513. using type = typelist<
  514. invoke<Fn, Ts>...
  515. >;
  516. };
  517. // Match for Binary Fn with two typelists
  518. template <typename... Ts0, typename... Ts1, typename Fn>
  519. struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
  520. void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
  521. using type = typelist<
  522. invoke<Fn, Ts0, Ts1>...
  523. >;
  524. };
  525. }
  526. /*!
  527. * Transformation by applying an invocable \c Fn to one or two lists
  528. * and return a typelist containing the invocables with their arguments,
  529. * not their resulting types.
  530. *
  531. * Complexity \f$ O(N) \f$
  532. *
  533. * \code{.cpp}
  534. * using l1 = typelist<char, int, ...>;
  535. * using l2 = typelist<void, void, ...>;
  536. * using r1 = transform<l1, F1>; // F1, unary invocable
  537. * using r2 = transform<l1, l2, F2>; // F2, binary invocable
  538. * \endcode
  539. */
  540. template <typename... Args>
  541. using transform_lazy = eval<
  542. transform_lazy_impl::transform_lazy_<typelist<Args...>>
  543. >;
  544. //! @}
  545. //! \name find_if, find
  546. //! @{
  547. namespace find_if_impl {
  548. template <typename, typename, index_t>
  549. struct find_if_ { };
  550. template<typename Head, typename... Tail, typename Fn, index_t N>
  551. struct find_if_<typelist<Head, Tail...>, Fn, N> {
  552. // Recursive call to find_if_ until Fn returns true_
  553. using type = if_ <
  554. invoke_t<Fn, Head>,
  555. index_<N>, // done, return current index
  556. eval<find_if_< // not done, re-call find_if_ with the Tail...
  557. typelist<Tail...>, Fn, N+1>
  558. >
  559. >;
  560. };
  561. // When empty or when we are one place after the last item return Npos
  562. template<typename Fn, index_t N>
  563. struct find_if_<typelist<>, Fn, N> {
  564. using type = Npos;
  565. };
  566. }
  567. /*!
  568. * Search for the first \c Item on the \c List for which the predicate \c Pred
  569. * returns true_ when `eval<invoke<Pred, Item>>`
  570. *
  571. * Complexity \f$ O(N) \f$
  572. *
  573. * \tparam List A typelist
  574. * \tparam Pred A Unary invocable predicate
  575. * \return An integral constant of index_t with the location of the first match,
  576. * or Npos otherwise.
  577. */
  578. template<typename List, typename Pred>
  579. using find_if = eval<
  580. find_if_impl::find_if_<List, Pred, 0>
  581. >;
  582. /*!
  583. * Search for the first occurrence of type \c T on a \c List
  584. */
  585. template <typename List, typename T>
  586. using find = find_if<List, same_as<T>>;
  587. //! @}
  588. //! \name seek_if
  589. //! @{
  590. namespace seek_if_impl {
  591. template <typename, typename, index_t>
  592. struct seek_if_ { };
  593. template<typename Head, typename... Tail, typename Fn, index_t N>
  594. struct seek_if_<typelist<Head, Tail...>, Fn, N> {
  595. // recursive call to seek_if_ until Fn returns true_
  596. using type = if_ <
  597. invoke_t<Fn, Head>,
  598. typelist<Head, Tail...>, // done, return the typelist starting from here
  599. eval<seek_if_< // not done, re-call seek_if_ with the Tail...
  600. typelist<Tail...>, Fn, N+1>
  601. >
  602. >;
  603. };
  604. // When empty or when we are one place after the last item return empty typelist
  605. template<typename Fn, index_t N>
  606. struct seek_if_<typelist<>, Fn, N> {
  607. using type = typelist<>;
  608. };
  609. }
  610. /*!
  611. * Search for the first \c Item on the \c List for which the predicate \c Pred
  612. * returns true_ when `eval<invoke<Pred, Item>>` and return the rest of the \c List
  613. * starting from that position as new typelist
  614. *
  615. * Complexity \f$ O(N) \f$
  616. *
  617. * \tparam List A typelist
  618. * \tparam Pred A Unary invocable predicate
  619. * \return An integral constant with the location of the first match, on Npos otherwise
  620. */
  621. template <typename List, typename Pred>
  622. using seek_if = eval<
  623. seek_if_impl::seek_if_<List, Pred, 0>
  624. >;
  625. /*!
  626. * Search for the first \c Item on the \c List of type \c T and return the rest
  627. * of the \c List starting from that position as new typelist
  628. */
  629. template <typename List, typename T>
  630. using seek = seek_if <List, same_as<T>>;
  631. //! @}
  632. template <typename List, typename Pred>
  633. using first_if = front<seek_if<List, Pred>>;
  634. //! \name count_if
  635. //! @{
  636. namespace count_if_impl {
  637. template <typename, typename, size_t>
  638. struct count_if_ { };
  639. template<typename Head, typename... Tail, typename Fn, size_t N>
  640. struct count_if_<typelist<Head, Tail...>, Fn, N> {
  641. // Recursive call to count_if_ up to the end of List, counting all invokes of Fn
  642. // returning true_
  643. using type = if_ <
  644. invoke_t<Fn, Head>,
  645. eval<
  646. count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
  647. >,
  648. eval<
  649. count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
  650. >
  651. >;
  652. };
  653. // At the end of the List return the counter
  654. template<typename Fn, size_t N>
  655. struct count_if_<typelist<>, Fn, N> {
  656. using type = size_<N>;
  657. };
  658. }
  659. /*!
  660. * Count all \c Items on the \c List for which the predicate \c Pred
  661. * returns true_ when `eval<invoke<Pred, Item>>`
  662. *
  663. * Complexity \f$ O(N) \f$
  664. *
  665. * \tparam List A typelist
  666. * \tparam Pred A Unary invocable predicate
  667. * \return The total count of occurrences as an integral constant of size_t
  668. */
  669. template <typename List, typename Pred>
  670. using count_if = eval<
  671. count_if_impl::count_if_<List, Pred, 0>
  672. >;
  673. /*!
  674. * Count all occurrences of type \c T int \c List
  675. */
  676. template <typename List, typename T>
  677. using count = count_if<List, same_as<T>>;
  678. //! @}
  679. //! \name filter
  680. //! @{
  681. namespace filter_impl {
  682. template <typename, typename, typename>
  683. struct filter_ { };
  684. template<typename Head, typename... Tail, typename Fn, typename L>
  685. struct filter_<typelist<Head, Tail...>, Fn, L> {
  686. // Recursive call to filter_ up to the end of the List, creating a new list
  687. // of items for which the invoke of Fn returns true_
  688. using type = if_ <
  689. invoke_t <Fn, Head>,
  690. eval<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
  691. eval<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
  692. >;
  693. };
  694. // At the end return the produced list
  695. template<typename Fn, typename L>
  696. struct filter_<typelist<>, Fn, L> {
  697. using type = L;
  698. };
  699. }
  700. /*!
  701. * Return a new typelist with elements, the elements of \c List that satisfy the
  702. * invocable \c Pred such that `eval<invoke<Pred, Item>>` is \c true_
  703. *
  704. * Complexity \f$ O(N) \f$
  705. *
  706. * \tparam List The input typelist
  707. * \tparam Pred A unary invocable predicate
  708. */
  709. template <typename List, typename Pred>
  710. using filter = eval<
  711. filter_impl::filter_<List, Pred, typelist<>>
  712. >;
  713. //! @}
  714. //! \name replace
  715. //! @{
  716. namespace replace_if_impl {
  717. template <typename, typename, typename, typename>
  718. struct replace_if_ { };
  719. template <typename Head, typename... Tail, typename Fn, typename T, typename Ret>
  720. struct replace_if_<typelist<Head, Tail...>, Fn, T, Ret> {
  721. // Recursive call to replace_if_ up to the end of the List, creating a new list
  722. // of items based on invocation of Fn
  723. using type = if_ <
  724. invoke_t<Fn, Head>,
  725. eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
  726. eval<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
  727. >;
  728. };
  729. // At the end return the produced list
  730. template <typename Fn, typename T, typename Ret>
  731. struct replace_if_ <typelist<>, Fn, T, Ret> {
  732. using type = Ret;
  733. };
  734. }
  735. /*!
  736. * Return a new typelist where all the instances for which the invocation of\c Pred
  737. * returns \c true_, are replaced with \c T
  738. *
  739. * Complexity \f$ O(N) \f$
  740. *
  741. * \tparam List The input typelist
  742. * \tparam Pred A unary invocable predicate
  743. * \tparam T The new type to replace the item of the \c List, when eval<invoke<Pred, Item>>
  744. * returns \c true_
  745. */
  746. template<typename List, typename Pred, typename T>
  747. using replace_if = eval<
  748. replace_if_impl::replace_if_<List, Pred, T, typelist<>>
  749. >;
  750. //! Alias wrapper that returns a new \c typelist where all instances of type \c T have
  751. //! been replaced with \c U.
  752. template <typename List, typename T, typename U>
  753. using replace = eval <
  754. replace_if <List, same_as<T>, U>
  755. >;
  756. //! @}
  757. //! Returns \c true_ if \c Pred returns \c true_ for all the elements in the \c List or if the
  758. //! \c List is empty and \c false_ otherwise.
  759. template <typename List, typename Pred>
  760. using all_of = if_ <
  761. empty <List>,
  762. false_,
  763. empty <
  764. filter <List, compose<quote<not_>, Pred>>
  765. >
  766. >;
  767. //! Returns \c true_ if \c Pred returns \c true_ for any of the elements in the \c List
  768. //! and \c false_ otherwise.
  769. template <typename List, typename Pred>
  770. using any_of = not_<
  771. empty<filter <List, Pred>>
  772. >;
  773. //! Returns \c true_ if \c Pred returns \c false_ for all the elements in the \c List
  774. //! or if the \c List is empty and \c false otherwise.
  775. template <typename List, typename Pred>
  776. using none_of = empty<
  777. filter <List, Pred>
  778. >;
  779. }}
  780. //! @}
  781. #endif /* __utl_meta_typelist_h__ */