You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

search_n.hpp 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2014-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. //===----------------------------------------------------------------------===//
  14. //
  15. // The LLVM Compiler Infrastructure
  16. //
  17. // This file is dual licensed under the MIT and the University of Illinois Open
  18. // Source Licenses. See LICENSE.TXT for details.
  19. //
  20. //===----------------------------------------------------------------------===//
  21. #ifndef RANGES_V3_ALGORITHM_SEARCH_N_HPP
  22. #define RANGES_V3_ALGORITHM_SEARCH_N_HPP
  23. #include <meta/meta.hpp>
  24. #include <range/v3/range_fwd.hpp>
  25. #include <range/v3/functional/comparisons.hpp>
  26. #include <range/v3/functional/identity.hpp>
  27. #include <range/v3/functional/invoke.hpp>
  28. #include <range/v3/iterator/concepts.hpp>
  29. #include <range/v3/iterator/operations.hpp>
  30. #include <range/v3/iterator/traits.hpp>
  31. #include <range/v3/range/access.hpp>
  32. #include <range/v3/range/concepts.hpp>
  33. #include <range/v3/range/primitives.hpp>
  34. #include <range/v3/range/traits.hpp>
  35. #include <range/v3/utility/static_const.hpp>
  36. #include <range/v3/view/subrange.hpp>
  37. namespace ranges
  38. {
  39. /// \addtogroup group-algorithms
  40. /// @{
  41. /// \cond
  42. namespace detail
  43. {
  44. template<typename I, typename S, typename D, typename V, typename C, typename P>
  45. subrange<I> search_n_sized_impl(I const begin_, S last, D const d_, D cnt,
  46. V const & val, C & pred, P & proj)
  47. {
  48. D d = d_; // always the distance from first to end
  49. auto first = uncounted(begin_);
  50. while(true)
  51. {
  52. // Find first element in sequence 1 that matches val, with a mininum of
  53. // loop checks
  54. while(true)
  55. {
  56. if(d < cnt) // return the last if we've run out of room
  57. {
  58. auto e = ranges::next(recounted(begin_, std::move(first), d_ - d),
  59. std::move(last));
  60. return {e, e};
  61. }
  62. if(invoke(pred, invoke(proj, *first), val))
  63. break;
  64. ++first;
  65. --d;
  66. }
  67. // *first matches val, now match elements after here
  68. auto m = first;
  69. D c = 0;
  70. while(true)
  71. {
  72. if(++c == cnt) // If pattern exhausted, first is the answer (works
  73. // for 1 element pattern)
  74. return {recounted(begin_, std::move(first), d_ - d),
  75. recounted(begin_, std::move(++m), d_ - d)};
  76. ++m; // No need to check, we know we have room to match successfully
  77. if(!invoke(pred,
  78. invoke(proj, *m),
  79. val)) // if there is a mismatch, restart with a new begin
  80. {
  81. first = next(std::move(m));
  82. d -= (c + 1);
  83. break;
  84. } // else there is a match, check next elements
  85. }
  86. }
  87. }
  88. template<typename I, typename S, typename D, typename V, typename C, typename P>
  89. subrange<I> search_n_impl(I first, S last, D cnt, V const & val, C & pred,
  90. P & proj)
  91. {
  92. while(true)
  93. {
  94. // Find first element in sequence 1 that matches val, with a mininum of
  95. // loop checks
  96. while(true)
  97. {
  98. if(first == last) // return last if no element matches val
  99. return {first, first};
  100. if(invoke(pred, invoke(proj, *first), val))
  101. break;
  102. ++first;
  103. }
  104. // *first matches val, now match elements after here
  105. I m = first;
  106. D c = 0;
  107. while(true)
  108. {
  109. if(++c == cnt) // If pattern exhausted, first is the answer (works
  110. // for 1 element pattern)
  111. return {first, ++m};
  112. if(++m == last) // Otherwise if source exhausted, pattern not found
  113. return {m, m};
  114. if(!invoke(pred,
  115. invoke(proj, *m),
  116. val)) // if there is a mismatch, restart with a new begin
  117. {
  118. first = next(std::move(m));
  119. break;
  120. } // else there is a match, check next elements
  121. }
  122. }
  123. }
  124. } // namespace detail
  125. /// \endcond
  126. RANGES_BEGIN_NIEBLOID(search_n)
  127. /// \brief function template \c search_n
  128. template<typename I,
  129. typename S,
  130. typename V,
  131. typename C = equal_to,
  132. typename P = identity>
  133. auto RANGES_FUN_NIEBLOID(search_n)(I first,
  134. S last,
  135. iter_difference_t<I>
  136. cnt,
  137. V const & val,
  138. C pred = C{},
  139. P proj = P{}) //
  140. ->CPP_ret(subrange<I>)( //
  141. requires forward_iterator<I> && sentinel_for<S, I> &&
  142. indirectly_comparable<I, V const *, C, P>)
  143. {
  144. if(cnt <= 0)
  145. return {first, first};
  146. if(RANGES_CONSTEXPR_IF(sized_sentinel_for<S, I>))
  147. return detail::search_n_sized_impl(std::move(first),
  148. std::move(last),
  149. distance(first, last),
  150. cnt,
  151. val,
  152. pred,
  153. proj);
  154. else
  155. return detail::search_n_impl(
  156. std::move(first), std::move(last), cnt, val, pred, proj);
  157. }
  158. /// \overload
  159. template<typename Rng, typename V, typename C = equal_to, typename P = identity>
  160. auto RANGES_FUN_NIEBLOID(search_n)(Rng && rng,
  161. iter_difference_t<iterator_t<Rng>>
  162. cnt,
  163. V const & val,
  164. C pred = C{},
  165. P proj = P{}) //
  166. ->CPP_ret(safe_subrange_t<Rng>)( //
  167. requires forward_range<Rng> &&
  168. indirectly_comparable<iterator_t<Rng>, V const *, C, P>)
  169. {
  170. if(cnt <= 0)
  171. return subrange<iterator_t<Rng>>{begin(rng), begin(rng)};
  172. if(RANGES_CONSTEXPR_IF(sized_range<Rng>))
  173. return detail::search_n_sized_impl(
  174. begin(rng), end(rng), distance(rng), cnt, val, pred, proj);
  175. else
  176. return detail::search_n_impl(begin(rng), end(rng), cnt, val, pred, proj);
  177. }
  178. RANGES_END_NIEBLOID(search_n)
  179. namespace cpp20
  180. {
  181. using ranges::search_n;
  182. }
  183. /// @}
  184. } // namespace ranges
  185. #endif // include guard