Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

879 lignes
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__ */