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.
 
 
 
 

867 lignes
26 KiB

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