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