filter.hpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. /*!
  2. @file
  3. Defines `boost::hana::filter`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_FILTER_HPP
  9. #define BOOST_HANA_FILTER_HPP
  10. #include <boost/hana/fwd/filter.hpp>
  11. #include <boost/hana/at.hpp>
  12. #include <boost/hana/bool.hpp>
  13. #include <boost/hana/chain.hpp>
  14. #include <boost/hana/concept/monad_plus.hpp>
  15. #include <boost/hana/concept/sequence.hpp>
  16. #include <boost/hana/config.hpp>
  17. #include <boost/hana/core/dispatch.hpp>
  18. #include <boost/hana/core/make.hpp>
  19. #include <boost/hana/detail/algorithm.hpp>
  20. #include <boost/hana/detail/array.hpp>
  21. #include <boost/hana/detail/decay.hpp>
  22. #include <boost/hana/empty.hpp>
  23. #include <boost/hana/lift.hpp>
  24. #include <boost/hana/unpack.hpp>
  25. #include <cstddef>
  26. #include <utility>
  27. namespace boost { namespace hana {
  28. //! @cond
  29. template <typename Xs, typename Pred>
  30. constexpr auto filter_t::operator()(Xs&& xs, Pred&& pred) const {
  31. using M = typename hana::tag_of<Xs>::type;
  32. using Filter = BOOST_HANA_DISPATCH_IF(filter_impl<M>,
  33. hana::MonadPlus<M>::value
  34. );
  35. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  36. static_assert(hana::MonadPlus<M>::value,
  37. "hana::filter(xs, pred) requires 'xs' to be a MonadPlus");
  38. #endif
  39. return Filter::apply(static_cast<Xs&&>(xs),
  40. static_cast<Pred&&>(pred));
  41. }
  42. //! @endcond
  43. namespace detail {
  44. template <typename Pred, typename M>
  45. struct lift_or_empty {
  46. template <typename X>
  47. static constexpr auto helper(X&& x, hana::true_)
  48. { return hana::lift<M>(static_cast<X&&>(x)); }
  49. template <typename X>
  50. static constexpr auto helper(X&&, hana::false_)
  51. { return hana::empty<M>(); }
  52. template <typename X>
  53. constexpr auto operator()(X&& x) const {
  54. constexpr bool cond = decltype(std::declval<Pred>()(x))::value;
  55. return helper(static_cast<X&&>(x), hana::bool_c<cond>);
  56. }
  57. };
  58. }
  59. template <typename M, bool condition>
  60. struct filter_impl<M, when<condition>> : default_ {
  61. template <typename Xs, typename Pred>
  62. static constexpr decltype(auto) apply(Xs&& xs, Pred const&) {
  63. return hana::chain(static_cast<Xs&&>(xs),
  64. detail::lift_or_empty<Pred, M>{}
  65. );
  66. }
  67. };
  68. namespace detail {
  69. template <bool ...b>
  70. struct filter_indices {
  71. static constexpr auto compute_indices() {
  72. constexpr bool bs[] = {b..., false}; // avoid empty array
  73. constexpr std::size_t N = detail::count(bs, bs + sizeof(bs), true);
  74. detail::array<std::size_t, N> indices{};
  75. std::size_t* keep = &indices[0];
  76. for (std::size_t i = 0; i < sizeof...(b); ++i)
  77. if (bs[i])
  78. *keep++ = i;
  79. return indices;
  80. }
  81. static constexpr auto cached_indices = compute_indices();
  82. };
  83. template <typename Pred>
  84. struct make_filter_indices {
  85. Pred const& pred;
  86. template <typename ...X>
  87. auto operator()(X&& ...x) const -> filter_indices<
  88. static_cast<bool>(detail::decay<
  89. decltype(pred(static_cast<X&&>(x)))
  90. >::type::value)...
  91. > { return {}; }
  92. };
  93. }
  94. template <typename S>
  95. struct filter_impl<S, when<Sequence<S>::value>> {
  96. template <typename Indices, typename Xs, std::size_t ...i>
  97. static constexpr auto filter_helper(Xs&& xs, std::index_sequence<i...>) {
  98. return hana::make<S>(
  99. hana::at_c<Indices::cached_indices[i]>(static_cast<Xs&&>(xs))...
  100. );
  101. }
  102. template <typename Xs, typename Pred>
  103. static constexpr auto apply(Xs&& xs, Pred const& pred) {
  104. using Indices = decltype(
  105. hana::unpack(static_cast<Xs&&>(xs),
  106. detail::make_filter_indices<Pred>{pred})
  107. );
  108. return filter_impl::filter_helper<Indices>(
  109. static_cast<Xs&&>(xs),
  110. std::make_index_sequence<Indices::cached_indices.size()>{}
  111. );
  112. }
  113. };
  114. }} // end namespace boost::hana
  115. #endif // !BOOST_HANA_FILTER_HPP