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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  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_HPP
  22. #define RANGES_V3_ALGORITHM_SEARCH_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 I1, typename S1, typename D1, typename I2, typename S2,
  45. typename D2, typename C, typename P1, typename P2>
  46. subrange<I1> search_sized_impl(I1 const begin1_, S1 end1, D1 const d1_, I2 begin2,
  47. S2 end2, D2 d2, C & pred, P1 & proj1, P2 & proj2)
  48. {
  49. D1 d1 = d1_;
  50. auto begin1 = uncounted(begin1_);
  51. while(true)
  52. {
  53. // Find first element in sequence 1 that matches *begin2, with a mininum
  54. // of loop checks
  55. while(true)
  56. {
  57. if(d1 < d2) // return the last if we've run out of room
  58. {
  59. auto e =
  60. ranges::next(recounted(begin1_, std::move(begin1), d1_ - d1),
  61. std::move(end1));
  62. return {e, e};
  63. }
  64. if(invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2)))
  65. break;
  66. ++begin1;
  67. --d1;
  68. }
  69. // *begin1 matches *begin2, now match elements after here
  70. auto m1 = begin1;
  71. I2 m2 = begin2;
  72. while(true)
  73. {
  74. if(++m2 == end2) // If pattern exhausted, begin1 is the answer (works
  75. // for 1 element pattern)
  76. {
  77. return {recounted(begin1_, std::move(begin1), d1_ - d1),
  78. recounted(begin1_, std::move(++m1), d1_ - d1)};
  79. }
  80. ++m1; // No need to check, we know we have room to match successfully
  81. if(!invoke(
  82. pred,
  83. invoke(proj1, *m1),
  84. invoke(
  85. proj2,
  86. *m2))) // if there is a mismatch, restart with a new begin1
  87. {
  88. ++begin1;
  89. --d1;
  90. break;
  91. } // else there is a match, check next elements
  92. }
  93. }
  94. }
  95. template<typename I1, typename S1, typename I2, typename S2, typename C,
  96. typename P1, typename P2>
  97. subrange<I1> search_impl(I1 begin1, S1 end1, I2 begin2, S2 end2, C & pred,
  98. P1 & proj1, P2 & proj2)
  99. {
  100. while(true)
  101. {
  102. // Find first element in sequence 1 that matches *begin2, with a mininum
  103. // of loop checks
  104. while(true)
  105. {
  106. if(begin1 == end1) // return end1 if no element matches *begin2
  107. return {begin1, begin1};
  108. if(invoke(pred, invoke(proj1, *begin1), invoke(proj2, *begin2)))
  109. break;
  110. ++begin1;
  111. }
  112. // *begin1 matches *begin2, now match elements after here
  113. I1 m1 = begin1;
  114. I2 m2 = begin2;
  115. while(true)
  116. {
  117. if(++m2 == end2) // If pattern exhausted, begin1 is the answer (works
  118. // for 1 element pattern)
  119. return {begin1, ++m1};
  120. if(++m1 == end1) // Otherwise if source exhausted, pattern not found
  121. return {m1, m1};
  122. if(!invoke(
  123. pred,
  124. invoke(proj1, *m1),
  125. invoke(
  126. proj2,
  127. *m2))) // if there is a mismatch, restart with a new begin1
  128. {
  129. ++begin1;
  130. break;
  131. } // else there is a match, check next elements
  132. }
  133. }
  134. }
  135. } // namespace detail
  136. /// \endcond
  137. RANGES_BEGIN_NIEBLOID(search)
  138. /// \brief function template \c search
  139. template<typename I1,
  140. typename S1,
  141. typename I2,
  142. typename S2,
  143. typename C = equal_to,
  144. typename P1 = identity,
  145. typename P2 = identity>
  146. auto RANGES_FUN_NIEBLOID(search)(I1 begin1,
  147. S1 end1,
  148. I2 begin2,
  149. S2 end2,
  150. C pred = C{},
  151. P1 proj1 = P1{},
  152. P2 proj2 = P2{}) //
  153. ->CPP_ret(subrange<I1>)( //
  154. requires forward_iterator<I1> && sentinel_for<S1, I1> &&
  155. forward_iterator<I2> && sentinel_for<S2, I2> &&
  156. indirectly_comparable<I1, I2, C, P1, P2>)
  157. {
  158. if(begin2 == end2)
  159. return {begin1, begin1};
  160. if(RANGES_CONSTEXPR_IF(sized_sentinel_for<S1, I1> &&
  161. sized_sentinel_for<S2, I2>))
  162. return detail::search_sized_impl(std::move(begin1),
  163. std::move(end1),
  164. distance(begin1, end1),
  165. std::move(begin2),
  166. std::move(end2),
  167. distance(begin2, end2),
  168. pred,
  169. proj1,
  170. proj2);
  171. else
  172. return detail::search_impl(std::move(begin1),
  173. std::move(end1),
  174. std::move(begin2),
  175. std::move(end2),
  176. pred,
  177. proj1,
  178. proj2);
  179. }
  180. /// \overload
  181. template<typename Rng1,
  182. typename Rng2,
  183. typename C = equal_to,
  184. typename P1 = identity,
  185. typename P2 = identity>
  186. auto RANGES_FUN_NIEBLOID(search)(
  187. Rng1 && rng1, Rng2 && rng2, C pred = C{}, P1 proj1 = P1{}, P2 proj2 = P2{}) //
  188. ->CPP_ret(safe_subrange_t<Rng1>)( //
  189. requires forward_range<Rng1> && forward_range<Rng2> &&
  190. indirectly_comparable<iterator_t<Rng1>, iterator_t<Rng2>, C, P1, P2>)
  191. {
  192. if(empty(rng2))
  193. return subrange<iterator_t<Rng1>>{begin(rng1), begin(rng1)};
  194. if(RANGES_CONSTEXPR_IF(sized_range<Rng1> && sized_range<Rng2>))
  195. return detail::search_sized_impl(begin(rng1),
  196. end(rng1),
  197. distance(rng1),
  198. begin(rng2),
  199. end(rng2),
  200. distance(rng2),
  201. pred,
  202. proj1,
  203. proj2);
  204. else
  205. return detail::search_impl(
  206. begin(rng1), end(rng1), begin(rng2), end(rng2), pred, proj1, proj2);
  207. }
  208. RANGES_END_NIEBLOID(search)
  209. namespace cpp20
  210. {
  211. using ranges::search;
  212. }
  213. /// @}
  214. } // namespace ranges
  215. #endif // include guard