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.
 
 
 
 

882 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_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__ */