Micro template library A library for building device drivers
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 

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