algorithm.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Copyright (C) 2020 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_PARSER_DETAIL_TEXT_ALGORITHM_HPP
  7. #define BOOST_PARSER_DETAIL_TEXT_ALGORITHM_HPP
  8. #include <boost/parser/detail/text/config.hpp>
  9. #include <boost/parser/detail/text/detail/algorithm.hpp>
  10. #include <boost/parser/detail/text/detail/sentinel_tag.hpp>
  11. #include <boost/parser/detail/stl_interfaces/view_interface.hpp>
  12. #include <cstddef>
  13. #include <iterator>
  14. #include <utility>
  15. namespace boost::parser::detail { namespace text {
  16. namespace detail {
  17. template<typename Iter>
  18. std::ptrdiff_t distance(Iter first, Iter last, non_sentinel_tag)
  19. {
  20. return std::distance(first, last);
  21. }
  22. template<typename Iter, typename Sentinel>
  23. std::ptrdiff_t distance(Iter first, Sentinel last, sentinel_tag)
  24. {
  25. std::ptrdiff_t retval = 0;
  26. while (first != last) {
  27. ++retval;
  28. ++first;
  29. }
  30. return retval;
  31. }
  32. }
  33. /** Range-friendly version of `std::distance()`, taking an iterator and a
  34. sentinel. */
  35. template<typename Iter, typename Sentinel>
  36. std::ptrdiff_t distance(Iter first, Sentinel last)
  37. {
  38. return detail::distance(
  39. first,
  40. last,
  41. typename std::conditional<
  42. std::is_same<Iter, Sentinel>::value,
  43. detail::non_sentinel_tag,
  44. detail::sentinel_tag>::type());
  45. }
  46. /** Range-friendly version of `std::find()`, taking an iterator and a
  47. sentinel. */
  48. template<typename BidiIter, typename Sentinel, typename T>
  49. BidiIter find(BidiIter first, Sentinel last, T const & x)
  50. {
  51. while (first != last) {
  52. if (*first == x)
  53. return first;
  54. ++first;
  55. }
  56. return first;
  57. }
  58. /** A range-friendly compliment to `std::find()`; returns an iterator to
  59. the first element not equal to `x`. */
  60. template<typename BidiIter, typename Sentinel, typename T>
  61. BidiIter find_not(BidiIter first, Sentinel last, T const & x)
  62. {
  63. while (first != last) {
  64. if (*first != x)
  65. return first;
  66. ++first;
  67. }
  68. return first;
  69. }
  70. /** Range-friendly version of `std::find_if()`, taking an iterator and a
  71. sentinel. */
  72. template<typename BidiIter, typename Sentinel, typename Pred>
  73. BidiIter find_if(BidiIter first, Sentinel last, Pred p)
  74. {
  75. while (first != last) {
  76. if (p(*first))
  77. return first;
  78. ++first;
  79. }
  80. return first;
  81. }
  82. /** Range-friendly version of `std::find_if_not()`, taking an iterator and
  83. a sentinel. */
  84. template<typename BidiIter, typename Sentinel, typename Pred>
  85. BidiIter find_if_not(BidiIter first, Sentinel last, Pred p)
  86. {
  87. while (first != last) {
  88. if (!p(*first))
  89. return first;
  90. ++first;
  91. }
  92. return first;
  93. }
  94. /** Analogue of `std::find()` that finds the last value in `[first, last)`
  95. equal to `x`. */
  96. template<typename BidiIter, typename T>
  97. BidiIter find_backward(BidiIter first, BidiIter last, T const & x)
  98. {
  99. auto it = last;
  100. while (it != first) {
  101. if (*--it == x)
  102. return it;
  103. }
  104. return last;
  105. }
  106. /** Analogue of `std::find()` that finds the last value in `[first, last)`
  107. not equal to `x`. */
  108. template<typename BidiIter, typename T>
  109. BidiIter find_not_backward(BidiIter first, BidiIter last, T const & x)
  110. {
  111. auto it = last;
  112. while (it != first) {
  113. if (*--it != x)
  114. return it;
  115. }
  116. return last;
  117. }
  118. /** Analogue of `std::find()` that finds the last value `v` in `[first,
  119. last)` for which `p(v)` is true. */
  120. template<typename BidiIter, typename Pred>
  121. BidiIter find_if_backward(BidiIter first, BidiIter last, Pred p)
  122. {
  123. auto it = last;
  124. while (it != first) {
  125. if (p(*--it))
  126. return it;
  127. }
  128. return last;
  129. }
  130. /** Analogue of `std::find()` that finds the last value `v` in `[first,
  131. last)` for which `p(v)` is false. */
  132. template<typename BidiIter, typename Pred>
  133. BidiIter find_if_not_backward(BidiIter first, BidiIter last, Pred p)
  134. {
  135. auto it = last;
  136. while (it != first) {
  137. if (!p(*--it))
  138. return it;
  139. }
  140. return last;
  141. }
  142. /** A utility range type returned by `foreach_subrange*()`. */
  143. template<typename Iter, typename Sentinel = Iter>
  144. using foreach_subrange_range =
  145. BOOST_PARSER_DETAIL_TEXT_SUBRANGE<Iter, Sentinel>;
  146. /** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
  147. is a contiguous subsequence of elements that each compares equal to
  148. the first element of the subsequence. Subranges passed to `f` are
  149. non-overlapping. */
  150. template<typename FwdIter, typename Sentinel, typename Func>
  151. Func foreach_subrange(FwdIter first, Sentinel last, Func f)
  152. {
  153. while (first != last) {
  154. auto const & x = *first;
  155. auto const next = boost::parser::detail::text::find_not(first, last, x);
  156. if (first != next) {
  157. f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
  158. first, next));
  159. }
  160. first = next;
  161. }
  162. return f;
  163. }
  164. /** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
  165. is a contiguous subsequence of elements that for each element `e`,
  166. `proj(e)` each compares equal to `proj()` of the first element of the
  167. subsequence. Subranges passed to `f` are non-overlapping. */
  168. template<typename FwdIter, typename Sentinel, typename Func, typename Proj>
  169. Func foreach_subrange(FwdIter first, Sentinel last, Func f, Proj proj)
  170. {
  171. using value_type = typename std::iterator_traits<FwdIter>::value_type;
  172. while (first != last) {
  173. auto const & x = proj(*first);
  174. auto const next = boost::parser::detail::text::find_if_not(
  175. first, last, [&x, proj](const value_type & element) {
  176. return proj(element) == x;
  177. });
  178. if (first != next) {
  179. f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
  180. first, next));
  181. }
  182. first = next;
  183. }
  184. return f;
  185. }
  186. /** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
  187. is a contiguous subsequence of elements, each of which is equal to
  188. `x`. Subranges passed to `f` are non-overlapping. */
  189. template<typename FwdIter, typename Sentinel, typename T, typename Func>
  190. Func foreach_subrange_of(FwdIter first, Sentinel last, T const & x, Func f)
  191. {
  192. while (first != last) {
  193. first = boost::parser::detail::text::find(first, last, x);
  194. auto const next = boost::parser::detail::text::find_not(first, last, x);
  195. if (first != next) {
  196. f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
  197. first, next));
  198. }
  199. first = next;
  200. }
  201. return f;
  202. }
  203. /** Calls `f(sub)` for each subrange `sub` in `[first, last)`. A subrange
  204. is a contiguous subsequence of elements `ei` for which `p(ei)` is
  205. true. Subranges passed to `f` are non-overlapping. */
  206. template<typename FwdIter, typename Sentinel, typename Pred, typename Func>
  207. Func foreach_subrange_if(FwdIter first, Sentinel last, Pred p, Func f)
  208. {
  209. while (first != last) {
  210. first = boost::parser::detail::text::find_if(first, last, p);
  211. auto const next = boost::parser::detail::text::find_if_not(first, last, p);
  212. if (first != next) {
  213. f(boost::parser::detail::text::foreach_subrange_range<FwdIter, Sentinel>(
  214. first, next));
  215. }
  216. first = next;
  217. }
  218. return f;
  219. }
  220. /** Sentinel-friendly version of `std::all_of()`. */
  221. template<typename Iter, typename Sentinel, typename Pred>
  222. bool all_of(Iter first, Sentinel last, Pred p)
  223. {
  224. for (; first != last; ++first) {
  225. if (!p(*first))
  226. return false;
  227. }
  228. return true;
  229. }
  230. /** Sentinel-friendly version of `std::equal()`. */
  231. template<
  232. typename Iter1,
  233. typename Sentinel1,
  234. typename Iter2,
  235. typename Sentinel2>
  236. bool equal(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
  237. {
  238. for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
  239. if (*first1 != *first2)
  240. return false;
  241. }
  242. return first1 == last1 && first2 == last2;
  243. }
  244. /** Sentinel-friendly version of `std::mismatch()`. */
  245. template<
  246. typename Iter1,
  247. typename Sentinel1,
  248. typename Iter2,
  249. typename Sentinel2>
  250. std::pair<Iter1, Iter2>
  251. mismatch(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
  252. {
  253. for (; first1 != last1 && first2 != last2; ++first1, ++first2) {
  254. if (*first1 != *first2)
  255. break;
  256. }
  257. return {first1, first2};
  258. }
  259. /** Sentinel-friendly version of
  260. `std::lexicographical_compare_three_way()`, except that it returns an
  261. `int` instead of a `std::strong_ordering`. */
  262. template<
  263. typename Iter1,
  264. typename Sentinel1,
  265. typename Iter2,
  266. typename Sentinel2>
  267. int lexicographical_compare_three_way(
  268. Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
  269. {
  270. auto const iters = boost::parser::detail::text::mismatch(first1, last1, first2, last2);
  271. if (iters.first == last1) {
  272. if (iters.second == last2)
  273. return 0;
  274. else
  275. return -1;
  276. } else if (iters.second == last2) {
  277. return 1;
  278. } else if (*iters.first < *iters.second) {
  279. return -1;
  280. } else {
  281. return 1;
  282. }
  283. }
  284. /** The view type returned by `boost::parser::detail::text::search()`. */
  285. template<typename Iter>
  286. using search_result = BOOST_PARSER_DETAIL_TEXT_SUBRANGE<Iter>;
  287. /** Sentinel-friendly version of `std::search()`. */
  288. template<
  289. typename Iter1,
  290. typename Sentinel1,
  291. typename Iter2,
  292. typename Sentinel2>
  293. search_result<Iter1>
  294. search(Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2)
  295. {
  296. if (first1 == last1 || first2 == last2)
  297. return {first1, first1};
  298. if (detail::next(first2) == last2) {
  299. auto const it = parser::detail::text::find(first1, last1, *first2);
  300. if (it == last1)
  301. return {it, it};
  302. return {it, detail::next(it)};
  303. }
  304. auto it = first1;
  305. for (;;) {
  306. first1 = parser::detail::text::find(first1, last1, *first2);
  307. if (first1 == last1)
  308. return {first1, first1};
  309. auto it2 = detail::next(first2);
  310. it = first1;
  311. if (++it == last1)
  312. return {it, it};
  313. while (*it == *it2) {
  314. if (++it2 == last2)
  315. return {first1, ++it};
  316. if (++it == last1)
  317. return {it, it};
  318. }
  319. ++first1;
  320. }
  321. return {first1, first1};
  322. }
  323. /** Sentinel-friendly version of `std::find_first_of()`. */
  324. template<
  325. typename Iter1,
  326. typename Sentinel1,
  327. typename Iter2,
  328. typename Sentinel2,
  329. typename Pred>
  330. Iter1 find_first_of(
  331. Iter1 first1, Sentinel1 last1, Iter2 first2, Sentinel2 last2, Pred pred)
  332. {
  333. for (; first1 != last1; ++first1) {
  334. for (auto it = first2; it != last2; ++it) {
  335. if (pred(*first1, *it))
  336. return first1;
  337. }
  338. }
  339. return first1;
  340. }
  341. }}
  342. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  343. namespace std::ranges {
  344. template<typename Iter, typename Sentinel>
  345. inline constexpr bool enable_borrowed_range<
  346. boost::parser::detail::text::foreach_subrange_range<Iter, Sentinel>> = true;
  347. }
  348. #endif
  349. #endif