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.
 
 
 
 

879 lines
26 KiB

  1. /*!
  2. * \file typelist.h
  3. * \brief A template parameter "container"
  4. *
  5. * Copyright (C) 2018-2019 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #ifndef __utl_meta_pack_h__
  21. #define __utl_meta_pack_h__
  22. #include <utl/core/impl.h>
  23. #include <utl/meta/integral.h>
  24. #include <utl/meta/idx_sequence.h>
  25. #include <utl/meta/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__ */