count_if.hpp 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. /*!
  2. @file
  3. Defines `boost::hana::count_if`.
  4. @copyright Louis Dionne 2013-2017
  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_COUNT_IF_HPP
  9. #define BOOST_HANA_COUNT_IF_HPP
  10. #include <boost/hana/fwd/count_if.hpp>
  11. #include <boost/hana/concept/foldable.hpp>
  12. #include <boost/hana/config.hpp>
  13. #include <boost/hana/core/dispatch.hpp>
  14. #include <boost/hana/detail/algorithm.hpp>
  15. #include <boost/hana/detail/fast_and.hpp>
  16. #include <boost/hana/integral_constant.hpp>
  17. #include <boost/hana/unpack.hpp>
  18. #include <cstddef>
  19. #include <type_traits>
  20. #include <utility>
  21. BOOST_HANA_NAMESPACE_BEGIN
  22. //! @cond
  23. template <typename Xs, typename Pred>
  24. constexpr auto count_if_t::operator()(Xs&& xs, Pred&& pred) const {
  25. using S = typename hana::tag_of<Xs>::type;
  26. using CountIf = BOOST_HANA_DISPATCH_IF(count_if_impl<S>,
  27. hana::Foldable<S>::value
  28. );
  29. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  30. static_assert(hana::Foldable<S>::value,
  31. "hana::count_if(xs, pred) requires 'xs' to be Foldable");
  32. #endif
  33. return CountIf::apply(static_cast<Xs&&>(xs),
  34. static_cast<Pred&&>(pred));
  35. }
  36. //! @endcond
  37. namespace detail {
  38. template <typename Pred>
  39. struct count_pred {
  40. Pred pred;
  41. template <typename ...Xs, typename = typename std::enable_if<
  42. detail::fast_and<
  43. Constant<decltype((*pred)(std::declval<Xs&&>()))>::value...
  44. >::value
  45. >::type>
  46. constexpr auto operator()(Xs&& ...xs) const {
  47. constexpr bool results[] = {false, // <-- avoid empty array
  48. static_cast<bool>(hana::value<decltype((*pred)(static_cast<Xs&&>(xs)))>())...
  49. };
  50. constexpr std::size_t total = detail::count(
  51. results, results + sizeof(results), true
  52. );
  53. return hana::size_c<total>;
  54. }
  55. template <typename ...Xs, typename = void, typename = typename std::enable_if<
  56. !detail::fast_and<
  57. Constant<decltype((*pred)(std::declval<Xs&&>()))>::value...
  58. >::value
  59. >::type>
  60. constexpr auto operator()(Xs&& ...xs) const {
  61. std::size_t total = 0;
  62. using Swallow = std::size_t[];
  63. (void)Swallow{0, ((*pred)(static_cast<Xs&&>(xs)) ? ++total : 0)...};
  64. return total;
  65. }
  66. };
  67. }
  68. template <typename T, bool condition>
  69. struct count_if_impl<T, when<condition>> : default_ {
  70. template <typename Xs, typename Pred>
  71. static constexpr decltype(auto) apply(Xs&& xs, Pred&& pred) {
  72. // We use a pointer instead of a reference to avoid a Clang ICE.
  73. return hana::unpack(static_cast<Xs&&>(xs),
  74. detail::count_pred<decltype(&pred)>{&pred}
  75. );
  76. }
  77. };
  78. BOOST_HANA_NAMESPACE_END
  79. #endif // !BOOST_HANA_COUNT_IF_HPP