Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-03 08:13:51

0001 // -*- C++ -*-
0002 //===----------------------------------------------------------------------===//
0003 //
0004 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0005 // See https://llvm.org/LICENSE.txt for license information.
0006 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0007 //
0008 //===----------------------------------------------------------------------===//
0009 
0010 #ifndef _LIBCPP___FORMAT_WRITE_ESCAPED_H
0011 #define _LIBCPP___FORMAT_WRITE_ESCAPED_H
0012 
0013 #include <__algorithm/ranges_copy.h>
0014 #include <__algorithm/ranges_for_each.h>
0015 #include <__charconv/to_chars_integral.h>
0016 #include <__charconv/to_chars_result.h>
0017 #include <__chrono/statically_widen.h>
0018 #include <__format/escaped_output_table.h>
0019 #include <__format/extended_grapheme_cluster_table.h>
0020 #include <__format/formatter_output.h>
0021 #include <__format/parser_std_format_spec.h>
0022 #include <__format/unicode.h>
0023 #include <__iterator/back_insert_iterator.h>
0024 #include <__memory/addressof.h>
0025 #include <__system_error/errc.h>
0026 #include <__type_traits/make_unsigned.h>
0027 #include <__utility/move.h>
0028 #include <string_view>
0029 
0030 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
0031 #  pragma GCC system_header
0032 #endif
0033 
0034 _LIBCPP_PUSH_MACROS
0035 #include <__undef_macros>
0036 
0037 _LIBCPP_BEGIN_NAMESPACE_STD
0038 
0039 namespace __formatter {
0040 
0041 #if _LIBCPP_STD_VER >= 20
0042 
0043 /// Writes a string using format's width estimation algorithm.
0044 ///
0045 /// \note When \c _LIBCPP_HAS_UNICODE is false the function assumes the input is ASCII.
0046 template <class _CharT>
0047 _LIBCPP_HIDE_FROM_ABI auto
0048 __write_string(basic_string_view<_CharT> __str,
0049                output_iterator<const _CharT&> auto __out_it,
0050                __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
0051   if (!__specs.__has_precision())
0052     return __formatter::__write_string_no_precision(__str, std::move(__out_it), __specs);
0053 
0054   int __size = __formatter::__truncate(__str, __specs.__precision_);
0055 
0056   return __formatter::__write(__str.begin(), __str.end(), std::move(__out_it), __specs, __size);
0057 }
0058 
0059 #endif // _LIBCPP_STD_VER >= 20
0060 #if _LIBCPP_STD_VER >= 23
0061 
0062 struct __nul_terminator {};
0063 
0064 template <class _CharT>
0065 _LIBCPP_HIDE_FROM_ABI bool operator==(const _CharT* __cstr, __nul_terminator) {
0066   return *__cstr == _CharT('\0');
0067 }
0068 
0069 template <class _CharT>
0070 _LIBCPP_HIDE_FROM_ABI void
0071 __write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _CharT* __prefix) {
0072   back_insert_iterator __out_it{__str};
0073   std::ranges::copy(__prefix, __nul_terminator{}, __out_it);
0074 
0075   char __buffer[8];
0076   to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16);
0077   _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small");
0078   std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it);
0079 
0080   __str += _CharT('}');
0081 }
0082 
0083 // [format.string.escaped]/2.2.1.2
0084 // ...
0085 // then the sequence \u{hex-digit-sequence} is appended to E, where
0086 // hex-digit-sequence is the shortest hexadecimal representation of C using
0087 // lower-case hexadecimal digits.
0088 template <class _CharT>
0089 _LIBCPP_HIDE_FROM_ABI void __write_well_formed_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value) {
0090   __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\u{"));
0091 }
0092 
0093 // [format.string.escaped]/2.2.3
0094 // Otherwise (X is a sequence of ill-formed code units), each code unit U is
0095 // appended to E in order as the sequence \x{hex-digit-sequence}, where
0096 // hex-digit-sequence is the shortest hexadecimal representation of U using
0097 // lower-case hexadecimal digits.
0098 template <class _CharT>
0099 _LIBCPP_HIDE_FROM_ABI void __write_escape_ill_formed_code_unit(basic_string<_CharT>& __str, char32_t __value) {
0100   __formatter::__write_escaped_code_unit(__str, __value, _LIBCPP_STATICALLY_WIDEN(_CharT, "\\x{"));
0101 }
0102 
0103 template <class _CharT>
0104 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool
0105 __is_escaped_sequence_written(basic_string<_CharT>& __str, bool __last_escaped, char32_t __value) {
0106 #  if !_LIBCPP_HAS_UNICODE
0107   // For ASCII assume everything above 127 is printable.
0108   if (__value > 127)
0109     return false;
0110 #  endif
0111 
0112   // [format.string.escaped]/2.2.1.2.1
0113   //   CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar
0114   //   value whose Unicode property General_Category has a value in the groups
0115   //   Separator (Z) or Other (C), as described by UAX #44 of the Unicode Standard,
0116   if (!__escaped_output_table::__needs_escape(__value))
0117     // [format.string.escaped]/2.2.1.2.2
0118     //   CE is UTF-8, UTF-16, or UTF-32 and C corresponds to a Unicode scalar
0119     //   value with the Unicode property Grapheme_Extend=Yes as described by UAX
0120     //   #44 of the Unicode Standard and C is not immediately preceded in S by a
0121     //   character P appended to E without translation to an escape sequence,
0122     if (!__last_escaped || __extended_grapheme_custer_property_boundary::__get_property(__value) !=
0123                                __extended_grapheme_custer_property_boundary::__property::__Extend)
0124       return false;
0125 
0126   __formatter::__write_well_formed_escaped_code_unit(__str, __value);
0127   return true;
0128 }
0129 
0130 template <class _CharT>
0131 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr char32_t __to_char32(_CharT __value) {
0132   return static_cast<make_unsigned_t<_CharT>>(__value);
0133 }
0134 
0135 enum class __escape_quotation_mark { __apostrophe, __double_quote };
0136 
0137 // [format.string.escaped]/2
0138 template <class _CharT>
0139 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI bool __is_escaped_sequence_written(
0140     basic_string<_CharT>& __str, char32_t __value, bool __last_escaped, __escape_quotation_mark __mark) {
0141   // 2.2.1.1 - Mapped character in [tab:format.escape.sequences]
0142   switch (__value) {
0143   case _CharT('\t'):
0144     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\t");
0145     return true;
0146   case _CharT('\n'):
0147     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\n");
0148     return true;
0149   case _CharT('\r'):
0150     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, "\\r");
0151     return true;
0152   case _CharT('\''):
0153     if (__mark == __escape_quotation_mark::__apostrophe)
0154       __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\')");
0155     else
0156       __str += __value;
0157     return true;
0158   case _CharT('"'):
0159     if (__mark == __escape_quotation_mark::__double_quote)
0160       __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\")");
0161     else
0162       __str += __value;
0163     return true;
0164   case _CharT('\\'):
0165     __str += _LIBCPP_STATICALLY_WIDEN(_CharT, R"(\\)");
0166     return true;
0167 
0168   // 2.2.1.2 - Space
0169   case _CharT(' '):
0170     __str += __value;
0171     return true;
0172   }
0173 
0174   // 2.2.2
0175   //   Otherwise, if X is a shift sequence, the effect on E and further
0176   //   decoding of S is unspecified.
0177   // For now shift sequences are ignored and treated as Unicode. Other parts
0178   // of the format library do the same. It's unknown how ostream treats them.
0179   // TODO FMT determine what to do with shift sequences.
0180 
0181   // 2.2.1.2.1 and 2.2.1.2.2 - Escape
0182   return __formatter::__is_escaped_sequence_written(__str, __last_escaped, __formatter::__to_char32(__value));
0183 }
0184 
0185 template <class _CharT>
0186 _LIBCPP_HIDE_FROM_ABI void
0187 __escape(basic_string<_CharT>& __str, basic_string_view<_CharT> __values, __escape_quotation_mark __mark) {
0188   __unicode::__code_point_view<_CharT> __view{__values.begin(), __values.end()};
0189 
0190   // When the first code unit has the property Grapheme_Extend=Yes it needs to
0191   // be escaped. This happens when the previous code unit was also escaped.
0192   bool __escape = true;
0193   while (!__view.__at_end()) {
0194     auto __first                                  = __view.__position();
0195     typename __unicode::__consume_result __result = __view.__consume();
0196     if (__result.__status == __unicode::__consume_result::__ok) {
0197       __escape = __formatter::__is_escaped_sequence_written(__str, __result.__code_point, __escape, __mark);
0198       if (!__escape)
0199         // 2.2.1.3 - Add the character
0200         ranges::copy(__first, __view.__position(), std::back_insert_iterator(__str));
0201     } else {
0202       // 2.2.3 sequence of ill-formed code units
0203       ranges::for_each(__first, __view.__position(), [&](_CharT __value) {
0204         __formatter::__write_escape_ill_formed_code_unit(__str, __formatter::__to_char32(__value));
0205       });
0206     }
0207   }
0208 }
0209 
0210 template <class _CharT>
0211 _LIBCPP_HIDE_FROM_ABI auto
0212 __format_escaped_char(_CharT __value,
0213                       output_iterator<const _CharT&> auto __out_it,
0214                       __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
0215   basic_string<_CharT> __str;
0216   __str += _CharT('\'');
0217   __formatter::__escape(__str, basic_string_view{std::addressof(__value), 1}, __escape_quotation_mark::__apostrophe);
0218   __str += _CharT('\'');
0219   return __formatter::__write(__str.data(), __str.data() + __str.size(), std::move(__out_it), __specs, __str.size());
0220 }
0221 
0222 template <class _CharT>
0223 _LIBCPP_HIDE_FROM_ABI auto
0224 __format_escaped_string(basic_string_view<_CharT> __values,
0225                         output_iterator<const _CharT&> auto __out_it,
0226                         __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) {
0227   basic_string<_CharT> __str;
0228   __str += _CharT('"');
0229   __formatter::__escape(__str, __values, __escape_quotation_mark::__double_quote);
0230   __str += _CharT('"');
0231   return __formatter::__write_string(basic_string_view{__str}, std::move(__out_it), __specs);
0232 }
0233 
0234 #endif // _LIBCPP_STD_VER >= 23
0235 
0236 } // namespace __formatter
0237 
0238 _LIBCPP_END_NAMESPACE_STD
0239 
0240 _LIBCPP_POP_MACROS
0241 
0242 #endif // _LIBCPP___FORMAT_WRITE_ESCAPED_H