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.
 
 
 
 

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