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.
 
 
 
 

867 lines
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/void.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__ */