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.
 
 
 
 

879 lignes
26 KiB

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