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.
 
 
 
 

865 lines
26 KiB

  1. /*!
  2. * \file typelist.h
  3. * \brief A template parameter "container"
  4. *
  5. * Copyright (C) 2018 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] suggest 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 come 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_t_<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. */
  143. //! @{
  144. namespace apply_impl {
  145. template <typename Fn, typename Seq>
  146. struct apply_ { };
  147. //! \p 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_c<T, Is>...>;
  156. };
  157. }
  158. /*!
  159. * Apply the Invocable \p Fn using the types in the type \p Seq as arguments.
  160. * \note
  161. * This is the opposed operation of typelist<Ts...>
  162. *
  163. * If \p Seq == typelist<> then
  164. * Unpack typelist and apply to \c Fn
  165. * It \p Seq == integer_sequence<> then
  166. * Unpack and use the integral_c<> of each integer
  167. */
  168. template <typename Fn, typename Seq>
  169. using apply = apply_impl::apply_<Fn, Seq>;
  170. //! @}
  171. /*
  172. * ========= element access ========
  173. */
  174. //! at: random element access
  175. //! @{
  176. namespace at_impl {
  177. template <typename T> struct _as_pointer__ { using type = T*; };
  178. template <typename T> struct _as_pointer__<T*> { using type = T*; };
  179. template <typename T> using as_pointer_ = type_<
  180. _as_pointer__<T>
  181. >;
  182. template <typename ...>
  183. struct at_head_ { };
  184. template <typename... voids>
  185. struct at_head_ <typelist<voids...>> {
  186. // successful selection N voids, one T* and the rest
  187. template <typename T> static constexpr T select(voids..., T*, ...);
  188. // selection on error
  189. static constexpr nil_ select (...);
  190. };
  191. template<typename List, index_t N>
  192. struct at_ { };
  193. template<typename... List, index_t N>
  194. struct at_<typelist<List...>, N> {
  195. using head_ = at_head_<typelist<void*>::times<N>>; //< make at_head_<> with N void*
  196. using type = decltype(
  197. head_::select(static_cast<as_pointer_<List>>(nullptr)...) //< pass all as List*...
  198. );
  199. };
  200. }
  201. /*!
  202. * Return the \p N th element in the \c meta::typelist \p List.
  203. *
  204. * Complexity \f$ O(N) \f$.
  205. */
  206. template <typename List, index_t N>
  207. using at_c = type_<
  208. at_impl::at_<List, N>
  209. >;
  210. /*!
  211. * Return the \p N th element in the \c meta::typelist \p List.
  212. *
  213. * Complexity \f$ O(N) \f$.
  214. */
  215. template <typename List, typename N>
  216. using at = at_c<List, N::type::value>;
  217. //!@}
  218. //! front
  219. //! @{
  220. namespace front_impl {
  221. template <typename L>
  222. struct front_ { };
  223. template <typename Head, typename... Tail>
  224. struct front_<typelist<Head, Tail...>> {
  225. using type = Head;
  226. };
  227. }
  228. //! Return the first element in \c meta::typelist \p List.
  229. //! Complexity \f$ O(1) \f$.
  230. template <typename List>
  231. using front = type_<
  232. front_impl::front_<List>
  233. >;
  234. //! @}
  235. //! back
  236. //! @{
  237. namespace back_impl {
  238. template <typename List>
  239. struct back_ { };
  240. template <typename Head, typename... Tail>
  241. struct back_<typelist<Head, Tail...>> {
  242. using type = at_c <
  243. typelist<Head, Tail...>, sizeof...(Tail)
  244. >;
  245. };
  246. }
  247. //! Return the last element in \c meta::typelist \p List.
  248. //! Complexity \f$ O(N) \f$.
  249. template <typename List>
  250. using back = type_<
  251. back_impl::back_<List>
  252. >;
  253. //! @}
  254. /*
  255. * ========= typelist operations =========
  256. */
  257. //! 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. * Complexity: \f$ O(N) \f$
  282. * where \f$ N \f$ is the number of lists passed to the algorithm.
  283. */
  284. template <typename... Lists>
  285. using cat = type_<
  286. cat_impl::cat_<Lists...>
  287. >;
  288. //! @}
  289. //! fold<List, V, Fn>, rev_fold<List, V, Fn>
  290. //! @{
  291. namespace fold_impl {
  292. // fold<<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
  293. template<typename, typename, typename>
  294. struct fold_ { }; // ill formed
  295. // recursive call
  296. template<typename Head, typename... Tail,
  297. typename V,
  298. typename Fn>
  299. struct fold_<typelist<Head, Tail...>, V, Fn> {
  300. // recursive call of fold_ by consuming typelist and invoking Fn
  301. using type = type_<
  302. fold_<
  303. typelist<Tail...>,
  304. invoke<Fn, V, Head>,
  305. Fn
  306. >
  307. >;
  308. };
  309. // termination call
  310. template<typename V0, typename Fn>
  311. struct fold_<typelist<>, V0, Fn> {
  312. using type = V0;
  313. };
  314. }
  315. /*!
  316. * transform the \p List to a new one by doing a left fold using binary Invocable \p Fn
  317. * and initial value \p V
  318. * Complexity \f$ O(N) \f$
  319. * \example
  320. * fold<typelist<T1, T2, T3>, V, F> == F<F<F<V, T1>, T2>, T3>
  321. * \example
  322. * fold<typelist<>, V, F> == V
  323. * \param List The list to fold
  324. * \param V The initial item feeded to Fn
  325. * \param Fn The binary Invocable
  326. */
  327. template <typename List, typename V, typename Fn>
  328. using fold = type_<fold_impl::fold_<List, V, Fn>>;
  329. //! accumulate is an stl name for fold
  330. template <typename List, typename V, typename Fn>
  331. using accumulate = fold<List, V, Fn>;
  332. namespace rev_fold_impl {
  333. // rev_fold<<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
  334. template<typename, typename, typename>
  335. struct rev_fold_ { }; // ill formed
  336. // recursive call
  337. template<typename Head, typename... Tail,
  338. typename V,
  339. typename Fn>
  340. struct rev_fold_<typelist<Head, Tail...>, V, Fn> {
  341. // recursive call inside invoke. This way the 2nd argument of Fn
  342. // becoming the recursive "thing", inside Fn<>
  343. using type = invoke <
  344. Fn, Head, type_<
  345. rev_fold_ <
  346. typelist<Tail...>,
  347. V,
  348. Fn
  349. >>
  350. >;
  351. };
  352. // pre-termination call
  353. template<typename Tail, typename V, typename Fn>
  354. struct rev_fold_ <typelist<Tail>, V, Fn> {
  355. using type = invoke<Fn, Tail, V>;
  356. };
  357. // termination call
  358. template<typename V, typename Fn>
  359. struct rev_fold_ <typelist<>, V, Fn> {
  360. using type = V;
  361. };
  362. }
  363. /*!
  364. * transform the \p List to a new one by doing a right fold using binary Invocable \p Fn
  365. * and initial value \p V
  366. * Complexity \f$ O(N) \f$
  367. * \example
  368. * rev_fold<typelist<T1, T2, T3>, V, F> == F<T1, F<T2, F<T3, V>>>
  369. * \example
  370. * rev_fold<typelist<>, V, F> == V
  371. * \param List The list to fold
  372. * \param V The initial item fed to Fn
  373. * \param Fn The binary Invocable
  374. */
  375. template <typename List, typename V, typename Fn>
  376. using rev_fold = type_<
  377. rev_fold_impl::rev_fold_<List, V, Fn>
  378. >;
  379. //! @}
  380. /*!
  381. * Return a new \c typelist by adding the elements \p Ts to the front of \p List.
  382. * Complexity \f$ O(1) \f$
  383. */
  384. template <typename List, typename... Ts>
  385. using push_front = type_<
  386. apply <
  387. bind_front<quote<typelist>, Ts...>, List
  388. >
  389. >;
  390. /*!
  391. * Return a new \c typelist by adding the elements \p Ts to the back of \p List.
  392. * Complexity \f$ O(1) \f$
  393. */
  394. template <typename List, typename... Ts>
  395. using push_back = type_<
  396. apply <
  397. bind_back<quote<typelist>, Ts...>, List
  398. >
  399. >;
  400. //! reverse
  401. //! @{
  402. namespace reverse_impl {
  403. template <typename List, typename V = typelist<>>
  404. struct reverse_ {
  405. using type = fold<List, V, quote<push_front>>;
  406. };
  407. }
  408. /*!
  409. * Return a new \c typelist by reversing the elements in the list \p List.
  410. * Complexity \f$ O(N) \f$
  411. */
  412. template <typename List>
  413. using reverse = type_<
  414. reverse_impl::reverse_<List>
  415. >;
  416. //! @}
  417. //! pop_front
  418. //! @{
  419. namespace pop_front_impl {
  420. template <typename List>
  421. struct pop_front_ { };
  422. template <typename Head, typename... Tail>
  423. struct pop_front_<typelist <Head, Tail...>> {
  424. using type = typelist<Tail...>;
  425. };
  426. }
  427. /*!
  428. * Return a new \c typelist by removing the first element from the
  429. * front of \p List.
  430. * Complexity \f$ O(1) \f$
  431. */
  432. template <typename List>
  433. using pop_front = type_<
  434. pop_front_impl::pop_front_<List>
  435. >;
  436. //! @}
  437. //! pop_back
  438. //! @{
  439. namespace pop_back_impl {
  440. template <typename List>
  441. struct pop_back_ {
  442. using type = reverse<
  443. pop_front<reverse<List>>
  444. >;
  445. };
  446. }
  447. /*!
  448. * Return a new \c typelist by removing the last element from the \p List.
  449. * Complexity \f$ O(N) \f$.
  450. * \note
  451. * This operation, in addition from other push/pop operations, is
  452. * heavy(2 reverse operations).
  453. */
  454. template <typename List>
  455. using pop_back = type_ <
  456. pop_back_impl::pop_back_<List>
  457. >;
  458. //! @}
  459. //! Transform
  460. //! @{
  461. namespace transform_impl {
  462. template <typename, typename = void>
  463. struct transform_ { };
  464. template <typename... Ts, typename Fn>
  465. struct transform_<typelist<typelist<Ts...>, Fn>,
  466. void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
  467. using type = typelist<
  468. invoke_t<Fn, Ts>...
  469. >;
  470. };
  471. template <typename... Ts0, typename... Ts1, typename Fn>
  472. struct transform_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
  473. void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
  474. using type = typelist<
  475. invoke_t<Fn, Ts0, Ts1>...
  476. >;
  477. };
  478. }
  479. /*!
  480. * Transformation by applying an invocable \c Fn to one or two lists
  481. * and return the resulting typelist
  482. *
  483. * Complexity \f$ O(N) \f$.
  484. * \example
  485. * \code
  486. * using l1 = typelist<char, int, ...>;
  487. * using l2 = typelist<void, void, ...>;
  488. * using r1 = transform<l1, F1>; // F1, unary invocable
  489. * using r2 = transform<l1, l2, F2>; // F2, binary invocable
  490. * \endcode
  491. */
  492. template <typename... Args>
  493. using transform = type_<
  494. transform_impl::transform_<typelist<Args...>>
  495. >;
  496. //! @}
  497. //! Transform lazy
  498. //! @{
  499. namespace transform_lazy_impl {
  500. template <typename, typename = void>
  501. struct transform_lazy_ { };
  502. // Match for Unary Fn with one typelist
  503. template <typename... Ts, typename Fn>
  504. struct transform_lazy_<typelist<typelist<Ts...>, Fn>,
  505. void_t<invoke<Fn, Ts>...> > /* SFINAE check */ {
  506. using type = typelist<
  507. invoke<Fn, Ts>...
  508. >;
  509. };
  510. // Match for Binary Fn with two typelists
  511. template <typename... Ts0, typename... Ts1, typename Fn>
  512. struct transform_lazy_<typelist<typelist<Ts0...>, typelist<Ts1...>, Fn>,
  513. void_t<invoke<Fn, Ts0, Ts1>...>> /* SFINAE check */ {
  514. using type = typelist<
  515. invoke<Fn, Ts0, Ts1>...
  516. >;
  517. };
  518. }
  519. /*!
  520. * Transformation by applying an invocable \c Fn to one or two lists
  521. * and return a typelist containing the invocables with their arguments,
  522. * not their resulting types.
  523. *
  524. * Complexity \f$ O(N) \f$
  525. *
  526. * \example
  527. * \code
  528. * using l1 = typelist<char, int, ...>;
  529. * using l2 = typelist<void, void, ...>;
  530. * using r1 = transform<l1, F1>; // F1, unary invocable
  531. * using r2 = transform<l1, l2, F2>; // F2, binary invocable
  532. * \endcode
  533. */
  534. template <typename... Args>
  535. using transform_lazy = type_<
  536. transform_lazy_impl::transform_lazy_<typelist<Args...>>
  537. >;
  538. //! @}
  539. //! find_if, find
  540. //! @{
  541. namespace find_if_impl {
  542. template <typename, typename, index_t>
  543. struct find_if_ { };
  544. template<typename Head, typename... Tail, typename Fn, index_t N>
  545. struct find_if_<typelist<Head, Tail...>, Fn, N> {
  546. // Recursive call to find_if_ until Fn returns true_
  547. using type = if_ <
  548. invoke_t<Fn, Head>,
  549. index_t_<N>, // done, return current index
  550. type_<find_if_< // not done, re-call find_if_ with the Tail...
  551. typelist<Tail...>, Fn, N+1>
  552. >
  553. >;
  554. };
  555. // When empty or when we are one place after the last item return Npos
  556. template<typename Fn, index_t N>
  557. struct find_if_<typelist<>, Fn, N> {
  558. using type = Npos;
  559. };
  560. }
  561. /*!
  562. * Search for the first \c Item on the \p List for which the predicate \p Pred
  563. * returns true_ when `type_<invoke<Pred, Item>>`
  564. *
  565. * Complexity \f$ O(N) \f$
  566. *
  567. * \param List A typelist
  568. * \param Pred A Unary invocable predicate
  569. * \return An integral constant of index_t with the location of the first match,
  570. * or Npos otherwise.
  571. */
  572. template<typename List, typename Pred>
  573. using find_if = type_<
  574. find_if_impl::find_if_<List, Pred, 0>
  575. >;
  576. /*!
  577. * Search for the first occurrence of type \p T on a \p List
  578. */
  579. template <typename List, typename T>
  580. using find = find_if<List, same_as<T>>;
  581. //! @}
  582. //! seek_if
  583. //! @{
  584. namespace seek_if_impl {
  585. template <typename, typename, index_t>
  586. struct seek_if_ { };
  587. template<typename Head, typename... Tail, typename Fn, index_t N>
  588. struct seek_if_<typelist<Head, Tail...>, Fn, N> {
  589. // recursive call to seek_if_ until Fn returns true_
  590. using type = if_ <
  591. invoke_t<Fn, Head>,
  592. typelist<Head, Tail...>, // done, return the typelist starting from here
  593. type_<seek_if_< // not done, re-call seek_if_ with the Tail...
  594. typelist<Tail...>, Fn, N+1>
  595. >
  596. >;
  597. };
  598. // When empty or when we are one place after the last item return empty typelist
  599. template<typename Fn, index_t N>
  600. struct seek_if_<typelist<>, Fn, N> {
  601. using type = typelist<>;
  602. };
  603. }
  604. /*!
  605. * Search for the first \c Item on the \p List for which the predicate \p Pred
  606. * returns true_ when `type_<invoke<Pred, Item>>` and return the rest of the \p List
  607. * starting from that position as new typelist
  608. *
  609. * Complexity \f$ O(N) \f$
  610. *
  611. * \param List A typelist
  612. * \param Pred A Unary invocable predicate
  613. * \return An integral constant with the location of the first match, on Npos otherwise
  614. */
  615. template <typename List, typename Pred>
  616. using seek_if = type_<
  617. seek_if_impl::seek_if_<List, Pred, 0>
  618. >;
  619. /*!
  620. * Search for the first \c Item on the \p List of type \p T and return the rest
  621. * of the \p List starting from that position as new typelist
  622. */
  623. template <typename List, typename T>
  624. using seek = seek_if <List, same_as<T>>;
  625. //! @}
  626. //! count_if
  627. //! @{
  628. namespace count_if_impl {
  629. template <typename, typename, size_t>
  630. struct count_if_ { };
  631. template<typename Head, typename... Tail, typename Fn, size_t N>
  632. struct count_if_<typelist<Head, Tail...>, Fn, N> {
  633. // Recursive call to count_if_ up to the end of List, counting all invokes of Fn
  634. // returning true_
  635. using type = if_ <
  636. invoke_t<Fn, Head>,
  637. type_<
  638. count_if_<typelist<Tail...>, Fn, N+1> // increase and re-call
  639. >,
  640. type_<
  641. count_if_<typelist<Tail...>, Fn, N> // re-call without increasing
  642. >
  643. >;
  644. };
  645. // At the end of the List return the counter
  646. template<typename Fn, size_t N>
  647. struct count_if_<typelist<>, Fn, N> {
  648. using type = size_t_<N>;
  649. };
  650. }
  651. /*!
  652. * Count all \c Items on the \p List for which the predicate \p Pred
  653. * returns true_ when `type_<invoke<Pred, Item>>`
  654. *
  655. * Complexity \f$ O(N) \f$
  656. *
  657. * \param List A typelist
  658. * \param Pred A Unary invocable predicate
  659. * \return The total count of occurrences as an integral constant of size_t
  660. */
  661. template <typename List, typename Pred>
  662. using count_if = type_<
  663. count_if_impl::count_if_<List, Pred, 0>
  664. >;
  665. /*!
  666. * Count all occurrences of type \p T int \p List
  667. */
  668. template <typename List, typename T>
  669. using count = count_if<List, same_as<T>>;
  670. //! @}
  671. //! filter
  672. //! @{
  673. namespace filter_impl {
  674. template <typename, typename, typename>
  675. struct filter_ { };
  676. template<typename Head, typename... Tail, typename Fn, typename L>
  677. struct filter_<typelist<Head, Tail...>, Fn, L> {
  678. // Recursive call to filter_ up to the end of the List, creating a new list
  679. // of items for which the invoke of Fn returns true_
  680. using type = if_ <
  681. invoke_t <Fn, Head>,
  682. type_<filter_<typelist<Tail...>, Fn, cat<L, typelist<Head>>>>, // Add the element and re-call
  683. type_<filter_<typelist<Tail...>, Fn, L>> // re-call with the same list
  684. >;
  685. };
  686. // At the end return the produced list
  687. template<typename Fn, typename L>
  688. struct filter_<typelist<>, Fn, L> {
  689. using type = L;
  690. };
  691. }
  692. /*!
  693. * Return a new typelist with elements, the elements of \p List that satisfy the
  694. * invocable \p Pred such that `type_<invoke<Pred, Item>>` is \c true_
  695. *
  696. * Complexity \f$ O(N) \f$
  697. *
  698. * \param List The input typelist
  699. * \param Pred A unary invocable predicate
  700. */
  701. template <typename List, typename Pred>
  702. using filter = type_<
  703. filter_impl::filter_<List, Pred, typelist<>>
  704. >;
  705. //! @}
  706. //! replace
  707. //! @{
  708. namespace replace_if_impl {
  709. template <typename, typename, typename, typename>
  710. struct replace_if_ { };
  711. template <typename Head, typename... Tail, typename Fn, typename T, typename Ret>
  712. struct replace_if_<typelist<Head, Tail...>, Fn, T, Ret> {
  713. // Recursive call to replace_if_ up to the end of the List, creating a new list
  714. // of items based on invocation of Fn
  715. using type = if_ <
  716. invoke_t<Fn, Head>,
  717. type_<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<T>>>>, // re-call with change to T
  718. type_<replace_if_<typelist<Tail...>, Fn, T, cat<Ret, typelist<Head>>>> // re-call with no change
  719. >;
  720. };
  721. // At the end return the produced list
  722. template <typename Fn, typename T, typename Ret>
  723. struct replace_if_ <typelist<>, Fn, T, Ret> {
  724. using type = Ret;
  725. };
  726. }
  727. /*!
  728. * Return a new typelist where all the instances for which the invocation of\p Pred
  729. * returns \c true_, are replaced with \p T
  730. *
  731. * Complexity \f$ O(N) \f$
  732. *
  733. * \param List The input typelist
  734. * \param Pred A unary invocable predicate
  735. * \param T The new type to replace the item of the \p List, when type_<invoke<Pred, Item>>
  736. * returns \c true_
  737. */
  738. template<typename List, typename Pred, typename T>
  739. using replace_if = type_<
  740. replace_if_impl::replace_if_<List, Pred, T, typelist<>>
  741. >;
  742. //! Alias wrapper that returns a new \c typelist where all instances of type \p T have
  743. //! been replaced with \p U.
  744. template <typename List, typename T, typename U>
  745. using replace = type_ <
  746. replace_if <List, same_as<T>, U>
  747. >;
  748. //! @}
  749. //! Returns \c true_ if \p Pred returns \c true_ for all the elements in the \p List or if the
  750. //! \p List is empty and \c false_ otherwise.
  751. template <typename List, typename Pred>
  752. using all_of = empty<
  753. filter <List, compose<quote<not_>, Pred>>
  754. >;
  755. //! Returns \c true_ if \p Pred returns \c true_ for any of the elements in the \p List
  756. //! and \c false_ otherwise.
  757. template <typename List, typename Pred>
  758. using any_of = not_<
  759. empty<filter <List, Pred>>
  760. >;
  761. //! Returns \c true_ if \p Pred returns \c false_ for all the elements in the \p List
  762. //! or if the \p List is empty and \c false otherwise.
  763. template <typename List, typename Pred>
  764. using none_of = empty<
  765. filter <List, Pred>
  766. >;
  767. }}
  768. //! @}
  769. #endif /* __utl_meta_pack_h__ */