find_if.hpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /*!
  2. @file
  3. Defines `boost::hana::find_if`.
  4. @copyright Louis Dionne 2013-2016
  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_FIND_IF_HPP
  9. #define BOOST_HANA_FIND_IF_HPP
  10. #include <boost/hana/fwd/find_if.hpp>
  11. #include <boost/hana/accessors.hpp>
  12. #include <boost/hana/at.hpp>
  13. #include <boost/hana/bool.hpp>
  14. #include <boost/hana/concept/iterable.hpp>
  15. #include <boost/hana/concept/searchable.hpp>
  16. #include <boost/hana/concept/sequence.hpp>
  17. #include <boost/hana/concept/struct.hpp>
  18. #include <boost/hana/config.hpp>
  19. #include <boost/hana/core/dispatch.hpp>
  20. #include <boost/hana/detail/decay.hpp>
  21. #include <boost/hana/drop_while.hpp>
  22. #include <boost/hana/first.hpp>
  23. #include <boost/hana/front.hpp>
  24. #include <boost/hana/functional/compose.hpp>
  25. #include <boost/hana/is_empty.hpp>
  26. #include <boost/hana/length.hpp>
  27. #include <boost/hana/not.hpp>
  28. #include <boost/hana/optional.hpp>
  29. #include <boost/hana/second.hpp>
  30. #include <boost/hana/transform.hpp>
  31. #include <cstddef>
  32. #include <utility>
  33. BOOST_HANA_NAMESPACE_BEGIN
  34. //! @cond
  35. template <typename Xs, typename Pred>
  36. constexpr auto find_if_t::operator()(Xs&& xs, Pred&& pred) const {
  37. using S = typename hana::tag_of<Xs>::type;
  38. using FindIf = BOOST_HANA_DISPATCH_IF(find_if_impl<S>,
  39. hana::Searchable<S>::value
  40. );
  41. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  42. static_assert(hana::Searchable<S>::value,
  43. "hana::find_if(xs, pred) requires 'xs' to be a Searchable");
  44. #endif
  45. return FindIf::apply(static_cast<Xs&&>(xs), static_cast<Pred&&>(pred));
  46. }
  47. //! @endcond
  48. template <typename S, bool condition>
  49. struct find_if_impl<S, when<condition>> : default_ {
  50. template <typename ...Args>
  51. static constexpr auto apply(Args&& ...) = delete;
  52. };
  53. namespace detail {
  54. template <typename Xs, typename Pred, std::size_t i, std::size_t N, bool Done>
  55. struct advance_until;
  56. template <typename Xs, typename Pred, std::size_t i, std::size_t N>
  57. struct advance_until<Xs, Pred, i, N, false>
  58. : advance_until<Xs, Pred, i + 1, N, static_cast<bool>(detail::decay<decltype(
  59. std::declval<Pred>()(hana::at_c<i>(std::declval<Xs>()))
  60. )>::type::value)>
  61. { };
  62. template <typename Xs, typename Pred, std::size_t N>
  63. struct advance_until<Xs, Pred, N, N, false> {
  64. template <typename Ys>
  65. static constexpr auto apply(Ys&&) {
  66. return hana::nothing;
  67. }
  68. };
  69. template <typename Xs, typename Pred, std::size_t i, std::size_t N>
  70. struct advance_until<Xs, Pred, i, N, true> {
  71. template <typename Ys>
  72. static constexpr auto apply(Ys&& ys) {
  73. return hana::just(hana::at_c<i - 1>(static_cast<Ys&&>(ys)));
  74. }
  75. };
  76. }
  77. template <typename S>
  78. struct find_if_impl<S, when<Sequence<S>::value>> {
  79. template <typename Xs, typename Pred>
  80. static constexpr auto apply(Xs&& xs, Pred&&) {
  81. constexpr std::size_t N = decltype(hana::length(xs))::value;
  82. return detail::advance_until<Xs&&, Pred&&, 0, N, false>::apply(
  83. static_cast<Xs&&>(xs)
  84. );
  85. }
  86. };
  87. template <typename It>
  88. struct find_if_impl<It, when<hana::Iterable<It>::value && !Sequence<It>::value>> {
  89. template <typename Xs, typename Pred>
  90. static constexpr auto find_if_helper(Xs&& xs, Pred&& pred, hana::true_) {
  91. return hana::just(hana::front(
  92. hana::drop_while(static_cast<Xs&&>(xs),
  93. hana::compose(hana::not_, static_cast<Pred&&>(pred)))
  94. ));
  95. }
  96. template <typename Xs, typename Pred>
  97. static constexpr auto find_if_helper(Xs&&, Pred&&, hana::false_) {
  98. return hana::nothing;
  99. }
  100. template <typename Xs, typename Pred>
  101. static constexpr auto apply(Xs&& xs, Pred&& pred) {
  102. constexpr bool found = !decltype(
  103. hana::is_empty(hana::drop_while(static_cast<Xs&&>(xs),
  104. hana::compose(hana::not_, static_cast<Pred&&>(pred))))
  105. )::value;
  106. return find_if_impl::find_if_helper(static_cast<Xs&&>(xs),
  107. static_cast<Pred&&>(pred),
  108. hana::bool_<found>{});
  109. }
  110. };
  111. template <typename T, std::size_t N>
  112. struct find_if_impl<T[N]> {
  113. template <typename Xs>
  114. static constexpr auto find_if_helper(Xs&&, hana::false_)
  115. { return hana::nothing; }
  116. template <typename Xs>
  117. static constexpr auto find_if_helper(Xs&& xs, hana::true_)
  118. { return hana::just(static_cast<Xs&&>(xs)[0]); }
  119. template <typename Xs, typename Pred>
  120. static constexpr auto apply(Xs&& xs, Pred&& pred) {
  121. return find_if_helper(static_cast<Xs&&>(xs),
  122. hana::bool_c<decltype(
  123. static_cast<Pred&&>(pred)(static_cast<Xs&&>(xs)[0])
  124. )::value>
  125. );
  126. }
  127. };
  128. namespace struct_detail {
  129. template <typename X>
  130. struct get_member {
  131. X x;
  132. template <typename Member>
  133. constexpr decltype(auto) operator()(Member&& member) && {
  134. return hana::second(static_cast<Member&&>(member))(
  135. static_cast<X&&>(x)
  136. );
  137. }
  138. };
  139. }
  140. template <typename S>
  141. struct find_if_impl<S, when<hana::Struct<S>::value>> {
  142. template <typename X, typename Pred>
  143. static constexpr decltype(auto) apply(X&& x, Pred&& pred) {
  144. return hana::transform(
  145. hana::find_if(hana::accessors<S>(),
  146. hana::compose(static_cast<Pred&&>(pred), hana::first)
  147. ),
  148. struct_detail::get_member<X>{static_cast<X&&>(x)}
  149. );
  150. }
  151. };
  152. BOOST_HANA_NAMESPACE_END
  153. #endif // !BOOST_HANA_FIND_IF_HPP