File indexing completed on 2025-09-17 08:40:35
0001 #ifndef BOOST_PARSER_SEARCH_HPP
0002 #define BOOST_PARSER_SEARCH_HPP
0003
0004 #include <boost/parser/parser.hpp>
0005 #include <boost/parser/transcode_view.hpp>
0006
0007 #include <cstring>
0008
0009
0010 namespace boost::parser {
0011
0012 namespace detail {
0013 template<bool Const, typename T>
0014 using maybe_const = std::conditional_t<Const, const T, T>;
0015
0016 inline constexpr text::format no_format = text::format::none;
0017
0018 template<text::format Format = text::format::utf8>
0019 constexpr auto as_utf =
0020 text::detail::as_utf_impl<text::utf8_view, text::format::utf8>{};
0021 template<>
0022 constexpr auto as_utf<text::format::utf16> =
0023 text::detail::as_utf_impl<text::utf16_view, text::format::utf16>{};
0024 template<>
0025 constexpr auto as_utf<text::format::utf32> =
0026 text::detail::as_utf_impl<text::utf32_view, text::format::utf32>{};
0027
0028 template<
0029 typename R_,
0030 bool ToCommonRange = false,
0031 text::format OtherRangeFormat = no_format,
0032 bool = std::is_same_v<sentinel_t<remove_cv_ref_t<R_>>,
0033 null_sentinel_t> ||
0034 text::detail::is_bounded_array_v<remove_cv_ref_t<R_>>>
0035 struct to_range
0036 {
0037 template<typename R>
0038 static constexpr auto call(R && r)
0039 {
0040 static_assert(std::is_same_v<R, R_>);
0041 using T = remove_cv_ref_t<R>;
0042 if constexpr (std::is_same_v<sentinel_t<T>, null_sentinel_t>) {
0043 auto plus_strlen = [](auto * ptr) {
0044 while (*ptr) {
0045 ++ptr;
0046 }
0047 return ptr;
0048 };
0049 auto const first = r.begin();
0050 if constexpr (OtherRangeFormat == no_format) {
0051 if constexpr (ToCommonRange) {
0052 return BOOST_PARSER_SUBRANGE(
0053 first, plus_strlen(first));
0054 } else {
0055 return (R &&) r;
0056 }
0057 } else {
0058 if constexpr (ToCommonRange) {
0059 return BOOST_PARSER_SUBRANGE(
0060 first, plus_strlen(first)) |
0061 as_utf<OtherRangeFormat>;
0062 } else {
0063 return (R &&) r | as_utf<OtherRangeFormat>;
0064 }
0065 }
0066 } else if constexpr (text::detail::is_bounded_array_v<T>) {
0067 auto const first = std::begin(r);
0068 auto last = std::end(r);
0069 constexpr auto n = std::extent_v<T>;
0070 if (n && !r[n - 1])
0071 --last;
0072 if constexpr (OtherRangeFormat == no_format) {
0073 return BOOST_PARSER_SUBRANGE(first, last);
0074 } else {
0075 return BOOST_PARSER_SUBRANGE(first, last) |
0076 as_utf<OtherRangeFormat>;
0077 }
0078 } else {
0079 return (R &&) r | as_utf<OtherRangeFormat>;
0080 }
0081 }
0082 };
0083
0084 template<typename R_, bool ToCommonRange>
0085 struct to_range<R_, ToCommonRange, no_format, false>
0086 {
0087 template<typename R>
0088 static constexpr R && call(R && r)
0089 {
0090 return (R &&) r;
0091 }
0092 };
0093
0094 template<typename R>
0095 using to_range_t = decltype(to_range<R>::call(std::declval<R>()));
0096
0097 struct phony
0098 {};
0099
0100 template<
0101 typename R,
0102 typename Parser,
0103 typename GlobalState,
0104 typename ErrorHandler,
0105 typename SkipParser>
0106 auto search_impl(
0107 R && r,
0108 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0109 parser_interface<SkipParser> const & skip,
0110 trace trace_mode)
0111 {
0112 auto first = text::detail::begin(r);
0113 auto const last = text::detail::end(r);
0114
0115 if (first == last)
0116 return BOOST_PARSER_SUBRANGE(first, first);
0117
0118 auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
0119 if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
0120 auto result = parser::prefix_parse(
0121 first, last, search_parser, trace_mode);
0122 if (*result)
0123 return **result;
0124 } else {
0125 auto result = parser::prefix_parse(
0126 first, last, search_parser, skip, trace_mode);
0127 if (*result)
0128 return **result;
0129 }
0130
0131 return BOOST_PARSER_SUBRANGE(first, first);
0132 }
0133
0134 template<
0135 typename R,
0136 typename Parser,
0137 typename GlobalState,
0138 typename ErrorHandler,
0139 typename SkipParser>
0140 #if BOOST_PARSER_USE_CONCEPTS
0141 std::ranges::borrowed_subrange_t<R>
0142 #else
0143 auto
0144 #endif
0145 search_repack_shim(
0146 R && r,
0147 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0148 parser_interface<SkipParser> const & skip,
0149 trace trace_mode)
0150 {
0151 using value_type = range_value_t<decltype(r)>;
0152 if constexpr (std::is_same_v<value_type, char>) {
0153 return detail::search_impl((R &&) r, parser, skip, trace_mode);
0154 } else {
0155 auto r_unpacked = detail::text::unpack_iterator_and_sentinel(
0156 text::detail::begin(r), text::detail::end(r));
0157 auto result =
0158 detail::search_impl(r | as_utf32, parser, skip, trace_mode);
0159 return BOOST_PARSER_SUBRANGE(
0160 r_unpacked.repack(text::detail::begin(result).base()),
0161 r_unpacked.repack(text::detail::end(result).base()));
0162 }
0163 }
0164
0165 template<typename T>
0166 constexpr bool is_parser_iface = false;
0167 template<typename T>
0168 constexpr bool is_parser_iface<parser_interface<T>> = true;
0169 }
0170
0171
0172
0173
0174
0175 template<
0176 #if BOOST_PARSER_USE_CONCEPTS
0177 parsable_range R,
0178 #else
0179 typename R,
0180 #endif
0181 typename Parser,
0182 typename GlobalState,
0183 typename ErrorHandler,
0184 typename SkipParser
0185 #if !BOOST_PARSER_USE_CONCEPTS
0186 ,
0187 typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
0188 #endif
0189 >
0190 auto search(
0191 R && r,
0192 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0193 parser_interface<SkipParser> const & skip,
0194 trace trace_mode = trace::off)
0195 {
0196 return detail::search_repack_shim(
0197 detail::to_range<R>::call((R &&) r), parser, skip, trace_mode);
0198 }
0199
0200
0201
0202
0203 template<
0204 #if BOOST_PARSER_USE_CONCEPTS
0205 parsable_iter I,
0206 std::sentinel_for<I> S,
0207 #else
0208 typename I,
0209 typename S,
0210 #endif
0211 typename Parser,
0212 typename SkipParser,
0213 typename GlobalState,
0214 #if BOOST_PARSER_USE_CONCEPTS
0215 error_handler<I, S, GlobalState> ErrorHandler
0216 #else
0217 typename ErrorHandler,
0218 typename Enable = std::enable_if_t<
0219 detail::is_parsable_iter_v<I> &&
0220 detail::is_equality_comparable_with_v<I, S>>
0221 #endif
0222 >
0223 auto search(
0224 I first,
0225 S last,
0226 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0227 parser_interface<SkipParser> const & skip,
0228 trace trace_mode = trace::off)
0229 {
0230 return parser::search(
0231 BOOST_PARSER_SUBRANGE(first, last), parser, skip, trace_mode);
0232 }
0233
0234
0235
0236
0237
0238 template<
0239 #if BOOST_PARSER_USE_CONCEPTS
0240 parsable_range R,
0241 #else
0242 typename R,
0243 #endif
0244 typename Parser,
0245 typename GlobalState,
0246 typename ErrorHandler
0247 #if !BOOST_PARSER_USE_CONCEPTS
0248 ,
0249 typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
0250 #endif
0251 >
0252 auto search(
0253 R && r,
0254 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0255 trace trace_mode = trace::off)
0256 {
0257 return parser::search(
0258 (R &&) r,
0259 parser,
0260 parser_interface<eps_parser<detail::phony>>{},
0261 trace_mode);
0262 }
0263
0264
0265
0266
0267 template<
0268 #if BOOST_PARSER_USE_CONCEPTS
0269 parsable_iter I,
0270 std::sentinel_for<I> S,
0271 #else
0272 typename I,
0273 typename S,
0274 #endif
0275 typename Parser,
0276 typename GlobalState,
0277 #if BOOST_PARSER_USE_CONCEPTS
0278 error_handler<I, S, GlobalState> ErrorHandler
0279 #else
0280 typename ErrorHandler,
0281 typename Enable = std::enable_if_t<
0282 detail::is_parsable_iter_v<I> &&
0283 detail::is_equality_comparable_with_v<I, S>>
0284 #endif
0285 >
0286 auto search(
0287 I first,
0288 S last,
0289 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0290 trace trace_mode = trace::off)
0291 {
0292 return parser::search(
0293 BOOST_PARSER_SUBRANGE(first, last),
0294 parser,
0295 parser_interface<eps_parser<detail::phony>>{},
0296 trace_mode);
0297 }
0298
0299
0300
0301
0302 template<
0303 #if BOOST_PARSER_USE_CONCEPTS
0304 std::ranges::viewable_range V,
0305 #else
0306 typename V,
0307 #endif
0308 typename Parser,
0309 typename GlobalState,
0310 typename ErrorHandler,
0311 typename SkipParser>
0312 struct search_all_view
0313 : detail::stl_interfaces::view_interface<
0314 search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
0315 {
0316 constexpr search_all_view() = default;
0317 constexpr search_all_view(
0318 V base,
0319 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0320 parser_interface<SkipParser> const & skip,
0321 trace trace_mode = trace::off) :
0322 base_(std::move(base)),
0323 parser_(parser),
0324 skip_(skip),
0325 trace_mode_(trace_mode)
0326 {}
0327 constexpr search_all_view(
0328 V base,
0329 parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
0330 trace trace_mode = trace::off) :
0331 base_(std::move(base)),
0332 parser_(parser),
0333 skip_(),
0334 trace_mode_(trace_mode)
0335 {}
0336
0337 constexpr V base() const &
0338 #if BOOST_PARSER_USE_CONCEPTS
0339 requires std::copy_constructible<V>
0340 #endif
0341 {
0342 return base_;
0343 }
0344 constexpr V base() && { return std::move(base_); }
0345
0346 constexpr auto begin() { return iterator<false>{this}; }
0347 constexpr auto end() { return sentinel<false>{}; }
0348
0349 constexpr auto begin() const
0350 #if BOOST_PARSER_USE_CONCEPTS
0351 requires std::ranges::range<const V>
0352 #endif
0353 {
0354 return iterator<true>{this};
0355 }
0356 constexpr auto end() const
0357 #if BOOST_PARSER_USE_CONCEPTS
0358 requires std::ranges::range<const V>
0359 #endif
0360 {
0361 return sentinel<true>{};
0362 }
0363
0364 template<bool Const>
0365 struct sentinel
0366 {};
0367
0368 template<bool Const>
0369 struct iterator
0370 : detail::stl_interfaces::proxy_iterator_interface<
0371 iterator<Const>,
0372 std::forward_iterator_tag,
0373 BOOST_PARSER_SUBRANGE<
0374 detail::iterator_t<detail::maybe_const<Const, V>>>>
0375 {
0376 using I = detail::iterator_t<detail::maybe_const<Const, V>>;
0377 using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
0378
0379 constexpr iterator() = default;
0380 constexpr iterator(
0381 detail::maybe_const<Const, search_all_view> * parent) :
0382 parent_(parent),
0383 r_(parent_->base_.begin(), parent_->base_.end()),
0384 curr_(r_.begin(), r_.begin()),
0385 next_it_(r_.begin())
0386 {
0387 ++*this;
0388 }
0389
0390 constexpr iterator & operator++()
0391 {
0392 r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
0393 curr_ = parser::search(
0394 r_, parent_->parser_, parent_->skip_, parent_->trace_mode_);
0395 next_it_ = curr_.end();
0396 if (curr_.begin() == curr_.end())
0397 r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
0398 return *this;
0399 }
0400
0401 constexpr BOOST_PARSER_SUBRANGE<I> operator*() const
0402 {
0403 return curr_;
0404 }
0405
0406 friend constexpr bool operator==(iterator lhs, iterator rhs)
0407 {
0408 return lhs.r_.begin() == rhs.r_.begin();
0409 }
0410 friend constexpr bool operator==(iterator it, sentinel<Const>)
0411 {
0412 return it.r_.begin() == it.r_.end();
0413 }
0414
0415 using base_type = detail::stl_interfaces::proxy_iterator_interface<
0416 iterator,
0417 std::forward_iterator_tag,
0418 BOOST_PARSER_SUBRANGE<I>>;
0419 using base_type::operator++;
0420
0421 private:
0422 detail::maybe_const<Const, search_all_view> * parent_;
0423 BOOST_PARSER_SUBRANGE<I, S> r_;
0424 BOOST_PARSER_SUBRANGE<I> curr_;
0425 I next_it_;
0426 };
0427
0428 template<bool Const>
0429 friend struct iterator;
0430
0431 private:
0432 V base_;
0433 parser_interface<Parser, GlobalState, ErrorHandler> parser_;
0434 parser_interface<SkipParser> skip_;
0435 trace trace_mode_;
0436 };
0437
0438
0439 template<
0440 typename V,
0441 typename Parser,
0442 typename GlobalState,
0443 typename ErrorHandler,
0444 typename SkipParser>
0445 search_all_view(
0446 V &&,
0447 parser_interface<Parser, GlobalState, ErrorHandler>,
0448 parser_interface<SkipParser>,
0449 trace)
0450 -> search_all_view<
0451 detail::text::detail::all_t<V>,
0452 Parser,
0453 GlobalState,
0454 ErrorHandler,
0455 SkipParser>;
0456
0457 template<
0458 typename V,
0459 typename Parser,
0460 typename GlobalState,
0461 typename ErrorHandler,
0462 typename SkipParser>
0463 search_all_view(
0464 V &&,
0465 parser_interface<Parser, GlobalState, ErrorHandler>,
0466 parser_interface<SkipParser>)
0467 -> search_all_view<
0468 detail::text::detail::all_t<V>,
0469 Parser,
0470 GlobalState,
0471 ErrorHandler,
0472 SkipParser>;
0473
0474 template<
0475 typename V,
0476 typename Parser,
0477 typename GlobalState,
0478 typename ErrorHandler>
0479 search_all_view(
0480 V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
0481 -> search_all_view<
0482 detail::text::detail::all_t<V>,
0483 Parser,
0484 GlobalState,
0485 ErrorHandler,
0486 parser_interface<eps_parser<detail::phony>>>;
0487
0488 template<
0489 typename V,
0490 typename Parser,
0491 typename GlobalState,
0492 typename ErrorHandler>
0493 search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
0494 -> search_all_view<
0495 detail::text::detail::all_t<V>,
0496 Parser,
0497 GlobalState,
0498 ErrorHandler,
0499 parser_interface<eps_parser<detail::phony>>>;
0500
0501 namespace detail {
0502 template<
0503 typename V,
0504 typename Parser,
0505 typename GlobalState,
0506 typename ErrorHandler,
0507 typename SkipParser>
0508 using search_all_view_expr = decltype(search_all_view<
0509 V,
0510 Parser,
0511 GlobalState,
0512 ErrorHandler,
0513 SkipParser>(
0514 std::declval<V>(),
0515 std::declval<
0516 parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
0517 std::declval<parser_interface<SkipParser> const &>(),
0518 trace::on));
0519
0520 template<
0521 typename V,
0522 typename Parser,
0523 typename GlobalState,
0524 typename ErrorHandler,
0525 typename SkipParser>
0526 constexpr bool can_search_all_view = is_detected_v<
0527 search_all_view_expr,
0528 V,
0529 Parser,
0530 GlobalState,
0531 ErrorHandler,
0532 SkipParser>;
0533
0534 struct search_all_impl
0535 {
0536 #if BOOST_PARSER_USE_CONCEPTS
0537
0538 template<
0539 parsable_range R,
0540 typename Parser,
0541 typename GlobalState,
0542 typename ErrorHandler,
0543 typename SkipParser>
0544 requires(std::ranges::viewable_range<R>) && can_search_all_view<
0545 to_range_t<R>,
0546 Parser,
0547 GlobalState,
0548 ErrorHandler,
0549 SkipParser>
0550 [[nodiscard]] constexpr auto operator()(
0551 R && r,
0552 parser_interface<Parser, GlobalState, ErrorHandler> const &
0553 parser,
0554 parser_interface<SkipParser> const & skip,
0555 trace trace_mode = trace::off) const
0556 {
0557 return search_all_view(
0558 to_range<R>::call((R &&)r), parser, skip, trace_mode);
0559 }
0560
0561 template<
0562 parsable_range R,
0563 typename Parser,
0564 typename GlobalState,
0565 typename ErrorHandler>
0566 requires(std::ranges::viewable_range<R>) &&
0567 can_search_all_view<
0568 to_range_t<R>,
0569 Parser,
0570 GlobalState,
0571 ErrorHandler,
0572 parser_interface<eps_parser<detail::phony>>>
0573 [[nodiscard]] constexpr auto operator()(
0574 R && r,
0575 parser_interface<Parser, GlobalState, ErrorHandler> const &
0576 parser,
0577 trace trace_mode = trace::off) const
0578 {
0579 return (*this)(
0580 (R &&)r,
0581 parser,
0582 parser_interface<eps_parser<detail::phony>>{},
0583 trace_mode);
0584 }
0585
0586 #else
0587
0588 template<
0589 typename R,
0590 typename Parser,
0591 typename GlobalState,
0592 typename ErrorHandler,
0593 typename SkipParser =
0594 parser_interface<eps_parser<detail::phony>>,
0595 typename Trace = trace,
0596 typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
0597 [[nodiscard]] constexpr auto operator()(
0598 R && r,
0599 parser_interface<Parser, GlobalState, ErrorHandler> const &
0600 parser,
0601 SkipParser const & skip = SkipParser{},
0602 Trace trace_mode = Trace{}) const
0603 {
0604 if constexpr (
0605 std::
0606 is_same_v<detail::remove_cv_ref_t<SkipParser>, trace> &&
0607 std::is_same_v<Trace, trace>) {
0608
0609 return impl(
0610 (R &&) r,
0611 parser,
0612 parser_interface<eps_parser<detail::phony>>{},
0613 skip);
0614 } else if constexpr (
0615 detail::is_parser_iface<SkipParser> &&
0616 std::is_same_v<Trace, trace>) {
0617
0618 return impl((R &&) r, parser, skip, trace_mode);
0619 } else {
0620 static_assert(
0621 sizeof(R) == 1 && false,
0622 "Only the signatures search_all(R, parser, skip, trace "
0623 "= trace::off) and search_all(R, parser, trace = "
0624 "trace::off) are supported.");
0625 }
0626 }
0627
0628 private:
0629 template<
0630 typename R,
0631 typename Parser,
0632 typename GlobalState,
0633 typename ErrorHandler,
0634 typename SkipParser>
0635 [[nodiscard]] constexpr auto impl(
0636 R && r,
0637 parser_interface<Parser, GlobalState, ErrorHandler> const &
0638 parser,
0639 parser_interface<SkipParser> const & skip,
0640 trace trace_mode = trace::off) const
0641 {
0642 return search_all_view(
0643 to_range<R>::call((R &&) r), parser, skip, trace_mode);
0644 }
0645
0646 #endif
0647 };
0648 }
0649
0650
0651
0652
0653
0654
0655 inline constexpr detail::stl_interfaces::adaptor<detail::search_all_impl>
0656 search_all = detail::search_all_impl{};
0657
0658 }
0659
0660 #if BOOST_PARSER_USE_CONCEPTS
0661 template<
0662 typename V,
0663 typename Parser,
0664 typename GlobalState,
0665 typename ErrorHandler,
0666 typename SkipParser>
0667 constexpr bool std::ranges::enable_borrowed_range<
0668 boost::parser::
0669 search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
0670 std::ranges::enable_borrowed_range<V>;
0671 #endif
0672
0673 #endif