index_if.hpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*!
  2. @file
  3. Defines `boost::hana::index_if`.
  4. Copyright Louis Dionne 2013-2022
  5. Copyright Jason Rice 2017
  6. Distributed under the Boost Software License, Version 1.0.
  7. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  8. */
  9. #ifndef BOOST_HANA_INDEX_IF_HPP
  10. #define BOOST_HANA_INDEX_IF_HPP
  11. #include <boost/hana/concept/foldable.hpp>
  12. #include <boost/hana/concept/iterable.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/detail/decay.hpp>
  15. #include <boost/hana/detail/index_if.hpp>
  16. #include <boost/hana/fwd/at.hpp>
  17. #include <boost/hana/fwd/basic_tuple.hpp>
  18. #include <boost/hana/fwd/index_if.hpp>
  19. #include <boost/hana/integral_constant.hpp>
  20. #include <boost/hana/length.hpp>
  21. #include <boost/hana/optional.hpp>
  22. #include <cstddef>
  23. #include <utility>
  24. namespace boost { namespace hana {
  25. //! @cond
  26. template <typename Xs, typename Pred>
  27. constexpr auto index_if_t::operator()(Xs&& xs, Pred&& pred) const {
  28. using S = typename hana::tag_of<Xs>::type;
  29. using IndexIf = BOOST_HANA_DISPATCH_IF(index_if_impl<S>,
  30. hana::Iterable<S>::value
  31. );
  32. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  33. static_assert(hana::Iterable<S>::value,
  34. "hana::index_if(xs, pred) requires 'xs' to be a Iterable");
  35. #endif
  36. return IndexIf::apply(static_cast<Xs&&>(xs), static_cast<Pred&&>(pred));
  37. }
  38. //! @endcond
  39. namespace detail {
  40. template <std::size_t i, std::size_t N, bool Done>
  41. struct iterate_while;
  42. template <std::size_t i, std::size_t N>
  43. struct iterate_while<i, N, false> {
  44. template <typename Xs, typename Pred>
  45. using f = typename iterate_while<i + 1, N,
  46. static_cast<bool>(detail::decay<decltype(
  47. std::declval<Pred>()(
  48. hana::at(std::declval<Xs>(), hana::size_c<i>)))>::type::value)
  49. >::template f<Xs, Pred>;
  50. };
  51. template <std::size_t N>
  52. struct iterate_while<N, N, false> {
  53. template <typename Xs, typename Pred>
  54. using f = hana::optional<>;
  55. };
  56. template <std::size_t i, std::size_t N>
  57. struct iterate_while<i, N, true> {
  58. template <typename Xs, typename Pred>
  59. using f = hana::optional<hana::size_t<i - 1>>;
  60. };
  61. }
  62. template <typename Tag>
  63. struct index_if_impl<Tag, when<Foldable<Tag>::value>> {
  64. template <typename Xs, typename Pred>
  65. static constexpr auto apply(Xs const& xs, Pred const&)
  66. -> typename detail::iterate_while<0,
  67. decltype(hana::length(xs))::value, false>
  68. ::template f<Xs, Pred>
  69. { return {}; }
  70. };
  71. template <typename It>
  72. struct index_if_impl<It, when<!Foldable<It>::value>> {
  73. template <typename Xs, typename Pred>
  74. static constexpr auto apply(Xs const&, Pred const&)
  75. -> typename detail::iterate_while<0,
  76. static_cast<std::size_t>(-1), false>
  77. ::template f<Xs, Pred>
  78. { return {}; }
  79. };
  80. // basic_tuple is implemented here to solve circular dependency issues.
  81. template <>
  82. struct index_if_impl<basic_tuple_tag> {
  83. template <typename ...Xs, typename Pred>
  84. static constexpr auto apply(basic_tuple<Xs...> const&, Pred const&)
  85. -> typename detail::index_if<Pred, Xs...>::type
  86. { return {}; }
  87. };
  88. }} // end namespace boost::hana
  89. #endif // !BOOST_HANA_INDEX_IF_HPP