search.hpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #ifndef BOOST_PARSER_SEARCH_HPP
  2. #define BOOST_PARSER_SEARCH_HPP
  3. #include <boost/parser/parser.hpp>
  4. #include <boost/parser/transcode_view.hpp>
  5. #include <cstring>
  6. namespace boost::parser {
  7. namespace detail {
  8. template<bool Const, typename T>
  9. using maybe_const = std::conditional_t<Const, const T, T>;
  10. inline constexpr text::format no_format = text::format::none;
  11. template<text::format Format = text::format::utf8>
  12. constexpr auto as_utf =
  13. text::detail::as_utf_impl<text::utf8_view, text::format::utf8>{};
  14. template<>
  15. constexpr auto as_utf<text::format::utf16> =
  16. text::detail::as_utf_impl<text::utf16_view, text::format::utf16>{};
  17. template<>
  18. constexpr auto as_utf<text::format::utf32> =
  19. text::detail::as_utf_impl<text::utf32_view, text::format::utf32>{};
  20. template<
  21. typename R_,
  22. bool ToCommonRange = false,
  23. text::format OtherRangeFormat = no_format,
  24. bool = std::is_same_v<sentinel_t<remove_cv_ref_t<R_>>,
  25. null_sentinel_t> ||
  26. text::detail::is_bounded_array_v<remove_cv_ref_t<R_>>>
  27. struct to_range
  28. {
  29. template<typename R>
  30. static constexpr auto call(R && r)
  31. {
  32. static_assert(std::is_same_v<R, R_>);
  33. using T = remove_cv_ref_t<R>;
  34. if constexpr (std::is_same_v<sentinel_t<T>, null_sentinel_t>) {
  35. auto plus_strlen = [](auto * ptr) {
  36. while (*ptr) {
  37. ++ptr;
  38. }
  39. return ptr;
  40. };
  41. auto const first = r.begin();
  42. if constexpr (OtherRangeFormat == no_format) {
  43. if constexpr (ToCommonRange) {
  44. return BOOST_PARSER_SUBRANGE(
  45. first, plus_strlen(first));
  46. } else {
  47. return (R &&) r;
  48. }
  49. } else {
  50. if constexpr (ToCommonRange) {
  51. return BOOST_PARSER_SUBRANGE(
  52. first, plus_strlen(first)) |
  53. as_utf<OtherRangeFormat>;
  54. } else {
  55. return (R &&) r | as_utf<OtherRangeFormat>;
  56. }
  57. }
  58. } else if constexpr (text::detail::is_bounded_array_v<T>) {
  59. auto const first = std::begin(r);
  60. auto last = std::end(r);
  61. constexpr auto n = std::extent_v<T>;
  62. if (n && !r[n - 1])
  63. --last;
  64. if constexpr (OtherRangeFormat == no_format) {
  65. return BOOST_PARSER_SUBRANGE(first, last);
  66. } else {
  67. return BOOST_PARSER_SUBRANGE(first, last) |
  68. as_utf<OtherRangeFormat>;
  69. }
  70. } else {
  71. return (R &&) r | as_utf<OtherRangeFormat>;
  72. }
  73. }
  74. };
  75. template<typename R_, bool ToCommonRange>
  76. struct to_range<R_, ToCommonRange, no_format, false>
  77. {
  78. template<typename R>
  79. static constexpr R && call(R && r)
  80. {
  81. return (R &&) r;
  82. }
  83. };
  84. template<typename R>
  85. using to_range_t = decltype(to_range<R>::call(std::declval<R>()));
  86. struct phony
  87. {};
  88. template<
  89. typename R,
  90. typename Parser,
  91. typename GlobalState,
  92. typename ErrorHandler,
  93. typename SkipParser>
  94. auto search_impl(
  95. R && r,
  96. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  97. parser_interface<SkipParser> const & skip,
  98. trace trace_mode)
  99. {
  100. auto first = text::detail::begin(r);
  101. auto const last = text::detail::end(r);
  102. if (first == last)
  103. return BOOST_PARSER_SUBRANGE(first, first);
  104. auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
  105. if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
  106. auto result = parser::prefix_parse(
  107. first, last, search_parser, trace_mode);
  108. if (*result)
  109. return **result;
  110. } else {
  111. auto result = parser::prefix_parse(
  112. first, last, search_parser, skip, trace_mode);
  113. if (*result)
  114. return **result;
  115. }
  116. return BOOST_PARSER_SUBRANGE(first, first);
  117. }
  118. template<
  119. typename R,
  120. typename Parser,
  121. typename GlobalState,
  122. typename ErrorHandler,
  123. typename SkipParser>
  124. #if BOOST_PARSER_USE_CONCEPTS
  125. std::ranges::borrowed_subrange_t<R>
  126. #else
  127. auto
  128. #endif
  129. search_repack_shim(
  130. R && r,
  131. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  132. parser_interface<SkipParser> const & skip,
  133. trace trace_mode)
  134. {
  135. using value_type = range_value_t<decltype(r)>;
  136. if constexpr (std::is_same_v<value_type, char>) {
  137. return detail::search_impl((R &&) r, parser, skip, trace_mode);
  138. } else {
  139. auto r_unpacked = detail::text::unpack_iterator_and_sentinel(
  140. text::detail::begin(r), text::detail::end(r));
  141. auto result =
  142. detail::search_impl(r | as_utf32, parser, skip, trace_mode);
  143. return BOOST_PARSER_SUBRANGE(
  144. r_unpacked.repack(text::detail::begin(result).base()),
  145. r_unpacked.repack(text::detail::end(result).base()));
  146. }
  147. }
  148. template<typename T>
  149. constexpr bool is_parser_iface = false;
  150. template<typename T>
  151. constexpr bool is_parser_iface<parser_interface<T>> = true;
  152. }
  153. /** Returns a subrange to the first match for parser `parser` in `r`,
  154. using skip-parser `skip`. This function has a similar interface and
  155. semantics to `std::ranges::search()`. Returns `std::ranges::dangling`
  156. in C++20 and later if `r` is a non-borrowable rvalue. */
  157. template<
  158. #if BOOST_PARSER_USE_CONCEPTS
  159. parsable_range R,
  160. #else
  161. typename R,
  162. #endif
  163. typename Parser,
  164. typename GlobalState,
  165. typename ErrorHandler,
  166. typename SkipParser
  167. #if !BOOST_PARSER_USE_CONCEPTS
  168. ,
  169. typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
  170. #endif
  171. >
  172. auto search(
  173. R && r,
  174. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  175. parser_interface<SkipParser> const & skip,
  176. trace trace_mode = trace::off)
  177. {
  178. return detail::search_repack_shim(
  179. detail::to_range<R>::call((R &&) r), parser, skip, trace_mode);
  180. }
  181. /** Returns a subrange to the first match for parser `parser` in `[first,
  182. last)`, using skip-parser `skip`. This function has a similar
  183. interface and semantics to `std::ranges::search()`. */
  184. template<
  185. #if BOOST_PARSER_USE_CONCEPTS
  186. parsable_iter I,
  187. std::sentinel_for<I> S,
  188. #else
  189. typename I,
  190. typename S,
  191. #endif
  192. typename Parser,
  193. typename SkipParser,
  194. typename GlobalState,
  195. #if BOOST_PARSER_USE_CONCEPTS
  196. error_handler<I, S, GlobalState> ErrorHandler
  197. #else
  198. typename ErrorHandler,
  199. typename Enable = std::enable_if_t<
  200. detail::is_parsable_iter_v<I> &&
  201. detail::is_equality_comparable_with_v<I, S>>
  202. #endif
  203. >
  204. auto search(
  205. I first,
  206. S last,
  207. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  208. parser_interface<SkipParser> const & skip,
  209. trace trace_mode = trace::off)
  210. {
  211. return parser::search(
  212. BOOST_PARSER_SUBRANGE(first, last), parser, skip, trace_mode);
  213. }
  214. /** Returns a subrange to the first match for parser `parser` in `r`.
  215. This function has a similar interface and semantics to
  216. `std::ranges::search()`. Returns `std::ranges::dangling` in C++20 and
  217. later if `r` is a non-borrowable rvalue. */
  218. template<
  219. #if BOOST_PARSER_USE_CONCEPTS
  220. parsable_range R,
  221. #else
  222. typename R,
  223. #endif
  224. typename Parser,
  225. typename GlobalState,
  226. typename ErrorHandler
  227. #if !BOOST_PARSER_USE_CONCEPTS
  228. ,
  229. typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
  230. #endif
  231. >
  232. auto search(
  233. R && r,
  234. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  235. trace trace_mode = trace::off)
  236. {
  237. return parser::search(
  238. (R &&) r,
  239. parser,
  240. parser_interface<eps_parser<detail::phony>>{},
  241. trace_mode);
  242. }
  243. /** Returns a subrange to the first match for parser `parser` in `[first,
  244. last)`. This function has a similar interface and semantics to
  245. `std::ranges::search()`. */
  246. template<
  247. #if BOOST_PARSER_USE_CONCEPTS
  248. parsable_iter I,
  249. std::sentinel_for<I> S,
  250. #else
  251. typename I,
  252. typename S,
  253. #endif
  254. typename Parser,
  255. typename GlobalState,
  256. #if BOOST_PARSER_USE_CONCEPTS
  257. error_handler<I, S, GlobalState> ErrorHandler
  258. #else
  259. typename ErrorHandler,
  260. typename Enable = std::enable_if_t<
  261. detail::is_parsable_iter_v<I> &&
  262. detail::is_equality_comparable_with_v<I, S>>
  263. #endif
  264. >
  265. auto search(
  266. I first,
  267. S last,
  268. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  269. trace trace_mode = trace::off)
  270. {
  271. return parser::search(
  272. BOOST_PARSER_SUBRANGE(first, last),
  273. parser,
  274. parser_interface<eps_parser<detail::phony>>{},
  275. trace_mode);
  276. }
  277. /** Produces a sequence of subranges of the underlying sequence of type
  278. `V`. Each subrange is a nonoverlapping match of the given parser,
  279. using a skip-parser if provided. */
  280. template<
  281. #if BOOST_PARSER_USE_CONCEPTS
  282. std::ranges::viewable_range V,
  283. #else
  284. typename V,
  285. #endif
  286. typename Parser,
  287. typename GlobalState,
  288. typename ErrorHandler,
  289. typename SkipParser>
  290. struct search_all_view
  291. : detail::stl_interfaces::view_interface<
  292. search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
  293. {
  294. constexpr search_all_view() = default;
  295. constexpr search_all_view(
  296. V base,
  297. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  298. parser_interface<SkipParser> const & skip,
  299. trace trace_mode = trace::off) :
  300. base_(std::move(base)),
  301. parser_(parser),
  302. skip_(skip),
  303. trace_mode_(trace_mode)
  304. {}
  305. constexpr search_all_view(
  306. V base,
  307. parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
  308. trace trace_mode = trace::off) :
  309. base_(std::move(base)),
  310. parser_(parser),
  311. skip_(),
  312. trace_mode_(trace_mode)
  313. {}
  314. constexpr V base() const &
  315. #if BOOST_PARSER_USE_CONCEPTS
  316. requires std::copy_constructible<V>
  317. #endif
  318. {
  319. return base_;
  320. }
  321. constexpr V base() && { return std::move(base_); }
  322. constexpr auto begin() { return iterator<false>{this}; }
  323. constexpr auto end() { return sentinel<false>{}; }
  324. constexpr auto begin() const
  325. #if BOOST_PARSER_USE_CONCEPTS
  326. requires std::ranges::range<const V>
  327. #endif
  328. {
  329. return iterator<true>{this};
  330. }
  331. constexpr auto end() const
  332. #if BOOST_PARSER_USE_CONCEPTS
  333. requires std::ranges::range<const V>
  334. #endif
  335. {
  336. return sentinel<true>{};
  337. }
  338. template<bool Const>
  339. struct sentinel
  340. {};
  341. template<bool Const>
  342. struct iterator
  343. : detail::stl_interfaces::proxy_iterator_interface<
  344. iterator<Const>,
  345. std::forward_iterator_tag,
  346. BOOST_PARSER_SUBRANGE<
  347. detail::iterator_t<detail::maybe_const<Const, V>>>>
  348. {
  349. using I = detail::iterator_t<detail::maybe_const<Const, V>>;
  350. using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
  351. constexpr iterator() = default;
  352. constexpr iterator(
  353. detail::maybe_const<Const, search_all_view> * parent) :
  354. parent_(parent),
  355. r_(parent_->base_.begin(), parent_->base_.end()),
  356. curr_(r_.begin(), r_.begin()),
  357. next_it_(r_.begin())
  358. {
  359. ++*this;
  360. }
  361. constexpr iterator & operator++()
  362. {
  363. r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
  364. curr_ = parser::search(
  365. r_, parent_->parser_, parent_->skip_, parent_->trace_mode_);
  366. next_it_ = curr_.end();
  367. if (curr_.begin() == curr_.end())
  368. r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
  369. return *this;
  370. }
  371. constexpr BOOST_PARSER_SUBRANGE<I> operator*() const
  372. {
  373. return curr_;
  374. }
  375. friend constexpr bool operator==(iterator lhs, iterator rhs)
  376. {
  377. return lhs.r_.begin() == rhs.r_.begin();
  378. }
  379. friend constexpr bool operator==(iterator it, sentinel<Const>)
  380. {
  381. return it.r_.begin() == it.r_.end();
  382. }
  383. using base_type = detail::stl_interfaces::proxy_iterator_interface<
  384. iterator,
  385. std::forward_iterator_tag,
  386. BOOST_PARSER_SUBRANGE<I>>;
  387. using base_type::operator++;
  388. private:
  389. detail::maybe_const<Const, search_all_view> * parent_;
  390. BOOST_PARSER_SUBRANGE<I, S> r_;
  391. BOOST_PARSER_SUBRANGE<I> curr_;
  392. I next_it_;
  393. };
  394. template<bool Const>
  395. friend struct iterator;
  396. private:
  397. V base_;
  398. parser_interface<Parser, GlobalState, ErrorHandler> parser_;
  399. parser_interface<SkipParser> skip_;
  400. trace trace_mode_;
  401. };
  402. // deduction guides
  403. template<
  404. typename V,
  405. typename Parser,
  406. typename GlobalState,
  407. typename ErrorHandler,
  408. typename SkipParser>
  409. search_all_view(
  410. V &&,
  411. parser_interface<Parser, GlobalState, ErrorHandler>,
  412. parser_interface<SkipParser>,
  413. trace)
  414. -> search_all_view<
  415. detail::text::detail::all_t<V>,
  416. Parser,
  417. GlobalState,
  418. ErrorHandler,
  419. SkipParser>;
  420. template<
  421. typename V,
  422. typename Parser,
  423. typename GlobalState,
  424. typename ErrorHandler,
  425. typename SkipParser>
  426. search_all_view(
  427. V &&,
  428. parser_interface<Parser, GlobalState, ErrorHandler>,
  429. parser_interface<SkipParser>)
  430. -> search_all_view<
  431. detail::text::detail::all_t<V>,
  432. Parser,
  433. GlobalState,
  434. ErrorHandler,
  435. SkipParser>;
  436. template<
  437. typename V,
  438. typename Parser,
  439. typename GlobalState,
  440. typename ErrorHandler>
  441. search_all_view(
  442. V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
  443. -> search_all_view<
  444. detail::text::detail::all_t<V>,
  445. Parser,
  446. GlobalState,
  447. ErrorHandler,
  448. parser_interface<eps_parser<detail::phony>>>;
  449. template<
  450. typename V,
  451. typename Parser,
  452. typename GlobalState,
  453. typename ErrorHandler>
  454. search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
  455. -> search_all_view<
  456. detail::text::detail::all_t<V>,
  457. Parser,
  458. GlobalState,
  459. ErrorHandler,
  460. parser_interface<eps_parser<detail::phony>>>;
  461. namespace detail {
  462. template<
  463. typename V,
  464. typename Parser,
  465. typename GlobalState,
  466. typename ErrorHandler,
  467. typename SkipParser>
  468. using search_all_view_expr = decltype(search_all_view<
  469. V,
  470. Parser,
  471. GlobalState,
  472. ErrorHandler,
  473. SkipParser>(
  474. std::declval<V>(),
  475. std::declval<
  476. parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
  477. std::declval<parser_interface<SkipParser> const &>(),
  478. trace::on));
  479. template<
  480. typename V,
  481. typename Parser,
  482. typename GlobalState,
  483. typename ErrorHandler,
  484. typename SkipParser>
  485. constexpr bool can_search_all_view = is_detected_v<
  486. search_all_view_expr,
  487. V,
  488. Parser,
  489. GlobalState,
  490. ErrorHandler,
  491. SkipParser>;
  492. struct search_all_impl
  493. {
  494. #if BOOST_PARSER_USE_CONCEPTS
  495. template<
  496. parsable_range R,
  497. typename Parser,
  498. typename GlobalState,
  499. typename ErrorHandler,
  500. typename SkipParser>
  501. requires(std::ranges::viewable_range<R>) && can_search_all_view<
  502. to_range_t<R>,
  503. Parser,
  504. GlobalState,
  505. ErrorHandler,
  506. SkipParser>
  507. [[nodiscard]] constexpr auto operator()(
  508. R && r,
  509. parser_interface<Parser, GlobalState, ErrorHandler> const &
  510. parser,
  511. parser_interface<SkipParser> const & skip,
  512. trace trace_mode = trace::off) const
  513. {
  514. return search_all_view(
  515. to_range<R>::call((R &&)r), parser, skip, trace_mode);
  516. }
  517. template<
  518. parsable_range R,
  519. typename Parser,
  520. typename GlobalState,
  521. typename ErrorHandler>
  522. requires(std::ranges::viewable_range<R>) &&
  523. can_search_all_view<
  524. to_range_t<R>,
  525. Parser,
  526. GlobalState,
  527. ErrorHandler,
  528. parser_interface<eps_parser<detail::phony>>>
  529. [[nodiscard]] constexpr auto operator()(
  530. R && r,
  531. parser_interface<Parser, GlobalState, ErrorHandler> const &
  532. parser,
  533. trace trace_mode = trace::off) const
  534. {
  535. return (*this)(
  536. (R &&)r,
  537. parser,
  538. parser_interface<eps_parser<detail::phony>>{},
  539. trace_mode);
  540. }
  541. #else
  542. template<
  543. typename R,
  544. typename Parser,
  545. typename GlobalState,
  546. typename ErrorHandler,
  547. typename SkipParser =
  548. parser_interface<eps_parser<detail::phony>>,
  549. typename Trace = trace,
  550. typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
  551. [[nodiscard]] constexpr auto operator()(
  552. R && r,
  553. parser_interface<Parser, GlobalState, ErrorHandler> const &
  554. parser,
  555. SkipParser const & skip = SkipParser{},
  556. Trace trace_mode = Trace{}) const
  557. {
  558. if constexpr (
  559. std::
  560. is_same_v<detail::remove_cv_ref_t<SkipParser>, trace> &&
  561. std::is_same_v<Trace, trace>) {
  562. // (r, parser, trace) case
  563. return impl(
  564. (R &&) r,
  565. parser,
  566. parser_interface<eps_parser<detail::phony>>{},
  567. skip);
  568. } else if constexpr (
  569. detail::is_parser_iface<SkipParser> &&
  570. std::is_same_v<Trace, trace>) {
  571. // (r, parser, skip, trace) case
  572. return impl((R &&) r, parser, skip, trace_mode);
  573. } else {
  574. static_assert(
  575. sizeof(R) == 1 && false,
  576. "Only the signatures search_all(R, parser, skip, trace "
  577. "= trace::off) and search_all(R, parser, trace = "
  578. "trace::off) are supported.");
  579. }
  580. }
  581. private:
  582. template<
  583. typename R,
  584. typename Parser,
  585. typename GlobalState,
  586. typename ErrorHandler,
  587. typename SkipParser>
  588. [[nodiscard]] constexpr auto impl(
  589. R && r,
  590. parser_interface<Parser, GlobalState, ErrorHandler> const &
  591. parser,
  592. parser_interface<SkipParser> const & skip,
  593. trace trace_mode = trace::off) const
  594. {
  595. return search_all_view(
  596. to_range<R>::call((R &&) r), parser, skip, trace_mode);
  597. }
  598. #endif
  599. };
  600. }
  601. /** A range adaptor object ([range.adaptor.object]). Given subexpressions
  602. `E` and `P`, `Q`, and `R`, each of the expressions `search_all(E, P)`,
  603. `search_all(E, P, Q)`, and `search_all(E, P, Q, R)` are
  604. expression-equivalent to `search_all_view(E, P)`, `search_all_view(E,
  605. P, Q)`, and `search_all_view(E, P, Q, R)`, respectively. */
  606. inline constexpr detail::stl_interfaces::adaptor<detail::search_all_impl>
  607. search_all = detail::search_all_impl{};
  608. }
  609. #if BOOST_PARSER_USE_CONCEPTS
  610. template<
  611. typename V,
  612. typename Parser,
  613. typename GlobalState,
  614. typename ErrorHandler,
  615. typename SkipParser>
  616. constexpr bool std::ranges::enable_borrowed_range<
  617. boost::parser::
  618. search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
  619. std::ranges::enable_borrowed_range<V>;
  620. #endif
  621. #endif