/*! @file Defines `boost::hana::filter`. @copyright Louis Dionne 2013-2017 Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) */ #ifndef BOOST_HANA_FILTER_HPP #define BOOST_HANA_FILTER_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include BOOST_HANA_NAMESPACE_BEGIN //! @cond template constexpr auto filter_t::operator()(Xs&& xs, Pred&& pred) const { using M = typename hana::tag_of::type; using Filter = BOOST_HANA_DISPATCH_IF(filter_impl, hana::MonadPlus::value ); #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS static_assert(hana::MonadPlus::value, "hana::filter(xs, pred) requires 'xs' to be a MonadPlus"); #endif return Filter::apply(static_cast(xs), static_cast(pred)); } //! @endcond namespace detail { template struct lift_or_empty { template static constexpr auto helper(X&& x, hana::true_) { return hana::lift(static_cast(x)); } template static constexpr auto helper(X&&, hana::false_) { return hana::empty(); } template constexpr auto operator()(X&& x) const { constexpr bool cond = decltype(std::declval()(x))::value; return helper(static_cast(x), hana::bool_c); } }; } template struct filter_impl> : default_ { template static constexpr decltype(auto) apply(Xs&& xs, Pred const&) { return hana::chain(static_cast(xs), detail::lift_or_empty{} ); } }; namespace detail { template struct filter_indices { static constexpr auto compute_indices() { constexpr bool bs[] = {b..., false}; // avoid empty array constexpr std::size_t N = detail::count(bs, bs + sizeof(bs), true); detail::array indices{}; std::size_t* keep = &indices[0]; for (std::size_t i = 0; i < sizeof...(b); ++i) if (bs[i]) *keep++ = i; return indices; } static constexpr auto cached_indices = compute_indices(); }; template struct make_filter_indices { Pred const& pred; template auto operator()(X&& ...x) const -> filter_indices< static_cast(detail::decay< decltype(pred(static_cast(x))) >::type::value)... > { return {}; } }; } template struct filter_impl::value>> { template static constexpr auto filter_helper(Xs&& xs, std::index_sequence) { return hana::make( hana::at_c(static_cast(xs))... ); } template static constexpr auto apply(Xs&& xs, Pred const& pred) { using Indices = decltype( hana::unpack(static_cast(xs), detail::make_filter_indices{pred}) ); return filter_impl::filter_helper( static_cast(xs), std::make_index_sequence{} ); } }; BOOST_HANA_NAMESPACE_END #endif // !BOOST_HANA_FILTER_HPP