Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:40:22

0001 // Copyright (C) 2020 T. Zachary Laine
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 #ifndef BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP
0007 #define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP
0008 
0009 #include <boost/parser/detail/text/transcode_algorithm.hpp>
0010 #include <boost/parser/detail/text/transcode_iterator.hpp>
0011 #include <boost/parser/detail/text/detail/all_t.hpp>
0012 
0013 #include <boost/parser/detail/stl_interfaces/view_interface.hpp>
0014 #include <boost/parser/detail/stl_interfaces/view_adaptor.hpp>
0015 
0016 #include <climits>
0017 
0018 
0019 namespace boost::parser::detail { namespace text {
0020 
0021     namespace detail {
0022         template<class I>
0023         constexpr auto iterator_to_tag()
0024         {
0025 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0026             if constexpr (std::random_access_iterator<I>) {
0027                 return std::random_access_iterator_tag{};
0028             } else if constexpr (std::bidirectional_iterator<I>) {
0029                 return std::bidirectional_iterator_tag{};
0030             } else if constexpr (std::forward_iterator<I>) {
0031 #else
0032             if constexpr (detail::random_access_iterator_v<I>) {
0033                 return std::random_access_iterator_tag{};
0034             } else if constexpr (detail::bidirectional_iterator_v<I>) {
0035                 return std::bidirectional_iterator_tag{};
0036             } else if constexpr (detail::forward_iterator_v<I>) {
0037 #endif
0038                 return std::forward_iterator_tag{};
0039             } else {
0040                 return std::input_iterator_tag{};
0041             }
0042         }
0043         template<class I>
0044         using iterator_to_tag_t = decltype(iterator_to_tag<I>());
0045 
0046 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0047         template<class T>
0048         using with_reference = T &;
0049         template<typename T>
0050         concept can_reference = requires { typename with_reference<T>; };
0051 #endif
0052 
0053 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0054         template<class Char>
0055         struct cast_to_charn {
0056             constexpr Char operator()(Char c) const { return c; }
0057         };
0058 #else
0059         struct cast_to_char8;
0060         struct cast_to_char16;
0061         struct cast_to_char32;
0062         template<typename Tag, typename Arg>
0063         auto function_for_tag(Arg arg)
0064         {
0065 #if defined(__cpp_char8_t)
0066             if constexpr (std::is_same_v<Tag, cast_to_char8>) {
0067                 return (char8_t)arg;
0068             } else
0069 #endif
0070                 if constexpr (std::is_same_v<Tag, cast_to_char16>) {
0071                 return (char16_t)arg;
0072             } else if constexpr (std::is_same_v<Tag, cast_to_char32>) {
0073                 return (char32_t)arg;
0074             }
0075         }
0076 #endif
0077     }
0078 
0079 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0080     template<std::ranges::input_range V, auto F>
0081         requires std::ranges::view<V> &&
0082                  std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
0083                  detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
0084 #else
0085     template<typename V, typename F> // F is a tag type in c++17
0086 #endif
0087     class project_view : public stl_interfaces::view_interface<project_view<V, F>>
0088     {
0089         V base_ = V();
0090 
0091         template<bool Const>
0092         class iterator;
0093         template<bool Const>
0094         class sentinel;
0095 
0096     public:
0097         constexpr project_view()
0098 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0099             requires std::default_initializable<V>
0100 #endif
0101         = default;
0102         constexpr explicit project_view(V base) : base_(std::move(base)) {}
0103 
0104         constexpr V& base() & { return base_; }
0105         constexpr const V& base() const& { return base_; }
0106         constexpr V base() && { return std::move(base_); }
0107 
0108         constexpr iterator<false> begin() { return iterator<false>{detail::begin(base_)}; }
0109         constexpr iterator<true> begin() const
0110 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0111             requires std::ranges::range<const V>
0112 #endif
0113         { return iterator<true>{detail::begin(base_)}; }
0114 
0115         constexpr sentinel<false> end() { return sentinel<false>{detail::end(base_)}; }
0116 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0117         constexpr iterator<false> end() requires std::ranges::common_range<V>
0118             { return iterator<false>{detail::end(base_)}; }
0119 #endif
0120         constexpr sentinel<true> end() const
0121 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0122             requires std::ranges::range<const V>
0123         { return sentinel<true>{detail::end(base_)}; }
0124         constexpr iterator<true> end() const
0125             requires std::ranges::common_range<const V>
0126 #endif
0127         { return iterator<true>{detail::end(base_)}; }
0128 
0129 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0130         constexpr auto size() requires std::ranges::sized_range<V> { return std::ranges::size(base_); }
0131         constexpr auto size() const requires std::ranges::sized_range<const V> { return std::ranges::size(base_); }
0132 #endif
0133     };
0134 
0135 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0136     template<std::ranges::input_range V, auto F>
0137         requires std::ranges::view<V> &&
0138                  std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
0139                  detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
0140 #else
0141     template<typename V, typename F>
0142 #endif
0143     template<bool Const>
0144     class project_view<V, F>::iterator
0145         : public boost::parser::detail::stl_interfaces::proxy_iterator_interface<
0146               iterator<Const>,
0147               detail::iterator_to_tag_t<detail::iterator_t<detail::maybe_const<Const, V>>>,
0148 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0149               std::invoke_result_t<decltype(F)&, detail::range_reference_t<V>>
0150 #else
0151               decltype(detail::function_for_tag<F>(0))
0152 #endif
0153         >
0154     {
0155         using iterator_type = detail::iterator_t<detail::maybe_const<Const, V>>;
0156         using sentinel_type = detail::sentinel_t<detail::maybe_const<Const, V>>;
0157         using reference_type =
0158 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0159             std::invoke_result_t<decltype(F) &, detail::range_reference_t<V>>
0160 #else
0161             decltype(detail::function_for_tag<F>(0))
0162 #endif
0163             ;
0164         using sentinel = project_view<V, F>::sentinel<Const>;
0165 
0166         friend boost::parser::detail::stl_interfaces::access;
0167         iterator_type & base_reference() noexcept { return it_; }
0168         iterator_type base_reference() const { return it_; }
0169 
0170         iterator_type it_ = iterator_type();
0171 
0172         friend project_view<V, F>::sentinel<Const>;
0173 
0174         template<bool OtherConst>
0175 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0176             requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0177 #endif
0178         friend constexpr bool operator==(const iterator<OtherConst> & x,
0179                                          const sentinel & y)
0180             { return x.it_ == y.end_; }
0181 
0182         template<bool OtherConst>
0183 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0184             requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0185 #endif
0186         friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
0187         operator-(const iterator<OtherConst> & x, const sentinel & y)
0188            { return x.it_ - y.end_; }
0189 
0190         template<bool OtherConst>
0191 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0192             requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0193 #endif
0194         friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
0195         operator-(const sentinel & y, const iterator<OtherConst> & x)
0196             { return y.end_ - x.it_; }
0197 
0198     public:
0199         constexpr iterator() = default;
0200         constexpr iterator(iterator_type it) : it_(std::move(it)) {}
0201 
0202 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0203         constexpr reference_type operator*() const { return F(*it_); }
0204 #else
0205         constexpr reference_type operator*() const
0206         {
0207             return detail::function_for_tag<F>(*it_);
0208         }
0209 #endif
0210     };
0211 
0212 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0213     template<std::ranges::input_range V, auto F>
0214         requires std::ranges::view<V> &&
0215                  std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> &&
0216                  detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>>
0217 #else
0218     template<typename V, typename F>
0219 #endif
0220     template<bool Const>
0221     class project_view<V, F>::sentinel
0222     {
0223         using Base = detail::maybe_const<Const, V>;
0224         using sentinel_type = detail::sentinel_t<Base>;
0225 
0226         sentinel_type end_ = sentinel_type();
0227 
0228     public:
0229         constexpr sentinel() = default;
0230         constexpr explicit sentinel(sentinel_type end) : end_(std::move(end)) {}
0231 #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0232         template<bool Enable = Const, class = std::enable_if_t<Enable>>
0233 #endif
0234         constexpr sentinel(sentinel<!Const> i)
0235 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0236             requires Const &&
0237             std::convertible_to<detail::sentinel_t<V>, detail::sentinel_t<Base>>
0238 #endif
0239             : end_(std::move(i.end_))
0240         {}
0241 
0242         constexpr sentinel_type base() const { return end_; }
0243 
0244         template<bool OtherConst>
0245 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0246             requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0247 #endif
0248         friend constexpr bool operator==(const iterator<OtherConst> & x,
0249                                          const sentinel & y)
0250             { return x.it_ == y.end_; }
0251 
0252         template<bool OtherConst>
0253 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0254             requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0255 #endif
0256         friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
0257         operator-(const iterator<OtherConst> & x, const sentinel & y)
0258             { return x.it_ - y.end_; }
0259 
0260         template<bool OtherConst>
0261 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0262             requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>>
0263 #endif
0264         friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>>
0265         operator-(const sentinel & y, const iterator<OtherConst> & x)
0266             { return y.end_ - x.it_; }
0267     };
0268 
0269     namespace detail {
0270 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0271         template<auto F>
0272 #else
0273         template<typename F>
0274 #endif
0275         struct project_impl : stl_interfaces::range_adaptor_closure<project_impl<F>>
0276         {
0277             template<class R>
0278             using project_view_type = project_view<R, F>;
0279 
0280 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0281             template<class R>
0282                 requires std::ranges::viewable_range<R> &&
0283                          std::ranges::input_range<R> &&
0284                          std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<R>> &&
0285                          detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<R>>>
0286 #else
0287             template<class R>
0288 #endif
0289             [[nodiscard]] constexpr auto operator()(R && r) const
0290             {
0291                 return project_view_type<R>(std::forward<R>(r));
0292             }
0293         };
0294     }
0295 
0296 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0297     template<auto F>
0298 #else
0299     template<typename F>
0300 #endif
0301     constexpr detail::project_impl<F> project{};
0302 
0303 #if defined(__cpp_char8_t)
0304 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0305     template<std::ranges::input_range V>
0306         requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char8_t>
0307     class char8_view : public project_view<V, detail::cast_to_charn<char8_type>{}>
0308 #else
0309     template<typename V>
0310     class char8_view : public project_view<V, detail::cast_to_char8>
0311 #endif
0312     {
0313     public:
0314         constexpr char8_view()
0315 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0316             requires std::default_initializable<V>
0317 #endif
0318         = default;
0319         constexpr char8_view(V base) :
0320 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0321             project_view<V, detail::cast_to_charn<char8_t>{}>{std::move(base)}
0322 #else
0323             project_view<V, detail::cast_to_char8>{std::move(base)}
0324 #endif
0325         {}
0326     };
0327 #endif
0328 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0329     template<std::ranges::input_range V>
0330         requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char16_t>
0331     class char16_view : public project_view<V, detail::cast_to_charn<char16_t>{}>
0332 #else
0333     template<typename V>
0334     class char16_view : public project_view<V, detail::cast_to_char16>
0335 #endif
0336     {
0337     public:
0338         constexpr char16_view()
0339 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0340             requires std::default_initializable<V>
0341 #endif
0342         = default;
0343         constexpr char16_view(V base) :
0344 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0345             project_view<V, detail::cast_to_charn<char16_t>{}>{std::move(base)}
0346 #else
0347             project_view<V, detail::cast_to_char16>{std::move(base)}
0348 #endif
0349         {}
0350     };
0351 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0352     template<std::ranges::input_range V>
0353         requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char32_t>
0354     class char32_view : public project_view<V, detail::cast_to_charn<char32_t>{}>
0355 #else
0356     template<typename V>
0357     class char32_view : public project_view<V, detail::cast_to_char32>
0358 #endif
0359     {
0360     public:
0361         constexpr char32_view()
0362 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0363             requires std::default_initializable<V>
0364 #endif
0365         = default;
0366         constexpr char32_view(V base) :
0367 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0368             project_view<V, detail::cast_to_charn<char32_t>{}>{std::move(base)}
0369 #else
0370             project_view<V, detail::cast_to_char32>{std::move(base)}
0371 #endif
0372         {}
0373     };
0374 
0375 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0376     template<class R>
0377     char8_view(R &&) -> char8_view<detail::all_t<R>>;
0378     template<class R>
0379     char16_view(R &&) -> char16_view<detail::all_t<R>>;
0380     template<class R>
0381     char32_view(R &&) -> char32_view<detail::all_t<R>>;
0382 #endif
0383 
0384     namespace detail {
0385         template<template<class> class View, format Format>
0386         struct as_charn_impl : stl_interfaces::range_adaptor_closure<as_charn_impl<View, Format>>
0387         {
0388 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0389             template<class R>
0390             requires (std::ranges::viewable_range<R> &&
0391                       std::ranges::input_range<R> &&
0392                       std::convertible_to<std::ranges::range_reference_t<R>, format_to_type_t<Format>>)
0393 #else
0394             template<class R>
0395 #endif
0396             [[nodiscard]] constexpr auto operator()(R && r) const
0397             {
0398                 using T = remove_cv_ref_t<R>;
0399                 if constexpr (detail::is_empty_view<T>) {
0400 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0401                     return std::ranges::empty_view<format_to_type_t<Format>>{};
0402 #else
0403                     return 42; // Never gonna happen.
0404 #endif
0405                 } else {
0406                     return View(std::forward<R>(r));
0407                 }
0408             }
0409         };
0410 
0411         template<class T>
0412         constexpr bool is_charn_view = false;
0413 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0414         template<class V>
0415         constexpr bool is_charn_view<char8_view<V>> = true;
0416 #endif
0417         template<class V>
0418         constexpr bool is_charn_view<char16_view<V>> = true;
0419         template<class V>
0420         constexpr bool is_charn_view<char32_view<V>> = true;
0421     }
0422 
0423 #if defined(__cpp_char8_t)
0424     inline constexpr detail::as_charn_impl<char8_view, format::utf8> as_char8_t;
0425 #endif
0426     inline constexpr detail::as_charn_impl<char16_view, format::utf16>
0427         as_char16_t;
0428     inline constexpr detail::as_charn_impl<char32_view, format::utf32>
0429         as_char32_t;
0430 
0431 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0432     template<utf_range V>
0433         requires std::ranges::view<V> && std::ranges::forward_range<V>
0434 #else
0435     template<typename V>
0436 #endif
0437     class unpacking_view
0438         : public stl_interfaces::view_interface<unpacking_view<V>>
0439     {
0440         V base_ = V();
0441 
0442     public:
0443         constexpr unpacking_view()
0444 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0445             requires std::default_initializable<V>
0446 #endif
0447         = default;
0448         constexpr unpacking_view(V base) : base_(std::move(base)) {}
0449 
0450         constexpr V base() const &
0451 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0452             requires std::copy_constructible<V>
0453 #endif
0454         {
0455             return base_;
0456         }
0457         constexpr V base() && { return std::move(base_); }
0458 
0459         constexpr auto code_units() const noexcept
0460         {
0461             auto unpacked =
0462                 boost::parser::detail::text::unpack_iterator_and_sentinel(
0463                     detail::begin(base_), detail::end(base_));
0464             return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(
0465                 unpacked.first, unpacked.last);
0466         }
0467 
0468         constexpr auto begin() { return code_units().begin(); }
0469         constexpr auto begin() const { return code_units().begin(); }
0470 
0471         constexpr auto end() { return code_units().end(); }
0472         constexpr auto end() const { return code_units().end(); }
0473     };
0474 
0475     template<class R>
0476     unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>;
0477 
0478 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0479     template<format Format, utf_range V>
0480         requires std::ranges::view<V>
0481 #else
0482     template<format Format, typename V>
0483 #endif
0484     class utf_view : public stl_interfaces::view_interface<utf_view<Format, V>>
0485     {
0486         V base_ = V();
0487 
0488         template<format FromFormat, class I, class S>
0489         static constexpr auto make_begin(I first, S last)
0490         {
0491             if constexpr (detail::bidirectional_iterator_v<I>) {
0492                 return utf_iterator<FromFormat, Format, I, S>{first, first, last};
0493             } else {
0494                 return utf_iterator<FromFormat, Format, I, S>{first, last};
0495             }
0496         }
0497         template<format FromFormat, class I, class S>
0498         static constexpr auto make_end(I first, S last)
0499         {
0500             if constexpr (!std::is_same_v<I, S>) {
0501                 return last;
0502             } else if constexpr (detail::bidirectional_iterator_v<I>) {
0503                 return utf_iterator<FromFormat, Format, I, S>{first, last, last};
0504             } else {
0505                 return utf_iterator<FromFormat, Format, I, S>{last, last};
0506             }
0507         }
0508 
0509     public:
0510 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0511         constexpr utf_view() requires std::default_initializable<V> = default;
0512 #endif
0513         constexpr utf_view(V base) : base_{std::move(base)} {}
0514 
0515         constexpr V base() const &
0516 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0517             requires std::copy_constructible<V>
0518 #endif
0519         { return base_; }
0520         constexpr V base() && { return std::move(base_); }
0521 
0522         constexpr auto begin()
0523         {
0524             constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
0525             if constexpr(detail::is_charn_view<V>) {
0526                 return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
0527             } else {
0528                 return make_begin<from_format>(detail::begin(base_), detail::end(base_));
0529             }
0530         }
0531         constexpr auto begin() const
0532         {
0533             constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
0534             if constexpr(detail::is_charn_view<V>) {
0535                 return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
0536             } else {
0537                 return make_begin<from_format>(detail::begin(base_), detail::end(base_));
0538             }
0539         }
0540 
0541         constexpr auto end()
0542         {
0543             constexpr format from_format = detail::format_of<detail::range_value_t<V>>();
0544             if constexpr(detail::is_charn_view<V>) {
0545                 return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
0546             } else {
0547                 return make_end<from_format>(detail::begin(base_), detail::end(base_));
0548             }
0549         }
0550         constexpr auto end() const
0551         {
0552             constexpr format from_format = detail::format_of<detail::range_value_t<const V>>();
0553             if constexpr(detail::is_charn_view<V>) {
0554                 return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base()));
0555             } else {
0556                 return make_end<from_format>(detail::begin(base_), detail::end(base_));
0557             }
0558         }
0559 
0560         /** Stream inserter; performs unformatted output, in UTF-8
0561             encoding. */
0562         friend std::ostream & operator<<(std::ostream & os, utf_view v)
0563         {
0564             if constexpr (Format == format::utf8) {
0565                 auto out = std::ostreambuf_iterator<char>(os);
0566                 for (auto it = v.begin(); it != v.end(); ++it, ++out) {
0567                     *out = *it;
0568                 }
0569             } else {
0570                 boost::parser::detail::text::transcode_to_utf8(
0571                     v.begin(), v.end(), std::ostreambuf_iterator<char>(os));
0572             }
0573             return os;
0574         }
0575 #if defined(BOOST_TEXT_DOXYGEN) || defined(_MSC_VER)
0576         /** Stream inserter; performs unformatted output, in UTF-16 encoding.
0577             Defined on Windows only. */
0578         friend std::wostream & operator<<(std::wostream & os, utf_view v)
0579         {
0580             if constexpr (Format == format::utf16) {
0581                 auto out = std::ostreambuf_iterator<wchar_t>(os);
0582                 for (auto it = v.begin(); it != v.end(); ++it, ++out) {
0583                     *out = *it;
0584                 }
0585             } else {
0586                 boost::parser::detail::text::transcode_to_utf16(
0587                     v.begin(), v.end(), std::ostreambuf_iterator<wchar_t>(os));
0588             }
0589             return os;
0590         }
0591 #endif
0592     };
0593 
0594 
0595 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0596     template<utf_range V>
0597         requires std::ranges::view<V>
0598 #else
0599     template<typename V>
0600 #endif
0601     class utf8_view : public utf_view<format::utf8, V>
0602     {
0603     public:
0604         constexpr utf8_view()
0605 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0606             requires std::default_initializable<V>
0607 #endif
0608         = default;
0609         constexpr utf8_view(V base) :
0610             utf_view<format::utf8, V>{std::move(base)}
0611         {}
0612     };
0613 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0614     template<utf_range V>
0615         requires std::ranges::view<V>
0616 #else
0617     template<typename V>
0618 #endif
0619     class utf16_view : public utf_view<format::utf16, V>
0620     {
0621     public:
0622         constexpr utf16_view()
0623 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0624             requires std::default_initializable<V>
0625 #endif
0626         = default;
0627         constexpr utf16_view(V base) :
0628             utf_view<format::utf16, V>{std::move(base)}
0629         {}
0630     };
0631 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0632     template<utf_range V>
0633         requires std::ranges::view<V>
0634 #else
0635     template<typename V>
0636 #endif
0637     class utf32_view : public utf_view<format::utf32, V>
0638     {
0639     public:
0640         constexpr utf32_view()
0641 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0642             requires std::default_initializable<V>
0643 #endif
0644         = default;
0645         constexpr utf32_view(V base) :
0646             utf_view<format::utf32, V>{std::move(base)}
0647         {}
0648     };
0649 
0650     template<class R>
0651     utf8_view(R &&) -> utf8_view<detail::all_t<R>>;
0652     template<class R>
0653     utf16_view(R &&) -> utf16_view<detail::all_t<R>>;
0654     template<class R>
0655     utf32_view(R &&) -> utf32_view<detail::all_t<R>>;
0656 
0657 #if defined(BOOST_TEXT_DOXYGEN)
0658 
0659     /** A view adaptor that produces a UTF-8 view of the given view. */
0660     constexpr detail::unspecified as_utf8;
0661 
0662     /** A view adaptor that produces a UTF-16 view of the given view. */
0663     constexpr detail::unspecified as_utf16;
0664 
0665     /** A view adaptor that produces a UTF-32 view of the given view. */
0666     constexpr detail::unspecified as_utf32;
0667 
0668 #endif
0669 
0670     namespace detail {
0671 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0672         template<class R, template<class> class View>
0673         concept can_utf_view = requires(R && r) { View((R &&)r); };
0674 #else
0675         template<class R, class View>
0676         using can_utf_view_expr = decltype(View(std::declval<R>()));
0677         template<class R, template<class> class View>
0678         constexpr bool can_utf_view =
0679             is_detected_v<can_utf_view_expr, R, View<R>>;
0680 #endif
0681 
0682         template<class T>
0683         constexpr bool is_utf_view = false;
0684         template<class T>
0685         constexpr bool is_utf_view<utf8_view<T>> = true;
0686         template<class T>
0687         constexpr bool is_utf_view<utf16_view<T>> = true;
0688         template<class T>
0689         constexpr bool is_utf_view<utf32_view<T>> = true;
0690         template<format F, class T>
0691         constexpr bool is_utf_view<utf_view<F, T>> = true;
0692 
0693         template<typename T>
0694         constexpr bool is_bounded_array_v = false;
0695         template<typename T, int N>
0696         constexpr bool is_bounded_array_v<T[N]> = true;
0697 
0698         template<class R>
0699         constexpr decltype(auto) unpack_range(R && r)
0700         {
0701             using T = detail::remove_cv_ref_t<R>;
0702             if constexpr (forward_range_v<T>) {
0703                 auto unpacked =
0704                     boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(r), detail::end(r));
0705                 if constexpr (is_bounded_array_v<T>) {
0706                     constexpr auto n = std::extent_v<T>;
0707                     if (n && !r[n - 1])
0708                         --unpacked.last;
0709                     return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last);
0710                 } else if constexpr (
0711                     !std::is_same_v<decltype(unpacked.first), iterator_t<R>> ||
0712                     !std::is_same_v<decltype(unpacked.last), sentinel_t<R>>) {
0713                     return unpacking_view(std::forward<R>(r));
0714                 } else {
0715                     return std::forward<R>(r);
0716                 }
0717             } else {
0718                 return std::forward<R>(r);
0719             }
0720         }
0721 
0722         template<class R>
0723         using unpacked_range = decltype(detail::unpack_range(std::declval<R>()));
0724 
0725         template<template<class> class View, format Format>
0726         struct as_utf_impl : stl_interfaces::range_adaptor_closure<as_utf_impl<View, Format>>
0727         {
0728 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0729             template<class R>
0730                 requires is_utf_view<std::remove_cvref_t<R>> ||
0731                          (std::ranges::viewable_range<R> &&
0732                           can_utf_view<unpacked_range<R>, View>)
0733 #else
0734             template<typename R>
0735 #endif
0736             [[nodiscard]] constexpr auto operator()(R && r) const
0737             {
0738                 using T = detail::remove_cv_ref_t<R>;
0739                 if constexpr (detail::is_empty_view<T>) {
0740 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0741                     return std::ranges::empty_view<format_to_type_t<Format>>{};
0742 #else
0743                     return 42; // Never gonna happen.
0744 #endif
0745                 } else if constexpr (is_utf_view<T>) {
0746                     return View(std::forward<R>(r).base());
0747                 } else if constexpr (detail::is_charn_view<T>) {
0748                     return View(std::forward<R>(r));
0749                 } else {
0750                     return View(detail::unpack_range(std::forward<R>(r)));
0751                 }
0752             }
0753         };
0754 
0755         template<class T>
0756         constexpr bool is_utf32_view = false;
0757         template<class V>
0758         constexpr bool is_utf32_view<utf_view<format::utf32, V>> = true;
0759     }
0760 
0761     inline constexpr detail::as_utf_impl<utf8_view, format::utf8> as_utf8;
0762     inline constexpr detail::as_utf_impl<utf16_view, format::utf16> as_utf16;
0763     inline constexpr detail::as_utf_impl<utf32_view, format::utf32> as_utf32;
0764 
0765 }}
0766 
0767 #if BOOST_PARSER_USE_CONCEPTS && defined(__cpp_lib_ranges)
0768 
0769 namespace std::ranges {
0770 #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS
0771     template<class V, auto F>
0772     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::project_view<V, F>> =
0773         enable_borrowed_range<V>;
0774 #endif
0775 
0776     template<class V>
0777     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::unpacking_view<V>> =
0778         enable_borrowed_range<V>;
0779 
0780     template<boost::parser::detail::text::format Format, class V>
0781     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf_view<Format, V>> =
0782         enable_borrowed_range<V>;
0783 
0784     template<class V>
0785     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf8_view<V>> =
0786         enable_borrowed_range<V>;
0787     template<class V>
0788     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf16_view<V>> =
0789         enable_borrowed_range<V>;
0790     template<class V>
0791     inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf32_view<V>> =
0792         enable_borrowed_range<V>;
0793 }
0794 
0795 #endif
0796 
0797 #endif