| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674 |
- #ifndef BOOST_PARSER_SEARCH_HPP
- #define BOOST_PARSER_SEARCH_HPP
- #include <boost/parser/parser.hpp>
- #include <boost/parser/transcode_view.hpp>
- #include <cstring>
- namespace boost::parser {
- namespace detail {
- template<bool Const, typename T>
- using maybe_const = std::conditional_t<Const, const T, T>;
- inline constexpr text::format no_format = text::format::none;
- template<text::format Format = text::format::utf8>
- constexpr auto as_utf =
- text::detail::as_utf_impl<text::utf8_view, text::format::utf8>{};
- template<>
- constexpr auto as_utf<text::format::utf16> =
- text::detail::as_utf_impl<text::utf16_view, text::format::utf16>{};
- template<>
- constexpr auto as_utf<text::format::utf32> =
- text::detail::as_utf_impl<text::utf32_view, text::format::utf32>{};
- template<
- typename R_,
- bool ToCommonRange = false,
- text::format OtherRangeFormat = no_format,
- bool = std::is_same_v<sentinel_t<remove_cv_ref_t<R_>>,
- null_sentinel_t> ||
- text::detail::is_bounded_array_v<remove_cv_ref_t<R_>>>
- struct to_range
- {
- template<typename R>
- static constexpr auto call(R && r)
- {
- static_assert(std::is_same_v<R, R_>);
- using T = remove_cv_ref_t<R>;
- if constexpr (std::is_same_v<sentinel_t<T>, null_sentinel_t>) {
- auto plus_strlen = [](auto * ptr) {
- while (*ptr) {
- ++ptr;
- }
- return ptr;
- };
- auto const first = r.begin();
- if constexpr (OtherRangeFormat == no_format) {
- if constexpr (ToCommonRange) {
- return BOOST_PARSER_SUBRANGE(
- first, plus_strlen(first));
- } else {
- return (R &&) r;
- }
- } else {
- if constexpr (ToCommonRange) {
- return BOOST_PARSER_SUBRANGE(
- first, plus_strlen(first)) |
- as_utf<OtherRangeFormat>;
- } else {
- return (R &&) r | as_utf<OtherRangeFormat>;
- }
- }
- } else if constexpr (text::detail::is_bounded_array_v<T>) {
- auto const first = std::begin(r);
- auto last = std::end(r);
- constexpr auto n = std::extent_v<T>;
- if (n && !r[n - 1])
- --last;
- if constexpr (OtherRangeFormat == no_format) {
- return BOOST_PARSER_SUBRANGE(first, last);
- } else {
- return BOOST_PARSER_SUBRANGE(first, last) |
- as_utf<OtherRangeFormat>;
- }
- } else {
- return (R &&) r | as_utf<OtherRangeFormat>;
- }
- }
- };
- template<typename R_, bool ToCommonRange>
- struct to_range<R_, ToCommonRange, no_format, false>
- {
- template<typename R>
- static constexpr R && call(R && r)
- {
- return (R &&) r;
- }
- };
- template<typename R>
- using to_range_t = decltype(to_range<R>::call(std::declval<R>()));
- struct phony
- {};
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- auto search_impl(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode)
- {
- auto first = text::detail::begin(r);
- auto const last = text::detail::end(r);
- if (first == last)
- return BOOST_PARSER_SUBRANGE(first, first);
- auto const search_parser = omit[*(char_ - parser)] >> -raw[parser];
- if constexpr (std::is_same_v<SkipParser, eps_parser<phony>>) {
- auto result = parser::prefix_parse(
- first, last, search_parser, trace_mode);
- if (*result)
- return **result;
- } else {
- auto result = parser::prefix_parse(
- first, last, search_parser, skip, trace_mode);
- if (*result)
- return **result;
- }
- return BOOST_PARSER_SUBRANGE(first, first);
- }
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- #if BOOST_PARSER_USE_CONCEPTS
- std::ranges::borrowed_subrange_t<R>
- #else
- auto
- #endif
- search_repack_shim(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode)
- {
- using value_type = range_value_t<decltype(r)>;
- if constexpr (std::is_same_v<value_type, char>) {
- return detail::search_impl((R &&) r, parser, skip, trace_mode);
- } else {
- auto r_unpacked = detail::text::unpack_iterator_and_sentinel(
- text::detail::begin(r), text::detail::end(r));
- auto result =
- detail::search_impl(r | as_utf32, parser, skip, trace_mode);
- return BOOST_PARSER_SUBRANGE(
- r_unpacked.repack(text::detail::begin(result).base()),
- r_unpacked.repack(text::detail::end(result).base()));
- }
- }
- template<typename T>
- constexpr bool is_parser_iface = false;
- template<typename T>
- constexpr bool is_parser_iface<parser_interface<T>> = true;
- }
- /** Returns a subrange to the first match for parser `parser` in `r`,
- using skip-parser `skip`. This function has a similar interface and
- semantics to `std::ranges::search()`. Returns `std::ranges::dangling`
- in C++20 and later if `r` is a non-borrowable rvalue. */
- template<
- #if BOOST_PARSER_USE_CONCEPTS
- parsable_range R,
- #else
- typename R,
- #endif
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser
- #if !BOOST_PARSER_USE_CONCEPTS
- ,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
- #endif
- >
- auto search(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off)
- {
- return detail::search_repack_shim(
- detail::to_range<R>::call((R &&) r), parser, skip, trace_mode);
- }
- /** Returns a subrange to the first match for parser `parser` in `[first,
- last)`, using skip-parser `skip`. This function has a similar
- interface and semantics to `std::ranges::search()`. */
- template<
- #if BOOST_PARSER_USE_CONCEPTS
- parsable_iter I,
- std::sentinel_for<I> S,
- #else
- typename I,
- typename S,
- #endif
- typename Parser,
- typename SkipParser,
- typename GlobalState,
- #if BOOST_PARSER_USE_CONCEPTS
- error_handler<I, S, GlobalState> ErrorHandler
- #else
- typename ErrorHandler,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>
- #endif
- >
- auto search(
- I first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off)
- {
- return parser::search(
- BOOST_PARSER_SUBRANGE(first, last), parser, skip, trace_mode);
- }
- /** Returns a subrange to the first match for parser `parser` in `r`.
- This function has a similar interface and semantics to
- `std::ranges::search()`. Returns `std::ranges::dangling` in C++20 and
- later if `r` is a non-borrowable rvalue. */
- template<
- #if BOOST_PARSER_USE_CONCEPTS
- parsable_range R,
- #else
- typename R,
- #endif
- typename Parser,
- typename GlobalState,
- typename ErrorHandler
- #if !BOOST_PARSER_USE_CONCEPTS
- ,
- typename Enable = std::enable_if_t<detail::is_parsable_range_v<R>>
- #endif
- >
- auto search(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- trace trace_mode = trace::off)
- {
- return parser::search(
- (R &&) r,
- parser,
- parser_interface<eps_parser<detail::phony>>{},
- trace_mode);
- }
- /** Returns a subrange to the first match for parser `parser` in `[first,
- last)`. This function has a similar interface and semantics to
- `std::ranges::search()`. */
- template<
- #if BOOST_PARSER_USE_CONCEPTS
- parsable_iter I,
- std::sentinel_for<I> S,
- #else
- typename I,
- typename S,
- #endif
- typename Parser,
- typename GlobalState,
- #if BOOST_PARSER_USE_CONCEPTS
- error_handler<I, S, GlobalState> ErrorHandler
- #else
- typename ErrorHandler,
- typename Enable = std::enable_if_t<
- detail::is_parsable_iter_v<I> &&
- detail::is_equality_comparable_with_v<I, S>>
- #endif
- >
- auto search(
- I first,
- S last,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- trace trace_mode = trace::off)
- {
- return parser::search(
- BOOST_PARSER_SUBRANGE(first, last),
- parser,
- parser_interface<eps_parser<detail::phony>>{},
- trace_mode);
- }
- /** Produces a sequence of subranges of the underlying sequence of type
- `V`. Each subrange is a nonoverlapping match of the given parser,
- using a skip-parser if provided. */
- template<
- #if BOOST_PARSER_USE_CONCEPTS
- std::ranges::viewable_range V,
- #else
- typename V,
- #endif
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- struct search_all_view
- : detail::stl_interfaces::view_interface<
- search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>>
- {
- constexpr search_all_view() = default;
- constexpr search_all_view(
- V base,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off) :
- base_(std::move(base)),
- parser_(parser),
- skip_(skip),
- trace_mode_(trace_mode)
- {}
- constexpr search_all_view(
- V base,
- parser_interface<Parser, GlobalState, ErrorHandler> const & parser,
- trace trace_mode = trace::off) :
- base_(std::move(base)),
- parser_(parser),
- skip_(),
- trace_mode_(trace_mode)
- {}
- constexpr V base() const &
- #if BOOST_PARSER_USE_CONCEPTS
- requires std::copy_constructible<V>
- #endif
- {
- return base_;
- }
- constexpr V base() && { return std::move(base_); }
- constexpr auto begin() { return iterator<false>{this}; }
- constexpr auto end() { return sentinel<false>{}; }
- constexpr auto begin() const
- #if BOOST_PARSER_USE_CONCEPTS
- requires std::ranges::range<const V>
- #endif
- {
- return iterator<true>{this};
- }
- constexpr auto end() const
- #if BOOST_PARSER_USE_CONCEPTS
- requires std::ranges::range<const V>
- #endif
- {
- return sentinel<true>{};
- }
- template<bool Const>
- struct sentinel
- {};
- template<bool Const>
- struct iterator
- : detail::stl_interfaces::proxy_iterator_interface<
- iterator<Const>,
- std::forward_iterator_tag,
- BOOST_PARSER_SUBRANGE<
- detail::iterator_t<detail::maybe_const<Const, V>>>>
- {
- using I = detail::iterator_t<detail::maybe_const<Const, V>>;
- using S = detail::sentinel_t<detail::maybe_const<Const, V>>;
- constexpr iterator() = default;
- constexpr iterator(
- detail::maybe_const<Const, search_all_view> * parent) :
- parent_(parent),
- r_(parent_->base_.begin(), parent_->base_.end()),
- curr_(r_.begin(), r_.begin()),
- next_it_(r_.begin())
- {
- ++*this;
- }
- constexpr iterator & operator++()
- {
- r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
- curr_ = parser::search(
- r_, parent_->parser_, parent_->skip_, parent_->trace_mode_);
- next_it_ = curr_.end();
- if (curr_.begin() == curr_.end())
- r_ = BOOST_PARSER_SUBRANGE<I, S>(next_it_, r_.end());
- return *this;
- }
- constexpr BOOST_PARSER_SUBRANGE<I> operator*() const
- {
- return curr_;
- }
- friend constexpr bool operator==(iterator lhs, iterator rhs)
- {
- return lhs.r_.begin() == rhs.r_.begin();
- }
- friend constexpr bool operator==(iterator it, sentinel<Const>)
- {
- return it.r_.begin() == it.r_.end();
- }
- using base_type = detail::stl_interfaces::proxy_iterator_interface<
- iterator,
- std::forward_iterator_tag,
- BOOST_PARSER_SUBRANGE<I>>;
- using base_type::operator++;
- private:
- detail::maybe_const<Const, search_all_view> * parent_;
- BOOST_PARSER_SUBRANGE<I, S> r_;
- BOOST_PARSER_SUBRANGE<I> curr_;
- I next_it_;
- };
- template<bool Const>
- friend struct iterator;
- private:
- V base_;
- parser_interface<Parser, GlobalState, ErrorHandler> parser_;
- parser_interface<SkipParser> skip_;
- trace trace_mode_;
- };
- // deduction guides
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- search_all_view(
- V &&,
- parser_interface<Parser, GlobalState, ErrorHandler>,
- parser_interface<SkipParser>,
- trace)
- -> search_all_view<
- detail::text::detail::all_t<V>,
- Parser,
- GlobalState,
- ErrorHandler,
- SkipParser>;
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- search_all_view(
- V &&,
- parser_interface<Parser, GlobalState, ErrorHandler>,
- parser_interface<SkipParser>)
- -> search_all_view<
- detail::text::detail::all_t<V>,
- Parser,
- GlobalState,
- ErrorHandler,
- SkipParser>;
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler>
- search_all_view(
- V &&, parser_interface<Parser, GlobalState, ErrorHandler>, trace)
- -> search_all_view<
- detail::text::detail::all_t<V>,
- Parser,
- GlobalState,
- ErrorHandler,
- parser_interface<eps_parser<detail::phony>>>;
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler>
- search_all_view(V &&, parser_interface<Parser, GlobalState, ErrorHandler>)
- -> search_all_view<
- detail::text::detail::all_t<V>,
- Parser,
- GlobalState,
- ErrorHandler,
- parser_interface<eps_parser<detail::phony>>>;
- namespace detail {
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- using search_all_view_expr = decltype(search_all_view<
- V,
- Parser,
- GlobalState,
- ErrorHandler,
- SkipParser>(
- std::declval<V>(),
- std::declval<
- parser_interface<Parser, GlobalState, ErrorHandler> const &>(),
- std::declval<parser_interface<SkipParser> const &>(),
- trace::on));
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- constexpr bool can_search_all_view = is_detected_v<
- search_all_view_expr,
- V,
- Parser,
- GlobalState,
- ErrorHandler,
- SkipParser>;
- struct search_all_impl
- {
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- requires(std::ranges::viewable_range<R>) && can_search_all_view<
- to_range_t<R>,
- Parser,
- GlobalState,
- ErrorHandler,
- SkipParser>
- [[nodiscard]] constexpr auto operator()(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const &
- parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off) const
- {
- return search_all_view(
- to_range<R>::call((R &&)r), parser, skip, trace_mode);
- }
- template<
- parsable_range R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler>
- requires(std::ranges::viewable_range<R>) &&
- can_search_all_view<
- to_range_t<R>,
- Parser,
- GlobalState,
- ErrorHandler,
- parser_interface<eps_parser<detail::phony>>>
- [[nodiscard]] constexpr auto operator()(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const &
- parser,
- trace trace_mode = trace::off) const
- {
- return (*this)(
- (R &&)r,
- parser,
- parser_interface<eps_parser<detail::phony>>{},
- trace_mode);
- }
- #else
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser =
- parser_interface<eps_parser<detail::phony>>,
- typename Trace = trace,
- typename Enable = std::enable_if_t<is_parsable_range_v<R>>>
- [[nodiscard]] constexpr auto operator()(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const &
- parser,
- SkipParser const & skip = SkipParser{},
- Trace trace_mode = Trace{}) const
- {
- if constexpr (
- std::
- is_same_v<detail::remove_cv_ref_t<SkipParser>, trace> &&
- std::is_same_v<Trace, trace>) {
- // (r, parser, trace) case
- return impl(
- (R &&) r,
- parser,
- parser_interface<eps_parser<detail::phony>>{},
- skip);
- } else if constexpr (
- detail::is_parser_iface<SkipParser> &&
- std::is_same_v<Trace, trace>) {
- // (r, parser, skip, trace) case
- return impl((R &&) r, parser, skip, trace_mode);
- } else {
- static_assert(
- sizeof(R) == 1 && false,
- "Only the signatures search_all(R, parser, skip, trace "
- "= trace::off) and search_all(R, parser, trace = "
- "trace::off) are supported.");
- }
- }
- private:
- template<
- typename R,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- [[nodiscard]] constexpr auto impl(
- R && r,
- parser_interface<Parser, GlobalState, ErrorHandler> const &
- parser,
- parser_interface<SkipParser> const & skip,
- trace trace_mode = trace::off) const
- {
- return search_all_view(
- to_range<R>::call((R &&) r), parser, skip, trace_mode);
- }
- #endif
- };
- }
- /** A range adaptor object ([range.adaptor.object]). Given subexpressions
- `E` and `P`, `Q`, and `R`, each of the expressions `search_all(E, P)`,
- `search_all(E, P, Q)`, and `search_all(E, P, Q, R)` are
- expression-equivalent to `search_all_view(E, P)`, `search_all_view(E,
- P, Q)`, and `search_all_view(E, P, Q, R)`, respectively. */
- inline constexpr detail::stl_interfaces::adaptor<detail::search_all_impl>
- search_all = detail::search_all_impl{};
- }
- #if BOOST_PARSER_USE_CONCEPTS
- template<
- typename V,
- typename Parser,
- typename GlobalState,
- typename ErrorHandler,
- typename SkipParser>
- constexpr bool std::ranges::enable_borrowed_range<
- boost::parser::
- search_all_view<V, Parser, GlobalState, ErrorHandler, SkipParser>> =
- std::ranges::enable_borrowed_range<V>;
- #endif
- #endif
|