replace.hpp 25 KB

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