search.hpp 9.7 KB

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