transcode_view.hpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. // Copyright (C) 2020 T. Zachary Laine
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP
  7. #define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP
  8. #include <boost/parser/detail/text/transcode_algorithm.hpp>
  9. #include <boost/parser/detail/text/transcode_iterator.hpp>
  10. #include <boost/parser/detail/text/detail/all_t.hpp>
  11. #include <boost/parser/detail/stl_interfaces/view_interface.hpp>
  12. #include <boost/parser/detail/stl_interfaces/view_adaptor.hpp>
  13. #include <climits>
  14. namespace boost::parser::detail { namespace text {
  15. namespace detail {
  16. template<class I>
  17. constexpr auto iterator_to_tag()
  18. {
  19. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  20. if constexpr (std::random_access_iterator<I>) {
  21. return std::random_access_iterator_tag{};
  22. } else if constexpr (std::bidirectional_iterator<I>) {
  23. return std::bidirectional_iterator_tag{};
  24. } else if constexpr (std::forward_iterator<I>) {
  25. #else
  26. if constexpr (detail::random_access_iterator_v<I>) {
  27. return std::random_access_iterator_tag{};
  28. } else if constexpr (detail::bidirectional_iterator_v<I>) {
  29. return std::bidirectional_iterator_tag{};
  30. } else if constexpr (detail::forward_iterator_v<I>) {
  31. #endif
  32. return std::forward_iterator_tag{};
  33. } else {
  34. return std::input_iterator_tag{};
  35. }
  36. }
  37. template<class I>
  38. using iterator_to_tag_t = decltype(iterator_to_tag<I>());
  39. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  40. template<class T>
  41. using with_reference = T &;
  42. template<typename T>
  43. concept can_reference = requires { typename with_reference<T>; };
  44. #endif
  45. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  46. template<class Char>
  47. struct cast_to_charn {
  48. constexpr Char operator()(Char c) const { return c; }
  49. };
  50. #else
  51. struct cast_to_char8;
  52. struct cast_to_char16;
  53. struct cast_to_char32;
  54. template<typename Tag, typename Arg>
  55. auto function_for_tag(Arg arg)
  56. {
  57. #if defined(__cpp_char8_t)
  58. if constexpr (std::is_same_v<Tag, cast_to_char8>) {
  59. return (char8_t)arg;
  60. } else
  61. #endif
  62. if constexpr (std::is_same_v<Tag, cast_to_char16>) {
  63. return (char16_t)arg;
  64. } else if constexpr (std::is_same_v<Tag, cast_to_char32>) {
  65. return (char32_t)arg;
  66. }
  67. }
  68. #endif
  69. }
  70. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  71. template<std::ranges::input_range V, auto F>
  72. requires std::ranges::view<V> &&
  73. std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
  74. detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
  75. #else
  76. template<typename V, typename F> // F is a tag type in c++17
  77. #endif
  78. class project_view : public stl_interfaces::view_interface<project_view<V, F>>
  79. {
  80. V base_ = V();
  81. // HACK: SentType is here to work around irritating big-3
  82. // implementation inconsistencies.
  83. template<bool Const>
  84. class sentinel;
  85. template<bool Const, typename SentType = sentinel<Const>>
  86. class iterator;
  87. public:
  88. constexpr project_view()
  89. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  90. requires std::default_initializable<V>
  91. #endif
  92. = default;
  93. constexpr explicit project_view(V base) : base_(std::move(base)) {}
  94. constexpr V& base() & { return base_; }
  95. constexpr const V& base() const& { return base_; }
  96. constexpr V base() && { return std::move(base_); }
  97. constexpr iterator<false> begin() { return iterator<false>{detail::begin(base_)}; }
  98. constexpr iterator<true> begin() const
  99. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  100. requires std::ranges::range<const V>
  101. #endif
  102. { return iterator<true>{detail::begin(base_)}; }
  103. constexpr sentinel<false> end() { return sentinel<false>{detail::end(base_)}; }
  104. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  105. constexpr iterator<false> end() requires std::ranges::common_range<V>
  106. { return iterator<false>{detail::end(base_)}; }
  107. #endif
  108. constexpr sentinel<true> end() const
  109. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  110. requires std::ranges::range<const V>
  111. { return sentinel<true>{detail::end(base_)}; }
  112. constexpr iterator<true> end() const
  113. requires std::ranges::common_range<const V>
  114. #endif
  115. { return iterator<true>{detail::end(base_)}; }
  116. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  117. constexpr auto size() requires std::ranges::sized_range<V> { return std::ranges::size(base_); }
  118. constexpr auto size() const requires std::ranges::sized_range<const V> { return std::ranges::size(base_); }
  119. #endif
  120. };
  121. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  122. template<std::ranges::input_range V, auto F>
  123. requires std::ranges::view<V> &&
  124. std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
  125. detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
  126. #else
  127. template<typename V, typename F>
  128. #endif
  129. template<bool Const, typename SentType>
  130. class project_view<V, F>::iterator
  131. : public boost::parser::detail::stl_interfaces::proxy_iterator_interface<
  132. iterator<Const>,
  133. detail::iterator_to_tag_t<detail::iterator_t<detail::maybe_const<Const, V>>>,
  134. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  135. std::invoke_result_t<decltype(F)&, detail::range_reference_t<V>>
  136. #else
  137. decltype(detail::function_for_tag<F>(0))
  138. #endif
  139. >
  140. {
  141. using iterator_type = detail::iterator_t<detail::maybe_const<Const, V>>;
  142. using sentinel_type = detail::sentinel_t<detail::maybe_const<Const, V>>;
  143. using reference_type =
  144. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  145. std::invoke_result_t<decltype(F) &, detail::range_reference_t<V>>
  146. #else
  147. decltype(detail::function_for_tag<F>(0))
  148. #endif
  149. ;
  150. using sentinel = SentType;
  151. friend boost::parser::detail::stl_interfaces::access;
  152. iterator_type & base_reference() noexcept { return it_; }
  153. iterator_type base_reference() const { return it_; }
  154. iterator_type it_ = iterator_type();
  155. friend project_view<V, F>::template sentinel<Const>;
  156. template<bool OtherConst>
  157. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  158. requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  159. #endif
  160. friend constexpr bool operator==(const iterator<OtherConst> & x,
  161. const sentinel & y)
  162. { return x.it_ == y.end_; }
  163. template<bool OtherConst>
  164. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  165. requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  166. #endif
  167. friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
  168. operator-(const iterator<OtherConst> & x, const sentinel & y)
  169. { return x.it_ - y.end_; }
  170. template<bool OtherConst>
  171. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  172. requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  173. #endif
  174. friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
  175. operator-(const sentinel & y, const iterator<OtherConst> & x)
  176. { return y.end_ - x.it_; }
  177. public:
  178. constexpr iterator() = default;
  179. constexpr iterator(iterator_type it) : it_(std::move(it)) {}
  180. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  181. constexpr reference_type operator*() const { return F(*it_); }
  182. #else
  183. constexpr reference_type operator*() const
  184. {
  185. return detail::function_for_tag<F>(*it_);
  186. }
  187. #endif
  188. };
  189. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  190. template<std::ranges::input_range V, auto F>
  191. requires std::ranges::view<V> &&
  192. std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
  193. detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
  194. #else
  195. template<typename V, typename F>
  196. #endif
  197. template<bool Const>
  198. class project_view<V, F>::sentinel
  199. {
  200. using Base = detail::maybe_const<Const, V>;
  201. using sentinel_type = detail::sentinel_t<Base>;
  202. sentinel_type end_ = sentinel_type();
  203. public:
  204. constexpr sentinel() = default;
  205. constexpr explicit sentinel(sentinel_type end) : end_(std::move(end)) {}
  206. #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  207. template<bool Enable = Const, class = std::enable_if_t<Enable>>
  208. #endif
  209. constexpr sentinel(sentinel<!Const> i)
  210. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  211. requires Const &&
  212. std::convertible_to<detail::sentinel_t<V>, detail::sentinel_t<Base>>
  213. #endif
  214. : end_(std::move(i.end_))
  215. {}
  216. constexpr sentinel_type base() const { return end_; }
  217. template<bool OtherConst>
  218. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  219. requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  220. #endif
  221. friend constexpr bool operator==(const iterator<OtherConst> & x,
  222. const sentinel & y)
  223. { return x.it_ == y.end_; }
  224. template<bool OtherConst>
  225. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  226. requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  227. #endif
  228. friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
  229. operator-(const iterator<OtherConst> & x, const sentinel & y)
  230. { return x.it_ - y.end_; }
  231. template<bool OtherConst>
  232. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  233. requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
  234. #endif
  235. friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
  236. operator-(const sentinel & y, const iterator<OtherConst> & x)
  237. { return y.end_ - x.it_; }
  238. };
  239. namespace detail {
  240. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  241. template<auto F>
  242. #else
  243. template<typename F>
  244. #endif
  245. struct project_impl : stl_interfaces::range_adaptor_closure<project_impl<F>>
  246. {
  247. template<class R>
  248. using project_view_type = project_view<R, F>;
  249. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  250. template<class R>
  251. requires std::ranges::viewable_range<R> &&
  252. std::ranges::input_range<R> &&
  253. std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<R>> &&
  254. detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<R>>>
  255. #else
  256. template<class R>
  257. #endif
  258. [[nodiscard]] constexpr auto operator()(R && r) const
  259. {
  260. return project_view_type<R>(std::forward<R>(r));
  261. }
  262. };
  263. }
  264. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  265. template<auto F>
  266. #else
  267. template<typename F>
  268. #endif
  269. constexpr detail::project_impl<F> project{};
  270. #if defined(__cpp_char8_t)
  271. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  272. template<std::ranges::input_range V>
  273. requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char8_t>
  274. class char8_view : public project_view<V, detail::cast_to_charn<char8_type>{}>
  275. #else
  276. template<typename V>
  277. class char8_view : public project_view<V, detail::cast_to_char8>
  278. #endif
  279. {
  280. public:
  281. constexpr char8_view()
  282. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  283. requires std::default_initializable<V>
  284. #endif
  285. = default;
  286. constexpr char8_view(V base) :
  287. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  288. project_view<V, detail::cast_to_charn<char8_t>{}>{std::move(base)}
  289. #else
  290. project_view<V, detail::cast_to_char8>{std::move(base)}
  291. #endif
  292. {}
  293. };
  294. #endif
  295. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  296. template<std::ranges::input_range V>
  297. requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char16_t>
  298. class char16_view : public project_view<V, detail::cast_to_charn<char16_t>{}>
  299. #else
  300. template<typename V>
  301. class char16_view : public project_view<V, detail::cast_to_char16>
  302. #endif
  303. {
  304. public:
  305. constexpr char16_view()
  306. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  307. requires std::default_initializable<V>
  308. #endif
  309. = default;
  310. constexpr char16_view(V base) :
  311. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  312. project_view<V, detail::cast_to_charn<char16_t>{}>{std::move(base)}
  313. #else
  314. project_view<V, detail::cast_to_char16>{std::move(base)}
  315. #endif
  316. {}
  317. };
  318. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  319. template<std::ranges::input_range V>
  320. requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char32_t>
  321. class char32_view : public project_view<V, detail::cast_to_charn<char32_t>{}>
  322. #else
  323. template<typename V>
  324. class char32_view : public project_view<V, detail::cast_to_char32>
  325. #endif
  326. {
  327. public:
  328. constexpr char32_view()
  329. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  330. requires std::default_initializable<V>
  331. #endif
  332. = default;
  333. constexpr char32_view(V base) :
  334. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  335. project_view<V, detail::cast_to_charn<char32_t>{}>{std::move(base)}
  336. #else
  337. project_view<V, detail::cast_to_char32>{std::move(base)}
  338. #endif
  339. {}
  340. };
  341. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  342. template<class R>
  343. char8_view(R &&) -> char8_view<detail::all_t<R>>;
  344. template<class R>
  345. char16_view(R &&) -> char16_view<detail::all_t<R>>;
  346. template<class R>
  347. char32_view(R &&) -> char32_view<detail::all_t<R>>;
  348. #endif
  349. namespace detail {
  350. template<template<class> class View, format Format>
  351. struct as_charn_impl : stl_interfaces::range_adaptor_closure<as_charn_impl<View, Format>>
  352. {
  353. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  354. template<class R>
  355. requires (std::ranges::viewable_range<R> &&
  356. std::ranges::input_range<R> &&
  357. std::convertible_to<std::ranges::range_reference_t<R>, format_to_type_t<Format>>)
  358. #else
  359. template<class R>
  360. #endif
  361. [[nodiscard]] constexpr auto operator()(R && r) const
  362. {
  363. using T = remove_cv_ref_t<R>;
  364. if constexpr (detail::is_empty_view<T>) {
  365. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  366. return std::ranges::empty_view<format_to_type_t<Format>>{};
  367. #else
  368. return 42; // Never gonna happen.
  369. #endif
  370. } else {
  371. return View(std::forward<R>(r));
  372. }
  373. }
  374. };
  375. template<class T>
  376. constexpr bool is_charn_view = false;
  377. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  378. template<class V>
  379. constexpr bool is_charn_view<char8_view<V>> = true;
  380. #endif
  381. template<class V>
  382. constexpr bool is_charn_view<char16_view<V>> = true;
  383. template<class V>
  384. constexpr bool is_charn_view<char32_view<V>> = true;
  385. }
  386. #if defined(__cpp_char8_t)
  387. inline constexpr detail::as_charn_impl<char8_view, format::utf8> as_char8_t;
  388. #endif
  389. inline constexpr detail::as_charn_impl<char16_view, format::utf16>
  390. as_char16_t;
  391. inline constexpr detail::as_charn_impl<char32_view, format::utf32>
  392. as_char32_t;
  393. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  394. template<utf_range V>
  395. requires std::ranges::view<V> && std::ranges::forward_range<V>
  396. #else
  397. template<typename V>
  398. #endif
  399. class unpacking_view
  400. : public stl_interfaces::view_interface<unpacking_view<V>>
  401. {
  402. V base_ = V();
  403. public:
  404. constexpr unpacking_view()
  405. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  406. requires std::default_initializable<V>
  407. #endif
  408. = default;
  409. constexpr unpacking_view(V base) : base_(std::move(base)) {}
  410. constexpr V base() const &
  411. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  412. requires std::copy_constructible<V>
  413. #endif
  414. {
  415. return base_;
  416. }
  417. constexpr V base() && { return std::move(base_); }
  418. constexpr auto code_units() const noexcept
  419. {
  420. auto unpacked =
  421. boost::parser::detail::text::unpack_iterator_and_sentinel(
  422. detail::begin(base_), detail::end(base_));
  423. return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(
  424. unpacked.first, unpacked.last);
  425. }
  426. constexpr auto begin() { return code_units().begin(); }
  427. constexpr auto begin() const { return code_units().begin(); }
  428. constexpr auto end() { return code_units().end(); }
  429. constexpr auto end() const { return code_units().end(); }
  430. };
  431. template<class R>
  432. unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>;
  433. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  434. template<format Format, utf_range V>
  435. requires std::ranges::view<V>
  436. #else
  437. template<format Format, typename V>
  438. #endif
  439. class utf_view : public stl_interfaces::view_interface<utf_view<Format, V>>
  440. {
  441. V base_ = V();
  442. template<format FromFormat, class I, class S>
  443. static constexpr auto make_begin(I first, S last)
  444. {
  445. if constexpr (detail::bidirectional_iterator_v<I>) {
  446. return utf_iterator<FromFormat, Format, I, S>{first, first, last};
  447. } else {
  448. return utf_iterator<FromFormat, Format, I, S>{first, last};
  449. }
  450. }
  451. template<format FromFormat, class I, class S>
  452. static constexpr auto make_end(I first, S last)
  453. {
  454. if constexpr (!std::is_same_v<I, S>) {
  455. return last;
  456. } else if constexpr (detail::bidirectional_iterator_v<I>) {
  457. return utf_iterator<FromFormat, Format, I, S>{first, last, last};
  458. } else {
  459. return utf_iterator<FromFormat, Format, I, S>{last, last};
  460. }
  461. }
  462. public:
  463. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  464. constexpr utf_view() requires std::default_initializable<V> = default;
  465. #endif
  466. constexpr utf_view(V base) : base_{std::move(base)} {}
  467. constexpr V base() const &
  468. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  469. requires std::copy_constructible<V>
  470. #endif
  471. { return base_; }
  472. constexpr V base() && { return std::move(base_); }
  473. constexpr auto begin()
  474. {
  475. constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
  476. if constexpr(detail::is_charn_view<V>) {
  477. return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
  478. } else {
  479. return make_begin<from_format>(detail::begin(base_), detail::end(base_));
  480. }
  481. }
  482. constexpr auto begin() const
  483. {
  484. constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
  485. if constexpr(detail::is_charn_view<V>) {
  486. return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
  487. } else {
  488. return make_begin<from_format>(detail::begin(base_), detail::end(base_));
  489. }
  490. }
  491. constexpr auto end()
  492. {
  493. constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
  494. if constexpr(detail::is_charn_view<V>) {
  495. return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
  496. } else {
  497. return make_end<from_format>(detail::begin(base_), detail::end(base_));
  498. }
  499. }
  500. constexpr auto end() const
  501. {
  502. constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
  503. if constexpr(detail::is_charn_view<V>) {
  504. return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
  505. } else {
  506. return make_end<from_format>(detail::begin(base_), detail::end(base_));
  507. }
  508. }
  509. /** Stream inserter; performs unformatted output, in UTF-8
  510. encoding. */
  511. friend std::ostream & operator<<(std::ostream & os, utf_view v)
  512. {
  513. if constexpr (Format == format::utf8) {
  514. auto out = std::ostreambuf_iterator<char>(os);
  515. for (auto it = v.begin(); it != v.end(); ++it, ++out) {
  516. *out = *it;
  517. }
  518. } else {
  519. boost::parser::detail::text::transcode_to_utf8(
  520. v.begin(), v.end(), std::ostreambuf_iterator<char>(os));
  521. }
  522. return os;
  523. }
  524. #if defined(BOOST_TEXT_DOXYGEN) || defined(_MSC_VER)
  525. /** Stream inserter; performs unformatted output, in UTF-16 encoding.
  526. Defined on Windows only. */
  527. friend std::wostream & operator<<(std::wostream & os, utf_view v)
  528. {
  529. if constexpr (Format == format::utf16) {
  530. auto out = std::ostreambuf_iterator<wchar_t>(os);
  531. for (auto it = v.begin(); it != v.end(); ++it, ++out) {
  532. *out = *it;
  533. }
  534. } else {
  535. boost::parser::detail::text::transcode_to_utf16(
  536. v.begin(), v.end(), std::ostreambuf_iterator<wchar_t>(os));
  537. }
  538. return os;
  539. }
  540. #endif
  541. };
  542. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  543. template<utf_range V>
  544. requires std::ranges::view<V>
  545. #else
  546. template<typename V>
  547. #endif
  548. class utf8_view : public utf_view<format::utf8, V>
  549. {
  550. public:
  551. constexpr utf8_view()
  552. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  553. requires std::default_initializable<V>
  554. #endif
  555. = default;
  556. constexpr utf8_view(V base) :
  557. utf_view<format::utf8, V>{std::move(base)}
  558. {}
  559. };
  560. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  561. template<utf_range V>
  562. requires std::ranges::view<V>
  563. #else
  564. template<typename V>
  565. #endif
  566. class utf16_view : public utf_view<format::utf16, V>
  567. {
  568. public:
  569. constexpr utf16_view()
  570. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  571. requires std::default_initializable<V>
  572. #endif
  573. = default;
  574. constexpr utf16_view(V base) :
  575. utf_view<format::utf16, V>{std::move(base)}
  576. {}
  577. };
  578. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  579. template<utf_range V>
  580. requires std::ranges::view<V>
  581. #else
  582. template<typename V>
  583. #endif
  584. class utf32_view : public utf_view<format::utf32, V>
  585. {
  586. public:
  587. constexpr utf32_view()
  588. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  589. requires std::default_initializable<V>
  590. #endif
  591. = default;
  592. constexpr utf32_view(V base) :
  593. utf_view<format::utf32, V>{std::move(base)}
  594. {}
  595. };
  596. template<class R>
  597. utf8_view(R &&) -> utf8_view<detail::all_t<R>>;
  598. template<class R>
  599. utf16_view(R &&) -> utf16_view<detail::all_t<R>>;
  600. template<class R>
  601. utf32_view(R &&) -> utf32_view<detail::all_t<R>>;
  602. #if defined(BOOST_TEXT_DOXYGEN)
  603. /** A view adaptor that produces a UTF-8 view of the given view. */
  604. constexpr detail::unspecified as_utf8;
  605. /** A view adaptor that produces a UTF-16 view of the given view. */
  606. constexpr detail::unspecified as_utf16;
  607. /** A view adaptor that produces a UTF-32 view of the given view. */
  608. constexpr detail::unspecified as_utf32;
  609. #endif
  610. namespace detail {
  611. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  612. template<class R, template<class> class View>
  613. concept can_utf_view = requires(R && r) { View((R &&)r); };
  614. #else
  615. template<class R, class View>
  616. using can_utf_view_expr = decltype(View(std::declval<R>()));
  617. template<class R, template<class> class View>
  618. constexpr bool can_utf_view =
  619. is_detected_v<can_utf_view_expr, R, View<R>>;
  620. #endif
  621. template<class T>
  622. constexpr bool is_utf_view = false;
  623. template<class T>
  624. constexpr bool is_utf_view<utf8_view<T>> = true;
  625. template<class T>
  626. constexpr bool is_utf_view<utf16_view<T>> = true;
  627. template<class T>
  628. constexpr bool is_utf_view<utf32_view<T>> = true;
  629. template<format F, class T>
  630. constexpr bool is_utf_view<utf_view<F, T>> = true;
  631. template<typename T>
  632. constexpr bool is_bounded_array_v = false;
  633. template<typename T, int N>
  634. constexpr bool is_bounded_array_v<T[N]> = true;
  635. template<class R>
  636. constexpr decltype(auto) unpack_range(R && r)
  637. {
  638. using T = detail::remove_cv_ref_t<R>;
  639. if constexpr (forward_range_v<T>) {
  640. auto unpacked =
  641. boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(r), detail::end(r));
  642. if constexpr (is_bounded_array_v<T>) {
  643. constexpr auto n = std::extent_v<T>;
  644. if (n && !r[n - 1])
  645. --unpacked.last;
  646. return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last);
  647. } else if constexpr (
  648. !std::is_same_v<decltype(unpacked.first), iterator_t<R>> ||
  649. !std::is_same_v<decltype(unpacked.last), sentinel_t<R>>) {
  650. return unpacking_view(std::forward<R>(r));
  651. } else {
  652. return std::forward<R>(r);
  653. }
  654. } else {
  655. return std::forward<R>(r);
  656. }
  657. }
  658. template<class R>
  659. using unpacked_range = decltype(detail::unpack_range(std::declval<R>()));
  660. template<template<class> class View, format Format>
  661. struct as_utf_impl : stl_interfaces::range_adaptor_closure<as_utf_impl<View, Format>>
  662. {
  663. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  664. template<class R>
  665. requires is_utf_view<std::remove_cvref_t<R>> ||
  666. (std::ranges::viewable_range<R> &&
  667. can_utf_view<unpacked_range<R>, View>)
  668. #else
  669. template<typename R>
  670. #endif
  671. [[nodiscard]] constexpr auto operator()(R && r) const
  672. {
  673. using T = detail::remove_cv_ref_t<R>;
  674. if constexpr (detail::is_empty_view<T>) {
  675. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  676. return std::ranges::empty_view<format_to_type_t<Format>>{};
  677. #else
  678. return 42; // Never gonna happen.
  679. #endif
  680. } else if constexpr (is_utf_view<T>) {
  681. return View(std::forward<R>(r).base());
  682. } else if constexpr (detail::is_charn_view<T>) {
  683. return View(std::forward<R>(r));
  684. } else {
  685. return View(detail::unpack_range(std::forward<R>(r)));
  686. }
  687. }
  688. };
  689. template<class T>
  690. constexpr bool is_utf32_view = false;
  691. template<class V>
  692. constexpr bool is_utf32_view<utf_view<format::utf32, V>> = true;
  693. }
  694. inline constexpr detail::as_utf_impl<utf8_view, format::utf8> as_utf8;
  695. inline constexpr detail::as_utf_impl<utf16_view, format::utf16> as_utf16;
  696. inline constexpr detail::as_utf_impl<utf32_view, format::utf32> as_utf32;
  697. }}
  698. #if BOOST_PARSER_USE_CONCEPTS && defined(__cpp_lib_ranges)
  699. namespace std::ranges {
  700. #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
  701. template<class V, auto F>
  702. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::project_view<V, F>> =
  703. enable_borrowed_range<V>;
  704. #endif
  705. template<class V>
  706. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::unpacking_view<V>> =
  707. enable_borrowed_range<V>;
  708. template<boost::parser::detail::text::format Format, class V>
  709. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf_view<Format, V>> =
  710. enable_borrowed_range<V>;
  711. template<class V>
  712. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf8_view<V>> =
  713. enable_borrowed_range<V>;
  714. template<class V>
  715. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf16_view<V>> =
  716. enable_borrowed_range<V>;
  717. template<class V>
  718. inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf32_view<V>> =
  719. enable_borrowed_range<V>;
  720. }
  721. #endif
  722. #endif