boost/parser/detail/text/transcode_view.hpp
// Copyright (C) 2020 T. Zachary Laine // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP #define BOOST_PARSER_DETAIL_TEXT_TRANSCODE_VIEW_HPP #include <boost/parser/detail/text/transcode_algorithm.hpp> #include <boost/parser/detail/text/transcode_iterator.hpp> #include <boost/parser/detail/text/detail/all_t.hpp> #include <boost/parser/detail/stl_interfaces/view_interface.hpp> #include <boost/parser/detail/stl_interfaces/view_adaptor.hpp> #include <climits> namespace boost::parser::detail { namespace text { namespace detail { template<class I> constexpr auto iterator_to_tag() { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS if constexpr (std::random_access_iterator<I>) { return std::random_access_iterator_tag{}; } else if constexpr (std::bidirectional_iterator<I>) { return std::bidirectional_iterator_tag{}; } else if constexpr (std::forward_iterator<I>) { #else if constexpr (detail::random_access_iterator_v<I>) { return std::random_access_iterator_tag{}; } else if constexpr (detail::bidirectional_iterator_v<I>) { return std::bidirectional_iterator_tag{}; } else if constexpr (detail::forward_iterator_v<I>) { #endif return std::forward_iterator_tag{}; } else { return std::input_iterator_tag{}; } } template<class I> using iterator_to_tag_t = decltype(iterator_to_tag<I>()); #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class T> using with_reference = T &; template<typename T> concept can_reference = requires { typename with_reference<T>; }; #endif #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class Char> struct cast_to_charn { constexpr Char operator()(Char c) const { return c; } }; #else struct cast_to_char8; struct cast_to_char16; struct cast_to_char32; template<typename Tag, typename Arg> auto function_for_tag(Arg arg) { #if defined(__cpp_char8_t) if constexpr (std::is_same_v<Tag, cast_to_char8>) { return (char8_t)arg; } else #endif if constexpr (std::is_same_v<Tag, cast_to_char16>) { return (char16_t)arg; } else if constexpr (std::is_same_v<Tag, cast_to_char32>) { return (char32_t)arg; } } #endif } #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V, auto F> requires std::ranges::view<V> && std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> && detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>> #else template<typename V, typename F> // F is a tag type in c++17 #endif class project_view : public stl_interfaces::view_interface<project_view<V, F>> { V base_ = V(); template<bool Const> class iterator; template<bool Const> class sentinel; public: constexpr project_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr explicit project_view(V base) : base_(std::move(base)) {} constexpr V& base() & { return base_; } constexpr const V& base() const& { return base_; } constexpr V base() && { return std::move(base_); } constexpr iterator<false> begin() { return iterator<false>{detail::begin(base_)}; } constexpr iterator<true> begin() const #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::ranges::range<const V> #endif { return iterator<true>{detail::begin(base_)}; } constexpr sentinel<false> end() { return sentinel<false>{detail::end(base_)}; } #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS constexpr iterator<false> end() requires std::ranges::common_range<V> { return iterator<false>{detail::end(base_)}; } #endif constexpr sentinel<true> end() const #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::ranges::range<const V> { return sentinel<true>{detail::end(base_)}; } constexpr iterator<true> end() const requires std::ranges::common_range<const V> #endif { return iterator<true>{detail::end(base_)}; } #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS constexpr auto size() requires std::ranges::sized_range<V> { return std::ranges::size(base_); } constexpr auto size() const requires std::ranges::sized_range<const V> { return std::ranges::size(base_); } #endif }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V, auto F> requires std::ranges::view<V> && std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> && detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>> #else template<typename V, typename F> #endif template<bool Const> class project_view<V, F>::iterator : public boost::parser::detail::stl_interfaces::proxy_iterator_interface< iterator<Const>, detail::iterator_to_tag_t<detail::iterator_t<detail::maybe_const<Const, V>>>, #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::invoke_result_t<decltype(F)&, detail::range_reference_t<V>> #else decltype(detail::function_for_tag<F>(0)) #endif > { using iterator_type = detail::iterator_t<detail::maybe_const<Const, V>>; using sentinel_type = detail::sentinel_t<detail::maybe_const<Const, V>>; using reference_type = #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS std::invoke_result_t<decltype(F) &, detail::range_reference_t<V>> #else decltype(detail::function_for_tag<F>(0)) #endif ; using sentinel = project_view<V, F>::sentinel<Const>; friend boost::parser::detail::stl_interfaces::access; iterator_type & base_reference() noexcept { return it_; } iterator_type base_reference() const { return it_; } iterator_type it_ = iterator_type(); friend project_view<V, F>::sentinel<Const>; template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr bool operator==(const iterator<OtherConst> & x, const sentinel & y) { return x.it_ == y.end_; } template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>> operator-(const iterator<OtherConst> & x, const sentinel & y) { return x.it_ - y.end_; } template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>> operator-(const sentinel & y, const iterator<OtherConst> & x) { return y.end_ - x.it_; } public: constexpr iterator() = default; constexpr iterator(iterator_type it) : it_(std::move(it)) {} #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS constexpr reference_type operator*() const { return F(*it_); } #else constexpr reference_type operator*() const { return detail::function_for_tag<F>(*it_); } #endif }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V, auto F> requires std::ranges::view<V> && std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<V>> && detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<V>>> #else template<typename V, typename F> #endif template<bool Const> class project_view<V, F>::sentinel { using Base = detail::maybe_const<Const, V>; using sentinel_type = detail::sentinel_t<Base>; sentinel_type end_ = sentinel_type(); public: constexpr sentinel() = default; constexpr explicit sentinel(sentinel_type end) : end_(std::move(end)) {} #if !BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<bool Enable = Const, class = std::enable_if_t<Enable>> #endif constexpr sentinel(sentinel<!Const> i) #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires Const && std::convertible_to<detail::sentinel_t<V>, detail::sentinel_t<Base>> #endif : end_(std::move(i.end_)) {} constexpr sentinel_type base() const { return end_; } template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr bool operator==(const iterator<OtherConst> & x, const sentinel & y) { return x.it_ == y.end_; } template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>> operator-(const iterator<OtherConst> & x, const sentinel & y) { return x.it_ - y.end_; } template<bool OtherConst> #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::sized_sentinel_for<sentinel_type, std::ranges::iterator_t<detail::maybe_const<OtherConst, V>>> #endif friend constexpr detail::range_difference_t<detail::maybe_const<OtherConst, V>> operator-(const sentinel & y, const iterator<OtherConst> & x) { return y.end_ - x.it_; } }; namespace detail { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<auto F> #else template<typename F> #endif struct project_impl : stl_interfaces::range_adaptor_closure<project_impl<F>> { template<class R> using project_view_type = project_view<R, F>; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class R> requires std::ranges::viewable_range<R> && std::ranges::input_range<R> && std::regular_invocable<decltype(F)&, std::ranges::range_reference_t<R>> && detail::can_reference<std::invoke_result_t<decltype(F)&, std::ranges::range_reference_t<R>>> #else template<class R> #endif [[nodiscard]] constexpr auto operator()(R && r) const { return project_view_type<R>(std::forward<R>(r)); } }; } #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<auto F> #else template<typename F> #endif constexpr detail::project_impl<F> project{}; #if defined(__cpp_char8_t) #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V> requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char8_t> class char8_view : public project_view<V, detail::cast_to_charn<char8_type>{}> #else template<typename V> class char8_view : public project_view<V, detail::cast_to_char8> #endif { public: constexpr char8_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr char8_view(V base) : #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS project_view<V, detail::cast_to_charn<char8_t>{}>{std::move(base)} #else project_view<V, detail::cast_to_char8>{std::move(base)} #endif {} }; #endif #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V> requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char16_t> class char16_view : public project_view<V, detail::cast_to_charn<char16_t>{}> #else template<typename V> class char16_view : public project_view<V, detail::cast_to_char16> #endif { public: constexpr char16_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr char16_view(V base) : #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS project_view<V, detail::cast_to_charn<char16_t>{}>{std::move(base)} #else project_view<V, detail::cast_to_char16>{std::move(base)} #endif {} }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<std::ranges::input_range V> requires std::ranges::view<V> && std::convertible_to<std::ranges::range_reference_t<V>, char32_t> class char32_view : public project_view<V, detail::cast_to_charn<char32_t>{}> #else template<typename V> class char32_view : public project_view<V, detail::cast_to_char32> #endif { public: constexpr char32_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr char32_view(V base) : #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS project_view<V, detail::cast_to_charn<char32_t>{}>{std::move(base)} #else project_view<V, detail::cast_to_char32>{std::move(base)} #endif {} }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class R> char8_view(R &&) -> char8_view<detail::all_t<R>>; template<class R> char16_view(R &&) -> char16_view<detail::all_t<R>>; template<class R> char32_view(R &&) -> char32_view<detail::all_t<R>>; #endif namespace detail { template<template<class> class View, format Format> struct as_charn_impl : stl_interfaces::range_adaptor_closure<as_charn_impl<View, Format>> { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class R> requires (std::ranges::viewable_range<R> && std::ranges::input_range<R> && std::convertible_to<std::ranges::range_reference_t<R>, format_to_type_t<Format>>) #else template<class R> #endif [[nodiscard]] constexpr auto operator()(R && r) const { using T = remove_cv_ref_t<R>; if constexpr (detail::is_empty_view<T>) { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS return std::ranges::empty_view<format_to_type_t<Format>>{}; #else return 42; // Never gonna happen. #endif } else { return View(std::forward<R>(r)); } } }; template<class T> constexpr bool is_charn_view = false; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class V> constexpr bool is_charn_view<char8_view<V>> = true; #endif template<class V> constexpr bool is_charn_view<char16_view<V>> = true; template<class V> constexpr bool is_charn_view<char32_view<V>> = true; } #if defined(__cpp_char8_t) inline constexpr detail::as_charn_impl<char8_view, format::utf8> as_char8_t; #endif inline constexpr detail::as_charn_impl<char16_view, format::utf16> as_char16_t; inline constexpr detail::as_charn_impl<char32_view, format::utf32> as_char32_t; // clang-format off #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<utf_range V> requires std::ranges::view<V> && std::ranges::forward_range<V> #else template<typename V> #endif class unpacking_view : public stl_interfaces::view_interface<unpacking_view<V>> { V base_ = V(); public: constexpr unpacking_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr unpacking_view(V base) : base_(std::move(base)) {} constexpr V base() const & #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::copy_constructible<V> #endif { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto code_units() const noexcept { auto unpacked = boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(base_), detail::end(base_)); return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last); } constexpr auto begin() { return code_units().begin(); } constexpr auto begin() const { return code_units().begin(); } constexpr auto end() { return code_units().end(); } constexpr auto end() const { return code_units().end(); } }; template<class R> unpacking_view(R &&) -> unpacking_view<detail::all_t<R>>; // clang-format on #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<format Format, utf_range V> requires std::ranges::view<V> #else template<format Format, typename V> #endif class utf_view : public stl_interfaces::view_interface<utf_view<Format, V>> { V base_ = V(); template<format FromFormat, class I, class S> static constexpr auto make_begin(I first, S last) { if constexpr (detail::bidirectional_iterator_v<I>) { return utf_iterator<FromFormat, Format, I, S>{first, first, last}; } else { return utf_iterator<FromFormat, Format, I, S>{first, last}; } } template<format FromFormat, class I, class S> static constexpr auto make_end(I first, S last) { if constexpr (!std::is_same_v<I, S>) { return last; } else if constexpr (detail::bidirectional_iterator_v<I>) { return utf_iterator<FromFormat, Format, I, S>{first, last, last}; } else { return utf_iterator<FromFormat, Format, I, S>{last, last}; } } public: #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS constexpr utf_view() requires std::default_initializable<V> = default; #endif constexpr utf_view(V base) : base_{std::move(base)} {} constexpr V base() const & #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::copy_constructible<V> #endif { return base_; } constexpr V base() && { return std::move(base_); } constexpr auto begin() { constexpr format from_format = detail::format_of<detail::range_value_t<V>>(); if constexpr(detail::is_charn_view<V>) { return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base())); } else { return make_begin<from_format>(detail::begin(base_), detail::end(base_)); } } constexpr auto begin() const { constexpr format from_format = detail::format_of<detail::range_value_t<const V>>(); if constexpr(detail::is_charn_view<V>) { return make_begin<from_format>(detail::begin(base_.base()), detail::end(base_.base())); } else { return make_begin<from_format>(detail::begin(base_), detail::end(base_)); } } constexpr auto end() { constexpr format from_format = detail::format_of<detail::range_value_t<V>>(); if constexpr(detail::is_charn_view<V>) { return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base())); } else { return make_end<from_format>(detail::begin(base_), detail::end(base_)); } } constexpr auto end() const { constexpr format from_format = detail::format_of<detail::range_value_t<const V>>(); if constexpr(detail::is_charn_view<V>) { return make_end<from_format>(detail::begin(base_.base()), detail::end(base_.base())); } else { return make_end<from_format>(detail::begin(base_), detail::end(base_)); } } /** Stream inserter; performs unformatted output, in UTF-8 encoding. */ friend std::ostream & operator<<(std::ostream & os, utf_view v) { if constexpr (Format == format::utf8) { auto out = std::ostreambuf_iterator<char>(os); for (auto it = v.begin(); it != v.end(); ++it, ++out) { *out = *it; } } else { boost::parser::detail::text::transcode_to_utf8( v.begin(), v.end(), std::ostreambuf_iterator<char>(os)); } return os; } #if defined(BOOST_TEXT_DOXYGEN) || defined(_MSC_VER) /** Stream inserter; performs unformatted output, in UTF-16 encoding. Defined on Windows only. */ friend std::wostream & operator<<(std::wostream & os, utf_view v) { if constexpr (Format == format::utf16) { auto out = std::ostreambuf_iterator<wchar_t>(os); for (auto it = v.begin(); it != v.end(); ++it, ++out) { *out = *it; } } else { boost::parser::detail::text::transcode_to_utf16( v.begin(), v.end(), std::ostreambuf_iterator<wchar_t>(os)); } return os; } #endif }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<utf_range V> requires std::ranges::view<V> #else template<typename V> #endif class utf8_view : public utf_view<format::utf8, V> { public: constexpr utf8_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr utf8_view(V base) : utf_view<format::utf8, V>{std::move(base)} {} }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<utf_range V> requires std::ranges::view<V> #else template<typename V> #endif class utf16_view : public utf_view<format::utf16, V> { public: constexpr utf16_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr utf16_view(V base) : utf_view<format::utf16, V>{std::move(base)} {} }; #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<utf_range V> requires std::ranges::view<V> #else template<typename V> #endif class utf32_view : public utf_view<format::utf32, V> { public: constexpr utf32_view() #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS requires std::default_initializable<V> #endif = default; constexpr utf32_view(V base) : utf_view<format::utf32, V>{std::move(base)} {} }; template<class R> utf8_view(R &&) -> utf8_view<detail::all_t<R>>; template<class R> utf16_view(R &&) -> utf16_view<detail::all_t<R>>; template<class R> utf32_view(R &&) -> utf32_view<detail::all_t<R>>; #if defined(BOOST_TEXT_DOXYGEN) /** A view adaptor that produces a UTF-8 view of the given view. */ constexpr detail::unspecified as_utf8; /** A view adaptor that produces a UTF-16 view of the given view. */ constexpr detail::unspecified as_utf16; /** A view adaptor that produces a UTF-32 view of the given view. */ constexpr detail::unspecified as_utf32; #endif namespace detail { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class R, template<class> class View> concept can_utf_view = requires(R && r) { View((R &&)r); }; #else template<class R, class View> using can_utf_view_expr = decltype(View(std::declval<R>())); template<class R, template<class> class View> constexpr bool can_utf_view = is_detected_v<can_utf_view_expr, R, View<R>>; #endif template<class T> constexpr bool is_utf_view = false; template<class T> constexpr bool is_utf_view<utf8_view<T>> = true; template<class T> constexpr bool is_utf_view<utf16_view<T>> = true; template<class T> constexpr bool is_utf_view<utf32_view<T>> = true; template<format F, class T> constexpr bool is_utf_view<utf_view<F, T>> = true; template<typename T> constexpr bool is_bounded_array_v = false; template<typename T, int N> constexpr bool is_bounded_array_v<T[N]> = true; template<class R> constexpr decltype(auto) unpack_range(R && r) { using T = detail::remove_cv_ref_t<R>; if constexpr (forward_range_v<T>) { auto unpacked = boost::parser::detail::text::unpack_iterator_and_sentinel(detail::begin(r), detail::end(r)); if constexpr (is_bounded_array_v<T>) { constexpr auto n = std::extent_v<T>; if (n && !r[n - 1]) --unpacked.last; return BOOST_PARSER_DETAIL_TEXT_SUBRANGE(unpacked.first, unpacked.last); } else if constexpr ( !std::is_same_v<decltype(unpacked.first), iterator_t<R>> || !std::is_same_v<decltype(unpacked.last), sentinel_t<R>>) { return unpacking_view(std::forward<R>(r)); } else { return std::forward<R>(r); } } else { return std::forward<R>(r); } } template<class R> using unpacked_range = decltype(detail::unpack_range(std::declval<R>())); template<template<class> class View, format Format> struct as_utf_impl : stl_interfaces::range_adaptor_closure<as_utf_impl<View, Format>> { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class R> requires is_utf_view<std::remove_cvref_t<R>> || (std::ranges::viewable_range<R> && can_utf_view<unpacked_range<R>, View>) #else template<typename R> #endif [[nodiscard]] constexpr auto operator()(R && r) const { using T = detail::remove_cv_ref_t<R>; if constexpr (detail::is_empty_view<T>) { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS return std::ranges::empty_view<format_to_type_t<Format>>{}; #else return 42; // Never gonna happen. #endif } else if constexpr (is_utf_view<T>) { return View(std::forward<R>(r).base()); } else if constexpr (detail::is_charn_view<T>) { return View(std::forward<R>(r)); } else { return View(detail::unpack_range(std::forward<R>(r))); } } }; template<class T> constexpr bool is_utf32_view = false; template<class V> constexpr bool is_utf32_view<utf_view<format::utf32, V>> = true; } inline constexpr detail::as_utf_impl<utf8_view, format::utf8> as_utf8; inline constexpr detail::as_utf_impl<utf16_view, format::utf16> as_utf16; inline constexpr detail::as_utf_impl<utf32_view, format::utf32> as_utf32; }} #if BOOST_PARSER_USE_CONCEPTS && defined(__cpp_lib_ranges) namespace std::ranges { #if BOOST_PARSER_DETAIL_TEXT_USE_CONCEPTS template<class V, auto F> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::project_view<V, F>> = enable_borrowed_range<V>; #endif template<class V> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::unpacking_view<V>> = enable_borrowed_range<V>; template<boost::parser::detail::text::format Format, class V> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf_view<Format, V>> = enable_borrowed_range<V>; template<class V> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf8_view<V>> = enable_borrowed_range<V>; template<class V> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf16_view<V>> = enable_borrowed_range<V>; template<class V> inline constexpr bool enable_borrowed_range<boost::parser::detail::text::utf32_view<V>> = enable_borrowed_range<V>; } #endif #endif