diff --git a/stl/inc/__msvc_format_ucd_tables.hpp b/stl/inc/__msvc_format_ucd_tables.hpp index bc5c7c355ea..d6bc251ca3b 100644 --- a/stl/inc/__msvc_format_ucd_tables.hpp +++ b/stl/inc/__msvc_format_ucd_tables.hpp @@ -73,7 +73,7 @@ _STL_DISABLE_CLANG_WARNINGS _STD_BEGIN -template +template struct _Unicode_property_data { uint32_t _Lower_bounds[_NumRanges]; uint16_t _Props_and_size[_NumRanges]; @@ -86,11 +86,17 @@ struct _Unicode_property_data { --_Upper_idx; const uint32_t _Lower_bound = _Lower_bounds[_Upper_idx]; const uint16_t _Data = _Props_and_size[_Upper_idx]; - const uint16_t _Size = static_cast(_Data & 0x0FFF); - const _ValueEnum _Prop = static_cast<_ValueEnum>((_Data & 0xF000) >> 12); _STL_INTERNAL_CHECK(_Code_point >= _Lower_bound); - if (_Code_point < _Lower_bound + _Size) { - return _Prop; + if constexpr (_Is_binary_property) { + if (_Code_point < _Lower_bound + _Data) { + return static_cast<_ValueEnum>(0); + } + } else { + const uint16_t _Size = static_cast(_Data & 0x0FFF); + const _ValueEnum _Prop = static_cast<_ValueEnum>((_Data & 0xF000) >> 12); + if (_Code_point < _Lower_bound + _Size) { + return _Prop; + } } return _No_value_constant; } @@ -101,25 +107,28 @@ struct _Unicode_property_data { // // _Extended_Pictographic_property_data comes from ucd/emoji/emoji-data.txt. // +// __printable_property_data comes from ucd/extracted/DerivedGeneralCategory.txt. +// +// _Grapheme_Extend_property_data comes from ucd/DerivedCoreProperties.txt. +// // The enums containing the values for the properties are also generated, in order to ensure they match // up correctly with how we're parsing them. // -// Both sets of data tables are generated by tools/unicode_properties_parse/grapheme_break_property_data_gen.py in the +// All sets of data tables are generated by tools/unicode_properties_parse/grapheme_break_property_data_gen.py in the // https://github.com/microsoft/stl repository. // // The data format is a set of arrays for each character property. The first is an array of uint32_t encoding // the lower bound of each range of codepoints that has the given property. -// The second is an array of uint16_t encoding both the range size and property value as follows: -// 16 12 0 -// +-----------------------------------------------------+ -// | property_value | range_size | -// +-----------------------------------------------------+ -// that is: the size is stored in the least significant 12 bits -// (leading to a max size of 4095), and the property value is stored in the most significant 4 bits, -// leading to a maximum of 16 property values. -// -// Note that the Extended_Pictographic property only has one value, and we encode it as zero in the most significant 4 -// bits, so the most significant 4 bits of _Props_and_size are "unused", in some sense. +// The second is an array of uint16_t. +// - For enumerated properties, this array encodes both the range size and property value as follows: +// 16 12 0 +// +-----------------------------------------------------+ +// | property_value | range_size | +// +-----------------------------------------------------+ +// that is: the size is stored in the least significant 12 bits +// (leading to a max size of 4095), and the property value is stored in the most significant 4 bits, +// leading to a maximum of 16 property values. +// - For binary properties, this array simply stores the range size. // // Codepoint ranges may not overlap, and, within one property, a codepoint may only appear once. Furthermore the // codepoint lower bounds appear in sorted (ascending) order. @@ -145,7 +154,7 @@ enum class _Grapheme_Break_property_values : uint8_t { // GraphemeBreakProperty-15.0.0.txt // Date: 2022-04-27, 17:07:38 GMT -inline constexpr _Unicode_property_data<_Grapheme_Break_property_values, 1371> _Grapheme_Break_property_data{ +inline constexpr _Unicode_property_data<_Grapheme_Break_property_values, 1371, false> _Grapheme_Break_property_data{ {0x0, 0xa, 0xb, 0xd, 0xe, 0x7f, 0xad, 0x300, 0x483, 0x591, 0x5bf, 0x5c1, 0x5c4, 0x5c7, 0x600, 0x610, 0x61c, 0x64b, 0x670, 0x6d6, 0x6dd, 0x6df, 0x6e7, 0x6ea, 0x70f, 0x711, 0x730, 0x7a6, 0x7eb, 0x7fd, 0x816, 0x81b, 0x825, 0x829, 0x859, 0x890, 0x898, 0x8ca, 0x8e2, 0x8e3, 0x903, 0x93a, 0x93b, 0x93c, 0x93e, 0x941, 0x949, 0x94d, 0x94e, 0x951, @@ -350,7 +359,7 @@ enum class _Extended_Pictographic_property_values : uint8_t { _Extended_Pictogra // emoji-data.txt // Date: 2022-08-02, 00:26:10 GMT -inline constexpr _Unicode_property_data<_Extended_Pictographic_property_values, 78> +inline constexpr _Unicode_property_data<_Extended_Pictographic_property_values, 78, true> _Extended_Pictographic_property_data{ {0xa9, 0xae, 0x203c, 0x2049, 0x2122, 0x2139, 0x2194, 0x21a9, 0x231a, 0x2328, 0x2388, 0x23cf, 0x23e9, 0x23f8, 0x24c2, 0x25aa, 0x25b6, 0x25c0, 0x25fb, 0x2600, 0x2607, 0x2614, 0x2690, 0x2708, 0x2714, 0x2716, 0x271d, @@ -364,6 +373,156 @@ inline constexpr _Unicode_property_data<_Extended_Pictographic_property_values, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x100, 0x3, 0x1, 0x6, 0x2, 0x1, 0xa, 0x39, 0xf, 0x1, 0x1, 0x9, 0x4, 0x1b2, 0x13e, 0x10a, 0x80, 0xc, 0x2b, 0x4, 0x8, 0x6, 0x8, 0x52, 0x2f, 0xa, 0x1b9, 0x3fe}}; +// DerivedGeneralCategory-15.0.0.txt +// Date: 2022-04-26, 23:14:35 GMT +enum class __printable_property_values : uint8_t { _Yes_value, _No_value = 255 }; + +// DerivedGeneralCategory-15.0.0.txt +// Date: 2022-04-26, 23:14:35 GMT +inline constexpr _Unicode_property_data<__printable_property_values, 711, true> __printable_property_data{ + {0x20, 0xa1, 0xae, 0x37a, 0x384, 0x38c, 0x38e, 0x3a3, 0x531, 0x559, 0x58d, 0x591, 0x5d0, 0x5ef, 0x606, 0x61d, 0x6de, + 0x710, 0x74d, 0x7c0, 0x7fd, 0x830, 0x840, 0x85e, 0x860, 0x870, 0x898, 0x8e3, 0x985, 0x98f, 0x993, 0x9aa, 0x9b2, + 0x9b6, 0x9bc, 0x9c7, 0x9cb, 0x9d7, 0x9dc, 0x9df, 0x9e6, 0xa01, 0xa05, 0xa0f, 0xa13, 0xa2a, 0xa32, 0xa35, 0xa38, + 0xa3c, 0xa3e, 0xa47, 0xa4b, 0xa51, 0xa59, 0xa5e, 0xa66, 0xa81, 0xa85, 0xa8f, 0xa93, 0xaaa, 0xab2, 0xab5, 0xabc, + 0xac7, 0xacb, 0xad0, 0xae0, 0xae6, 0xaf9, 0xb01, 0xb05, 0xb0f, 0xb13, 0xb2a, 0xb32, 0xb35, 0xb3c, 0xb47, 0xb4b, + 0xb55, 0xb5c, 0xb5f, 0xb66, 0xb82, 0xb85, 0xb8e, 0xb92, 0xb99, 0xb9c, 0xb9e, 0xba3, 0xba8, 0xbae, 0xbbe, 0xbc6, + 0xbca, 0xbd0, 0xbd7, 0xbe6, 0xc00, 0xc0e, 0xc12, 0xc2a, 0xc3c, 0xc46, 0xc4a, 0xc55, 0xc58, 0xc5d, 0xc60, 0xc66, + 0xc77, 0xc8e, 0xc92, 0xcaa, 0xcb5, 0xcbc, 0xcc6, 0xcca, 0xcd5, 0xcdd, 0xce0, 0xce6, 0xcf1, 0xd00, 0xd0e, 0xd12, + 0xd46, 0xd4a, 0xd54, 0xd66, 0xd81, 0xd85, 0xd9a, 0xdb3, 0xdbd, 0xdc0, 0xdca, 0xdcf, 0xdd6, 0xdd8, 0xde6, 0xdf2, + 0xe01, 0xe3f, 0xe81, 0xe84, 0xe86, 0xe8c, 0xea5, 0xea7, 0xec0, 0xec6, 0xec8, 0xed0, 0xedc, 0xf00, 0xf49, 0xf71, + 0xf99, 0xfbe, 0xfce, 0x1000, 0x10c7, 0x10cd, 0x10d0, 0x124a, 0x1250, 0x1258, 0x125a, 0x1260, 0x128a, 0x1290, + 0x12b2, 0x12b8, 0x12c0, 0x12c2, 0x12c8, 0x12d8, 0x1312, 0x1318, 0x135d, 0x1380, 0x13a0, 0x13f8, 0x1400, 0x1681, + 0x16a0, 0x1700, 0x171f, 0x1740, 0x1760, 0x176e, 0x1772, 0x1780, 0x17e0, 0x17f0, 0x1800, 0x180f, 0x1820, 0x1880, + 0x18b0, 0x1900, 0x1920, 0x1930, 0x1940, 0x1944, 0x1970, 0x1980, 0x19b0, 0x19d0, 0x19de, 0x1a1e, 0x1a60, 0x1a7f, + 0x1a90, 0x1aa0, 0x1ab0, 0x1b00, 0x1b50, 0x1b80, 0x1bfc, 0x1c3b, 0x1c4d, 0x1c90, 0x1cbd, 0x1cd0, 0x1d00, 0x1f18, + 0x1f20, 0x1f48, 0x1f50, 0x1f59, 0x1f5b, 0x1f5d, 0x1f5f, 0x1f80, 0x1fb6, 0x1fc6, 0x1fd6, 0x1fdd, 0x1ff2, 0x1ff6, + 0x2010, 0x2030, 0x2070, 0x2074, 0x2090, 0x20a0, 0x20d0, 0x2100, 0x2190, 0x2440, 0x2460, 0x2b76, 0x2b97, 0x2cf9, + 0x2d27, 0x2d2d, 0x2d30, 0x2d6f, 0x2d7f, 0x2da0, 0x2da8, 0x2db0, 0x2db8, 0x2dc0, 0x2dc8, 0x2dd0, 0x2dd8, 0x2de0, + 0x2e80, 0x2e9b, 0x2f00, 0x2ff0, 0x3001, 0x3041, 0x3099, 0x3105, 0x3131, 0x3190, 0x31f0, 0x3220, 0xa490, 0xa4d0, + 0xa640, 0xa700, 0xa7d0, 0xa7d3, 0xa7d5, 0xa7f2, 0xa830, 0xa840, 0xa880, 0xa8ce, 0xa8e0, 0xa95f, 0xa980, 0xa9cf, + 0xa9de, 0xaa00, 0xaa40, 0xaa50, 0xaa5c, 0xaadb, 0xab01, 0xab09, 0xab11, 0xab20, 0xab28, 0xab30, 0xab70, 0xabf0, + 0xac00, 0xd7b0, 0xd7cb, 0xf900, 0xfa70, 0xfb00, 0xfb13, 0xfb1d, 0xfb38, 0xfb3e, 0xfb40, 0xfb43, 0xfb46, 0xfbd3, + 0xfd92, 0xfdcf, 0xfdf0, 0xfe20, 0xfe54, 0xfe68, 0xfe70, 0xfe76, 0xff01, 0xffc2, 0xffca, 0xffd2, 0xffda, 0xffe0, + 0xffe8, 0xfffc, 0x10000, 0x1000d, 0x10028, 0x1003c, 0x1003f, 0x10050, 0x10080, 0x10100, 0x10107, 0x10137, + 0x10190, 0x101a0, 0x101d0, 0x10280, 0x102a0, 0x102e0, 0x10300, 0x1032d, 0x10350, 0x10380, 0x1039f, 0x103c8, + 0x10400, 0x104a0, 0x104b0, 0x104d8, 0x10500, 0x10530, 0x1056f, 0x1057c, 0x1058c, 0x10594, 0x10597, 0x105a3, + 0x105b3, 0x105bb, 0x10600, 0x10740, 0x10760, 0x10780, 0x10787, 0x107b2, 0x10800, 0x10808, 0x1080a, 0x10837, + 0x1083c, 0x1083f, 0x10857, 0x108a7, 0x108e0, 0x108f4, 0x108fb, 0x1091f, 0x1093f, 0x10980, 0x109bc, 0x109d2, + 0x10a05, 0x10a0c, 0x10a15, 0x10a19, 0x10a38, 0x10a3f, 0x10a50, 0x10a60, 0x10ac0, 0x10aeb, 0x10b00, 0x10b39, + 0x10b58, 0x10b78, 0x10b99, 0x10ba9, 0x10c00, 0x10c80, 0x10cc0, 0x10cfa, 0x10d30, 0x10e60, 0x10e80, 0x10eab, + 0x10eb0, 0x10efd, 0x10f30, 0x10f70, 0x10fb0, 0x10fe0, 0x11000, 0x11052, 0x1107f, 0x110be, 0x110d0, 0x110f0, + 0x11100, 0x11136, 0x11150, 0x11180, 0x111e1, 0x11200, 0x11213, 0x11280, 0x11288, 0x1128a, 0x1128f, 0x1129f, + 0x112b0, 0x112f0, 0x11300, 0x11305, 0x1130f, 0x11313, 0x1132a, 0x11332, 0x11335, 0x1133b, 0x11347, 0x1134b, + 0x11350, 0x11357, 0x1135d, 0x11366, 0x11370, 0x11400, 0x1145d, 0x11480, 0x114d0, 0x11580, 0x115b8, 0x11600, + 0x11650, 0x11660, 0x11680, 0x116c0, 0x11700, 0x1171d, 0x11730, 0x11800, 0x118a0, 0x118ff, 0x11909, 0x1190c, + 0x11915, 0x11918, 0x11937, 0x1193b, 0x11950, 0x119a0, 0x119aa, 0x119da, 0x11a00, 0x11a50, 0x11ab0, 0x11b00, + 0x11c00, 0x11c0a, 0x11c38, 0x11c50, 0x11c70, 0x11c92, 0x11ca9, 0x11d00, 0x11d08, 0x11d0b, 0x11d3a, 0x11d3c, + 0x11d3f, 0x11d50, 0x11d60, 0x11d67, 0x11d6a, 0x11d90, 0x11d93, 0x11da0, 0x11ee0, 0x11f00, 0x11f12, 0x11f3e, + 0x11fb0, 0x11fc0, 0x11fff, 0x12400, 0x12470, 0x12480, 0x12f90, 0x13000, 0x13440, 0x14400, 0x16800, 0x16a40, + 0x16a60, 0x16a6e, 0x16ac0, 0x16ad0, 0x16af0, 0x16b00, 0x16b50, 0x16b5b, 0x16b63, 0x16b7d, 0x16e40, 0x16f00, + 0x16f4f, 0x16f8f, 0x16fe0, 0x16ff0, 0x17000, 0x18800, 0x18d00, 0x1aff0, 0x1aff5, 0x1affd, 0x1b000, 0x1b132, + 0x1b150, 0x1b155, 0x1b164, 0x1b170, 0x1bc00, 0x1bc70, 0x1bc80, 0x1bc90, 0x1bc9c, 0x1cf00, 0x1cf30, 0x1cf50, + 0x1d000, 0x1d100, 0x1d129, 0x1d17b, 0x1d200, 0x1d2c0, 0x1d2e0, 0x1d300, 0x1d360, 0x1d400, 0x1d456, 0x1d49e, + 0x1d4a2, 0x1d4a5, 0x1d4a9, 0x1d4ae, 0x1d4bb, 0x1d4bd, 0x1d4c5, 0x1d507, 0x1d50d, 0x1d516, 0x1d51e, 0x1d53b, + 0x1d540, 0x1d546, 0x1d54a, 0x1d552, 0x1d6a8, 0x1d7ce, 0x1da9b, 0x1daa1, 0x1df00, 0x1df25, 0x1e000, 0x1e008, + 0x1e01b, 0x1e023, 0x1e026, 0x1e030, 0x1e08f, 0x1e100, 0x1e130, 0x1e140, 0x1e14e, 0x1e290, 0x1e2c0, 0x1e2ff, + 0x1e4d0, 0x1e7e0, 0x1e7e8, 0x1e7ed, 0x1e7f0, 0x1e800, 0x1e8c7, 0x1e900, 0x1e950, 0x1e95e, 0x1ec71, 0x1ed01, + 0x1ee00, 0x1ee05, 0x1ee21, 0x1ee24, 0x1ee27, 0x1ee29, 0x1ee34, 0x1ee39, 0x1ee3b, 0x1ee42, 0x1ee47, 0x1ee49, + 0x1ee4b, 0x1ee4d, 0x1ee51, 0x1ee54, 0x1ee57, 0x1ee59, 0x1ee5b, 0x1ee5d, 0x1ee5f, 0x1ee61, 0x1ee64, 0x1ee67, + 0x1ee6c, 0x1ee74, 0x1ee79, 0x1ee7e, 0x1ee80, 0x1ee8b, 0x1eea1, 0x1eea5, 0x1eeab, 0x1eef0, 0x1f000, 0x1f030, + 0x1f0a0, 0x1f0b1, 0x1f0c1, 0x1f0d1, 0x1f100, 0x1f1e6, 0x1f210, 0x1f240, 0x1f250, 0x1f260, 0x1f300, 0x1f6dc, + 0x1f6f0, 0x1f700, 0x1f77b, 0x1f7e0, 0x1f7f0, 0x1f800, 0x1f810, 0x1f850, 0x1f860, 0x1f890, 0x1f8b0, 0x1f900, + 0x1fa60, 0x1fa70, 0x1fa80, 0x1fa90, 0x1fabf, 0x1face, 0x1fae0, 0x1faf0, 0x1fb00, 0x1fb94, 0x1fbf0, 0x20000, + 0x2a700, 0x2b740, 0x2b820, 0x2ceb0, 0x2f800, 0x30000, 0x31350, 0xe0100}, + {0x5f, 0xc, 0x2ca, 0x6, 0x7, 0x1, 0x14, 0x18d, 0x26, 0x32, 0x3, 0x37, 0x1b, 0x6, 0x16, 0xc0, 0x30, 0x3b, 0x65, 0x3b, + 0x31, 0xf, 0x1c, 0x1, 0xb, 0x1f, 0x4a, 0xa1, 0x8, 0x2, 0x16, 0x7, 0x1, 0x4, 0x9, 0x2, 0x4, 0x1, 0x2, 0x5, 0x19, + 0x3, 0x6, 0x2, 0x16, 0x7, 0x2, 0x2, 0x2, 0x1, 0x5, 0x2, 0x3, 0x1, 0x4, 0x1, 0x11, 0x3, 0x9, 0x3, 0x16, 0x7, 0x2, + 0x5, 0xa, 0x3, 0x3, 0x1, 0x4, 0xc, 0x7, 0x3, 0x8, 0x2, 0x16, 0x7, 0x2, 0x5, 0x9, 0x2, 0x3, 0x3, 0x2, 0x5, 0x12, + 0x2, 0x6, 0x3, 0x4, 0x2, 0x1, 0x2, 0x2, 0x3, 0xc, 0x5, 0x3, 0x4, 0x1, 0x1, 0x15, 0xd, 0x3, 0x17, 0x10, 0x9, 0x3, + 0x4, 0x2, 0x3, 0x1, 0x4, 0xa, 0x16, 0x3, 0x17, 0xa, 0x5, 0x9, 0x3, 0x4, 0x2, 0x2, 0x4, 0xa, 0x3, 0xd, 0x3, 0x33, + 0x3, 0x6, 0x10, 0x1a, 0x3, 0x12, 0x18, 0x9, 0x1, 0x7, 0x1, 0x6, 0x1, 0x8, 0xa, 0x3, 0x3a, 0x1d, 0x2, 0x1, 0x5, + 0x18, 0x1, 0x17, 0x5, 0x1, 0x7, 0xa, 0x4, 0x48, 0x24, 0x27, 0x24, 0xf, 0xd, 0xc6, 0x1, 0x1, 0x179, 0x4, 0x7, + 0x1, 0x4, 0x29, 0x4, 0x21, 0x4, 0x7, 0x1, 0x4, 0xf, 0x39, 0x4, 0x43, 0x20, 0x1a, 0x56, 0x6, 0x280, 0x1c, 0x59, + 0x16, 0x18, 0x14, 0xd, 0x3, 0x2, 0x5e, 0xa, 0xa, 0xe, 0xb, 0x59, 0x2b, 0x46, 0x1f, 0xc, 0xc, 0x1, 0x2a, 0x5, + 0x2c, 0x1a, 0xb, 0x3e, 0x41, 0x1d, 0xb, 0xa, 0xe, 0x1f, 0x4d, 0x2f, 0x74, 0x3c, 0xf, 0x3c, 0x2b, 0xb, 0x2b, + 0x216, 0x6, 0x26, 0x6, 0x8, 0x1, 0x1, 0x1, 0x1f, 0x35, 0xf, 0xe, 0x6, 0x13, 0x3, 0x9, 0x18, 0x2f, 0x2, 0x1b, + 0xd, 0x21, 0x21, 0x8c, 0x297, 0xb, 0x714, 0x20, 0x15d, 0x2d, 0x1, 0x1, 0x38, 0x2, 0x18, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7e, 0x1a, 0x59, 0xd6, 0xc, 0x3f, 0x56, 0x67, 0x2b, 0x5e, 0x54, 0x2f, 0x726d, 0x37, 0x15c, 0xb8, + 0xcb, 0x2, 0x1, 0x5, 0x3b, 0xa, 0x38, 0x46, 0xc, 0x74, 0x1e, 0x4e, 0xb, 0x21, 0x37, 0xe, 0xa, 0x67, 0x1c, 0x6, + 0x6, 0x6, 0x7, 0x7, 0x3c, 0x7e, 0xa, 0x2ba4, 0x17, 0x31, 0x16e, 0x6a, 0x7, 0x5, 0x1a, 0x5, 0x1, 0x2, 0x2, 0x7d, + 0x1bd, 0x36, 0x1, 0x2a, 0x33, 0x13, 0x4, 0x5, 0x87, 0xbe, 0x6, 0x6, 0x6, 0x3, 0x7, 0x7, 0x2, 0xc, 0x1a, 0x13, + 0x2, 0xf, 0xe, 0x7b, 0x3, 0x2d, 0x58, 0xd, 0x1, 0x2e, 0x1d, 0x31, 0x1c, 0x24, 0x1e, 0x2b, 0x1e, 0x25, 0xe, 0x9e, + 0xa, 0x24, 0x24, 0x28, 0x34, 0xc, 0xf, 0x7, 0x2, 0xb, 0xf, 0x7, 0x2, 0x137, 0x16, 0x8, 0x6, 0x2a, 0x9, 0x6, 0x1, + 0x2c, 0x2, 0x1, 0x17, 0x48, 0x9, 0x13, 0x2, 0x21, 0x1b, 0x1, 0x38, 0x14, 0x32, 0x2, 0x8, 0x3, 0x1d, 0x3, 0xa, + 0x9, 0x40, 0x27, 0xc, 0x36, 0x1d, 0x1b, 0x1a, 0x4, 0x7, 0x49, 0x33, 0x33, 0x2e, 0xa, 0x1f, 0x2a, 0x3, 0x2, 0x2b, + 0x2a, 0x1a, 0x1c, 0x17, 0x4e, 0x24, 0x3e, 0x5, 0x19, 0xa, 0x35, 0x12, 0x27, 0x60, 0x14, 0x12, 0x2f, 0x7, 0x1, + 0x4, 0xf, 0xb, 0x3b, 0xa, 0x4, 0x8, 0x2, 0x16, 0x7, 0x2, 0x5, 0xa, 0x2, 0x3, 0x1, 0x1, 0x7, 0x7, 0x5, 0x5c, 0x5, + 0x48, 0xa, 0x36, 0x26, 0x45, 0xa, 0xd, 0x3a, 0xa, 0x1b, 0xf, 0x17, 0x3c, 0x53, 0x8, 0x1, 0x8, 0x2, 0x1e, 0x2, + 0xc, 0xa, 0x8, 0x2e, 0xb, 0x48, 0x53, 0x49, 0xa, 0x9, 0x2d, 0xe, 0x1d, 0x20, 0x16, 0xe, 0x7, 0x2, 0x2c, 0x1, + 0x2, 0x9, 0xa, 0x6, 0x2, 0x25, 0x2, 0x6, 0xa, 0x19, 0x11, 0x29, 0x1c, 0x1, 0x32, 0x39b, 0x6f, 0x5, 0xc4, 0x63, + 0x430, 0x16, 0x247, 0x239, 0x1f, 0xa, 0x51, 0xa, 0x1e, 0x6, 0x46, 0xa, 0x7, 0x15, 0x13, 0x5b, 0x4b, 0x39, 0x11, + 0x5, 0x2, 0x17f8, 0x4d6, 0x9, 0x4, 0x7, 0x2, 0x123, 0x1, 0x3, 0x1, 0x4, 0x18c, 0x6b, 0xd, 0x9, 0xa, 0x4, 0x2e, + 0x17, 0x74, 0xf6, 0x27, 0x4a, 0x70, 0x46, 0x14, 0x14, 0x57, 0x19, 0x55, 0x47, 0x2, 0x1, 0x2, 0x4, 0xc, 0x1, 0x7, + 0x41, 0x4, 0x8, 0x7, 0x1c, 0x4, 0x5, 0x1, 0x7, 0x154, 0x124, 0x2be, 0x5, 0xf, 0x1f, 0x6, 0x7, 0x11, 0x7, 0x2, + 0x5, 0x3e, 0x1, 0x2d, 0xe, 0xa, 0x2, 0x1f, 0x3a, 0x1, 0x2a, 0x7, 0x4, 0x2, 0xf, 0xc5, 0x10, 0x4c, 0xa, 0x2, + 0x44, 0x3d, 0x4, 0x1b, 0x2, 0x1, 0x1, 0xa, 0x4, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, + 0x1, 0x2, 0x1, 0x4, 0x7, 0x4, 0x4, 0x1, 0xa, 0x11, 0x3, 0x5, 0x11, 0x2, 0x2c, 0x64, 0xf, 0xf, 0xf, 0x25, 0xae, + 0x1d, 0x2c, 0x9, 0x2, 0x6, 0x3d8, 0x11, 0xd, 0x77, 0x5f, 0xc, 0x1, 0xc, 0x38, 0xa, 0x28, 0x1e, 0x2, 0x154, 0xe, + 0xd, 0x9, 0x2e, 0x7, 0xe, 0x9, 0x9, 0x93, 0x37, 0xa, 0xa6e0, 0x103a, 0xde, 0x1682, 0x1d31, 0x21e, 0x134b, + 0x1060, 0xf0}}; + +// DerivedCoreProperties-15.0.0.txt +// Date: 2022-08-05, 22:17:05 GMT +enum class _Grapheme_Extend_property_values : uint8_t { _Grapheme_Extend_value, _No_value = 255 }; + +// DerivedCoreProperties-15.0.0.txt +// Date: 2022-08-05, 22:17:05 GMT +inline constexpr _Unicode_property_data<_Grapheme_Extend_property_values, 363, true> _Grapheme_Extend_property_data{ + {0x300, 0x483, 0x591, 0x5bf, 0x5c1, 0x5c4, 0x5c7, 0x610, 0x64b, 0x670, 0x6d6, 0x6df, 0x6e7, 0x6ea, 0x711, 0x730, + 0x7a6, 0x7eb, 0x7fd, 0x816, 0x81b, 0x825, 0x829, 0x859, 0x898, 0x8ca, 0x8e3, 0x93a, 0x93c, 0x941, 0x94d, 0x951, + 0x962, 0x981, 0x9bc, 0x9be, 0x9c1, 0x9cd, 0x9d7, 0x9e2, 0x9fe, 0xa01, 0xa3c, 0xa41, 0xa47, 0xa4b, 0xa51, 0xa70, + 0xa75, 0xa81, 0xabc, 0xac1, 0xac7, 0xacd, 0xae2, 0xafa, 0xb01, 0xb3c, 0xb3e, 0xb41, 0xb4d, 0xb55, 0xb62, 0xb82, + 0xbbe, 0xbc0, 0xbcd, 0xbd7, 0xc00, 0xc04, 0xc3c, 0xc3e, 0xc46, 0xc4a, 0xc55, 0xc62, 0xc81, 0xcbc, 0xcbf, 0xcc2, + 0xcc6, 0xccc, 0xcd5, 0xce2, 0xd00, 0xd3b, 0xd3e, 0xd41, 0xd4d, 0xd57, 0xd62, 0xd81, 0xdca, 0xdcf, 0xdd2, 0xdd6, + 0xddf, 0xe31, 0xe34, 0xe47, 0xeb1, 0xeb4, 0xec8, 0xf18, 0xf35, 0xf37, 0xf39, 0xf71, 0xf80, 0xf86, 0xf8d, 0xf99, + 0xfc6, 0x102d, 0x1032, 0x1039, 0x103d, 0x1058, 0x105e, 0x1071, 0x1082, 0x1085, 0x108d, 0x109d, 0x135d, 0x1712, + 0x1732, 0x1752, 0x1772, 0x17b4, 0x17b7, 0x17c6, 0x17c9, 0x17dd, 0x180b, 0x180f, 0x1885, 0x18a9, 0x1920, 0x1927, + 0x1932, 0x1939, 0x1a17, 0x1a1b, 0x1a56, 0x1a58, 0x1a60, 0x1a62, 0x1a65, 0x1a73, 0x1a7f, 0x1ab0, 0x1b00, 0x1b34, + 0x1b3c, 0x1b42, 0x1b6b, 0x1b80, 0x1ba2, 0x1ba8, 0x1bab, 0x1be6, 0x1be8, 0x1bed, 0x1bef, 0x1c2c, 0x1c36, 0x1cd0, + 0x1cd4, 0x1ce2, 0x1ced, 0x1cf4, 0x1cf8, 0x1dc0, 0x200c, 0x20d0, 0x2cef, 0x2d7f, 0x2de0, 0x302a, 0x3099, 0xa66f, + 0xa674, 0xa69e, 0xa6f0, 0xa802, 0xa806, 0xa80b, 0xa825, 0xa82c, 0xa8c4, 0xa8e0, 0xa8ff, 0xa926, 0xa947, 0xa980, + 0xa9b3, 0xa9b6, 0xa9bc, 0xa9e5, 0xaa29, 0xaa31, 0xaa35, 0xaa43, 0xaa4c, 0xaa7c, 0xaab0, 0xaab2, 0xaab7, 0xaabe, + 0xaac1, 0xaaec, 0xaaf6, 0xabe5, 0xabe8, 0xabed, 0xfb1e, 0xfe00, 0xfe20, 0xff9e, 0x101fd, 0x102e0, 0x10376, + 0x10a01, 0x10a05, 0x10a0c, 0x10a38, 0x10a3f, 0x10ae5, 0x10d24, 0x10eab, 0x10efd, 0x10f46, 0x10f82, 0x11001, + 0x11038, 0x11070, 0x11073, 0x1107f, 0x110b3, 0x110b9, 0x110c2, 0x11100, 0x11127, 0x1112d, 0x11173, 0x11180, + 0x111b6, 0x111c9, 0x111cf, 0x1122f, 0x11234, 0x11236, 0x1123e, 0x11241, 0x112df, 0x112e3, 0x11300, 0x1133b, + 0x1133e, 0x11340, 0x11357, 0x11366, 0x11370, 0x11438, 0x11442, 0x11446, 0x1145e, 0x114b0, 0x114b3, 0x114ba, + 0x114bd, 0x114bf, 0x114c2, 0x115af, 0x115b2, 0x115bc, 0x115bf, 0x115dc, 0x11633, 0x1163d, 0x1163f, 0x116ab, + 0x116ad, 0x116b0, 0x116b7, 0x1171d, 0x11722, 0x11727, 0x1182f, 0x11839, 0x11930, 0x1193b, 0x1193e, 0x11943, + 0x119d4, 0x119da, 0x119e0, 0x11a01, 0x11a33, 0x11a3b, 0x11a47, 0x11a51, 0x11a59, 0x11a8a, 0x11a98, 0x11c30, + 0x11c38, 0x11c3f, 0x11c92, 0x11caa, 0x11cb2, 0x11cb5, 0x11d31, 0x11d3a, 0x11d3c, 0x11d3f, 0x11d47, 0x11d90, + 0x11d95, 0x11d97, 0x11ef3, 0x11f00, 0x11f36, 0x11f40, 0x11f42, 0x13440, 0x13447, 0x16af0, 0x16b30, 0x16f4f, + 0x16f8f, 0x16fe4, 0x1bc9d, 0x1cf00, 0x1cf30, 0x1d165, 0x1d167, 0x1d16e, 0x1d17b, 0x1d185, 0x1d1aa, 0x1d242, + 0x1da00, 0x1da3b, 0x1da75, 0x1da84, 0x1da9b, 0x1daa1, 0x1e000, 0x1e008, 0x1e01b, 0x1e023, 0x1e026, 0x1e08f, + 0x1e130, 0x1e2ae, 0x1e2ec, 0x1e4ec, 0x1e8d0, 0x1e944, 0xe0020, 0xe0100}, + {0x70, 0x7, 0x2d, 0x1, 0x2, 0x2, 0x1, 0xb, 0x15, 0x1, 0x7, 0x6, 0x2, 0x4, 0x1, 0x1b, 0xb, 0x9, 0x1, 0x4, 0x9, 0x3, + 0x5, 0x3, 0x8, 0x18, 0x20, 0x1, 0x1, 0x8, 0x1, 0x7, 0x2, 0x1, 0x1, 0x1, 0x4, 0x1, 0x1, 0x2, 0x1, 0x2, 0x1, 0x2, + 0x2, 0x3, 0x1, 0x2, 0x1, 0x2, 0x1, 0x5, 0x2, 0x1, 0x2, 0x6, 0x1, 0x1, 0x2, 0x4, 0x1, 0x3, 0x2, 0x1, 0x1, 0x1, + 0x1, 0x1, 0x1, 0x1, 0x1, 0x3, 0x3, 0x4, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, 0x2, 0x2, 0x1, 0x4, + 0x1, 0x1, 0x2, 0x1, 0x1, 0x1, 0x3, 0x1, 0x1, 0x1, 0x7, 0x8, 0x1, 0x9, 0x7, 0x2, 0x1, 0x1, 0x1, 0xe, 0x5, 0x2, + 0xb, 0x24, 0x1, 0x4, 0x6, 0x2, 0x2, 0x2, 0x3, 0x4, 0x1, 0x2, 0x1, 0x1, 0x3, 0x3, 0x2, 0x2, 0x2, 0x2, 0x7, 0x1, + 0xb, 0x1, 0x3, 0x1, 0x2, 0x1, 0x3, 0x2, 0x1, 0x3, 0x2, 0x1, 0x1, 0x7, 0x1, 0x1, 0x8, 0xa, 0x1, 0x1f, 0x4, 0x7, + 0x1, 0x1, 0x9, 0x2, 0x4, 0x2, 0x3, 0x1, 0x2, 0x1, 0x3, 0x8, 0x2, 0x3, 0xd, 0x7, 0x1, 0x1, 0x2, 0x40, 0x1, 0x21, + 0x3, 0x1, 0x20, 0x6, 0x2, 0x4, 0xa, 0x2, 0x2, 0x1, 0x1, 0x1, 0x2, 0x1, 0x2, 0x12, 0x1, 0x8, 0xb, 0x3, 0x1, 0x4, + 0x2, 0x1, 0x6, 0x2, 0x2, 0x1, 0x1, 0x1, 0x1, 0x3, 0x2, 0x2, 0x1, 0x2, 0x1, 0x1, 0x1, 0x1, 0x1, 0x10, 0x10, 0x2, + 0x1, 0x1, 0x5, 0x3, 0x2, 0x4, 0x3, 0x1, 0x2, 0x4, 0x2, 0x3, 0xb, 0x4, 0x1, 0xf, 0x1, 0x2, 0x3, 0x4, 0x2, 0x1, + 0x3, 0x5, 0x8, 0x1, 0x2, 0x9, 0x4, 0x1, 0x3, 0x1, 0x2, 0x1, 0x1, 0x1, 0x8, 0x2, 0x2, 0x1, 0x1, 0x1, 0x7, 0x5, + 0x8, 0x3, 0x1, 0x1, 0x1, 0x6, 0x1, 0x1, 0x2, 0x2, 0x1, 0x4, 0x2, 0x2, 0x2, 0x8, 0x1, 0x2, 0x1, 0x1, 0x6, 0x1, + 0x3, 0x4, 0x5, 0x9, 0x2, 0x1, 0x2, 0x1, 0x1, 0x4, 0x2, 0x1, 0xa, 0x6, 0x4, 0x1, 0x6, 0x3, 0xd, 0x2, 0x7, 0x6, + 0x1, 0x16, 0x7, 0x2, 0x2, 0x6, 0x1, 0x2, 0x7, 0x1, 0x2, 0x1, 0x1, 0x2, 0x2, 0x5, 0x1, 0x1, 0x1, 0xf, 0x5, 0x7, + 0x1, 0x4, 0x1, 0x2, 0x2e, 0x17, 0x1, 0x3, 0x5, 0x8, 0x7, 0x4, 0x3, 0x37, 0x32, 0x1, 0x1, 0x5, 0xf, 0x7, 0x11, + 0x7, 0x2, 0x5, 0x1, 0x7, 0x1, 0x4, 0x4, 0x7, 0x7, 0x60, 0xf0}}; + _STD_END #pragma pop_macro("new") diff --git a/stl/inc/chrono b/stl/inc/chrono index 088cba4c21d..ade183d9577 100644 --- a/stl/inc/chrono +++ b/stl/inc/chrono @@ -4685,17 +4685,6 @@ namespace chrono { #ifdef __cpp_lib_concepts // [time.format] -template -_NODISCARD constexpr const _CharT* _Choose_literal(const char* const _Str, const wchar_t* const _WStr) noexcept { - if constexpr (is_same_v<_CharT, char>) { - return _Str; - } else { - return _WStr; - } -} - -#define _STATICALLY_WIDEN(_CharT, _Literal) (_Choose_literal<_CharT>(_Literal, L##_Literal)) - // clang-format off template concept _Chrono_parse_spec_callbacks = _Parse_align_callbacks<_Ty, _CharT> @@ -6031,8 +6020,6 @@ inline namespace literals { } // namespace literals #endif // _HAS_CXX20 -#undef _STATICALLY_WIDEN - _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS diff --git a/stl/inc/format b/stl/inc/format index dd50c3a524f..455ac09ef71 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -44,6 +44,7 @@ _EMIT_STL_WARNING(STL4038, "The contents of are available only with C++ #else // ^^^ !defined(__cpp_lib_concepts) / defined(__cpp_lib_concepts) vvv #include <__msvc_format_ucd_tables.hpp> +#include <__msvc_print.hpp> #include #include #include @@ -68,6 +69,19 @@ extern "C" _NODISCARD __std_win_error __stdcall __std_get_cvt(__std_code_page _C _STD_BEGIN +template +_NODISCARD constexpr const _CharT* _Choose_literal(const char* const _Str, const wchar_t* const _WStr) noexcept { + if constexpr (is_same_v<_CharT, char>) { + return _Str; + } else { + return _WStr; + } +} + +// _STATICALLY_WIDEN is used by since C++20 and by since C++23. +// It's defined here, so that both headers can use this definition. +#define _STATICALLY_WIDEN(_CharT, _Literal) (_Choose_literal<_CharT>(_Literal, L##_Literal)) + _EXPORT_STD template class vector; @@ -169,13 +183,15 @@ concept _Parse_spec_callbacks = _Parse_align_callbacks<_Ty, _CharT> // clang-format on template -struct _Decode_utf_result { +struct _Decode_result { const _CharT* _Next_ptr; bool _Is_unicode_scalar_value; // Also _Is_usv below, see https://www.unicode.org/glossary/#unicode_scalar_value + // _Is_unicode_scalar_value is also used for non-Unicode encodings, to indicate that the input can be converted to + // Unicode. }; // _Decode_utf decodes UTF-8 or UTF-16 encoded unsigned char or wchar_t strings respectively -_NODISCARD constexpr _Decode_utf_result _Decode_utf( +_NODISCARD constexpr _Decode_result _Decode_utf( const wchar_t* _First, const wchar_t* _Last, char32_t& _Val) noexcept { _STL_INTERNAL_CHECK(_First < _Last); _Val = static_cast(*_First); @@ -207,8 +223,7 @@ _NODISCARD constexpr _Decode_utf_result _Decode_utf( return {_First + 1, true}; } -_NODISCARD constexpr _Decode_utf_result _Decode_utf( - const char* _First, const char* _Last, char32_t& _Val) noexcept { +_NODISCARD constexpr _Decode_result _Decode_utf(const char* _First, const char* _Last, char32_t& _Val) noexcept { _STL_INTERNAL_CHECK(_First < _Last); // Decode a UTF-8 encoded codepoint starting at _First and not exceeding _Last, returning // one past the end of the character decoded. Any invalid codepoints will result in @@ -309,7 +324,7 @@ _NODISCARD constexpr _Decode_utf_result _Decode_utf( return {_First + _Num_bytes, true}; } -_NODISCARD constexpr _Decode_utf_result _Decode_utf( +_NODISCARD constexpr _Decode_result _Decode_utf( const char32_t* _First, const char32_t* _Last, char32_t& _Val) noexcept { _STL_INTERNAL_CHECK(_First < _Last); (void) _Last; @@ -954,6 +969,7 @@ public: return _First; } } + _NODISCARD constexpr int _Units_in_next_character( const char* const _First, const char* const _Last) const noexcept { // Returns the number of code units that compose the first encoded character in @@ -979,6 +995,38 @@ public: } } } + +#if _HAS_CXX23 + _NODISCARD _Decode_result _Decode(const char* const _First, const char* const _Last, char32_t& _Val) const { + _STL_INTERNAL_CHECK(_First < _Last); + + if constexpr (_Is_ordinary_literal_encoding_utf8()) { + return _Decode_utf(_First, _Last, _Val); + } else if constexpr (_Is_execution_charset_self_synchronizing()) { + wchar_t _Wide; + const auto _Res = + __std_fs_convert_narrow_to_wide(__std_code_page{_MSVC_EXECUTION_CHARACTER_SET}, _First, 1, &_Wide, 1); + _Val = _Wide; + return {_First + 1, _Res._Len != 0}; + } else { + if (*_First == '\0') { + _Val = U'\0'; + return {_First + 1, true}; + } + + wchar_t _Wide; + mbstate_t _St{}; + const auto _Len = static_cast(_Last - _First); + const int _Result = _Mbrtowc(&_Wide, _First, _Len, &_St, &this->_Cvt); + if (_Result < 0) { + return {_First + 1, false}; + } else { + _Val = _Wide; + return {_First + _Result, true}; + } + } + } +#endif // _HAS_CXX23 }; template @@ -988,6 +1036,7 @@ public: const wchar_t* const _First, const wchar_t* const _Last, const wchar_t _Val) const { return _STD _Find_unchecked(_First, _Last, _Val); } + _NODISCARD constexpr int _Units_in_next_character( const wchar_t* _First, const wchar_t* const _Last) const noexcept { char32_t _Ch; @@ -995,6 +1044,13 @@ public: _STL_INTERNAL_CHECK(_Next - _First <= 2); return _Is_usv ? static_cast(_Next - _First) : -1; } + +#if _HAS_CXX23 + _NODISCARD constexpr _Decode_result _Decode( + const wchar_t* const _First, const wchar_t* const _Last, char32_t& _Val) const noexcept { + return _Decode_utf(_First, _Last, _Val); + } +#endif // _HAS_CXX23 }; template @@ -1620,11 +1676,26 @@ public: _Throw_format_error("Invalid type specification."); } const char _Narrow_type = static_cast(_Type); - enum class _Presentation_type_category { _Default, _Integer, _Floating, _String, _Pointer, _Char }; + enum class _Presentation_type_category { + _Default, + _Integer, + _Floating, + _String, + _Pointer, + _Char, +#if _HAS_CXX23 + _Escape, +#endif // _HAS_CXX23 + }; auto _Cat = _Presentation_type_category::_Default; switch (_Narrow_type) { case '\0': break; +#if _HAS_CXX23 + case '?': + _Cat = _Presentation_type_category::_Escape; + break; +#endif // _HAS_CXX23 case 's': _Cat = _Presentation_type_category::_String; break; @@ -1674,7 +1745,11 @@ public: _Cat = _Presentation_type_category::_Char; } - if (_Cat != _Presentation_type_category::_Char && _Cat != _Presentation_type_category::_Integer) { + if (_Cat != _Presentation_type_category::_Char && _Cat != _Presentation_type_category::_Integer +#if _HAS_CXX23 + && _Cat != _Presentation_type_category::_Escape +#endif // _HAS_CXX23 + ) { if constexpr (is_same_v<_CharT, char>) { _Throw_format_error("Invalid presentation type for char"); } else { @@ -1711,7 +1786,11 @@ public: _Cat = _Presentation_type_category::_String; } - if (_Cat != _Presentation_type_category::_String) { + if (_Cat != _Presentation_type_category::_String +#if _HAS_CXX23 + && _Cat != _Presentation_type_category::_Escape +#endif // _HAS_CXX23 + ) { _Throw_format_error("Invalid presentation type for string"); } break; @@ -2269,1020 +2348,1172 @@ using _Fmt_wit = back_insert_iterator<_Fmt_buffer>; _EXPORT_STD using format_context = basic_format_context<_Fmt_it, char>; _EXPORT_STD using wformat_context = basic_format_context<_Fmt_wit, wchar_t>; -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) { - _STL_INTERNAL_CHECK(false); - return _Out; -} +#if _HAS_CXX23 +inline namespace __p2286 { +#endif // _HAS_CXX23 + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate) { + _STL_INTERNAL_CHECK(false); + return _Out; + } -// This size is derived from the maximum length of an arithmetic type. The contenders for widest are: -// (a) long long has a max length of 20 characters: LLONG_MIN is "-9223372036854775807". -// (b) unsigned long long has a max length of 20 characters: ULLONG_MAX is "18446744073709551615". -// (c) double has a max length of 24 characters: -DBL_MAX is "-1.7976931348623158e+308". -// That's 17 characters for numeric_limits::max_digits10, -// plus 1 character for the sign, -// plus 1 character for the decimal point, -// plus 1 character for 'e', -// plus 1 character for the exponent's sign, -// plus 3 characters for the max exponent. -inline constexpr size_t _Format_min_buffer_length = 24; + // This size is derived from the maximum length of an arithmetic type. The contenders for widest are: + // (a) long long has a max length of 20 characters: LLONG_MIN is "-9223372036854775807". + // (b) unsigned long long has a max length of 20 characters: ULLONG_MAX is "18446744073709551615". + // (c) double has a max length of 24 characters: -DBL_MAX is "-1.7976931348623158e+308". + // That's 17 characters for numeric_limits::max_digits10, + // plus 1 character for the sign, + // plus 1 character for the decimal point, + // plus 1 character for 'e', + // plus 1 character for the exponent's sign, + // plus 3 characters for the max exponent. + inline constexpr size_t _Format_min_buffer_length = 24; -template - requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _Arithmetic _Value); + template + requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _Arithmetic _Value); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _CharT _Value); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, _CharT _Value); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* _Value); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* _Value); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, basic_string_view<_CharT> _Value); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, basic_string_view<_CharT> _Value); -template -_NODISCARD _OutputIt _Widen_and_copy(const char* _First, const char* const _Last, _OutputIt _Out) { - for (; _First != _Last; ++_First, (void) ++_Out) { - *_Out = static_cast<_CharT>(*_First); + template + _NODISCARD _OutputIt _Widen_and_copy(const char* _First, const char* const _Last, _OutputIt _Out) { + for (; _First != _Last; ++_First, (void) ++_Out) { + *_Out = static_cast<_CharT>(*_First); + } + + return _Out; } - return _Out; -} + template + requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _Arithmetic _Value) { + // TRANSITION, Reusable buffer + char _Buffer[_Format_min_buffer_length]; + char* _End = _Buffer; -template - requires (is_arithmetic_v<_Arithmetic> && !_CharT_or_bool<_Arithmetic, _CharT>) -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _Arithmetic _Value) { - // TRANSITION, Reusable buffer - char _Buffer[_Format_min_buffer_length]; - char* _End = _Buffer; + if constexpr (is_floating_point_v<_Arithmetic>) { + if ((_STD isnan)(_Value)) { + if ((_STD signbit)(_Value)) { + *_End++ = '-'; + } - if constexpr (is_floating_point_v<_Arithmetic>) { - if ((_STD isnan)(_Value)) { - if ((_STD signbit)(_Value)) { - *_End++ = '-'; + _CSTD memcpy(_End, "nan", 3); + _End += 3; } + } - _CSTD memcpy(_End, "nan", 3); - _End += 3; + if (_End == _Buffer) { + const to_chars_result _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value); + _STL_ASSERT(_Result.ec == errc{}, "to_chars failed"); + _End = _Result.ptr; } + + return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); } - if (_End == _Buffer) { - const to_chars_result _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value); - _STL_ASSERT(_Result.ec == errc{}, "to_chars failed"); - _End = _Result.ptr; + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const bool _Value) { + if constexpr (is_same_v<_CharT, wchar_t>) { + return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false"); + } else { + return _Fmt_write(_STD move(_Out), _Value ? "true" : "false"); + } } - return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); -} + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT _Value) { + *_Out++ = _Value; + return _Out; + } -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const bool _Value) { - if constexpr (is_same_v<_CharT, wchar_t>) { - return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false"); - } else { - return _Fmt_write(_STD move(_Out), _Value ? "true" : "false"); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* const _Value) { + // TRANSITION, Reusable buffer + char _Buffer[_Format_min_buffer_length]; + const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), reinterpret_cast(_Value), 16); + _STL_ASSERT(_Ec == errc{}, "to_chars failed"); + *_Out++ = '0'; + *_Out++ = 'x'; + return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); } -} -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT _Value) { - *_Out++ = _Value; - return _Out; -} + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value) { + if (!_Value) { + _Throw_format_error("String pointer is null."); + } -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const void* const _Value) { - // TRANSITION, Reusable buffer - char _Buffer[_Format_min_buffer_length]; - const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), reinterpret_cast(_Value), 16); - _STL_ASSERT(_Ec == errc{}, "to_chars failed"); - *_Out++ = '0'; - *_Out++ = 'x'; - return _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); -} + while (*_Value) { + *_Out++ = *_Value++; + } -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const _CharT* _Value) { - if (!_Value) { - _Throw_format_error("String pointer is null."); + return _Out; } - while (*_Value) { - *_Out++ = *_Value++; - } + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value) { + return _RANGES copy(_Value, _STD move(_Out)).out; + } + + template + _NODISCARD _OutputIt _Write_aligned( + _OutputIt _Out, const int _Width, const _Specs_type& _Specs, const _Fmt_align _Default_align, _Func&& _Fn) { + int _Fill_left = 0; + int _Fill_right = 0; + auto _Alignment = _Specs._Alignment; + + if (_Alignment == _Fmt_align::_None) { + _Alignment = _Default_align; + } + + if (_Width < _Specs._Width) { + switch (_Alignment) { + case _Fmt_align::_Left: + _Fill_right = _Specs._Width - _Width; + break; + case _Fmt_align::_Right: + _Fill_left = _Specs._Width - _Width; + break; + case _Fmt_align::_Center: + _Fill_left = (_Specs._Width - _Width) / 2; + _Fill_right = _Specs._Width - _Width - _Fill_left; + break; + case _Fmt_align::_None: + _STL_ASSERT(false, "Invalid alignment"); + break; + } + } - return _Out; -} + const basic_string_view _Fill_char{_Specs._Fill, _Specs._Fill_length}; + for (; _Fill_left > 0; --_Fill_left) { + _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; + } -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value) { - return _RANGES copy(_Value, _STD move(_Out)).out; -} + _Out = _Fn(_STD move(_Out)); -template -_NODISCARD _OutputIt _Write_aligned( - _OutputIt _Out, const int _Width, const _Specs_type& _Specs, const _Fmt_align _Default_align, _Func&& _Fn) { - int _Fill_left = 0; - int _Fill_right = 0; - auto _Alignment = _Specs._Alignment; + for (; _Fill_right > 0; --_Fill_right) { + _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; + } - if (_Alignment == _Fmt_align::_None) { - _Alignment = _Default_align; + return _Out; } - if (_Width < _Specs._Width) { - switch (_Alignment) { - case _Fmt_align::_Left: - _Fill_right = _Specs._Width - _Width; - break; - case _Fmt_align::_Right: - _Fill_left = _Specs._Width - _Width; - break; - case _Fmt_align::_Center: - _Fill_left = (_Specs._Width - _Width) / 2; - _Fill_right = _Specs._Width - _Width - _Fill_left; - break; - case _Fmt_align::_None: - _STL_ASSERT(false, "Invalid alignment"); - break; + template + _NODISCARD constexpr string_view _Get_integral_prefix(const char _Type, const _Integral _Value) noexcept { + switch (_Type) { + case 'b': + return "0b"sv; + case 'B': + return "0B"sv; + case 'x': + return "0x"sv; + case 'X': + return "0X"sv; + case 'o': + if (_Value != _Integral{0}) { + return "0"sv; + } + return {}; + default: + return {}; } } - const basic_string_view _Fill_char{_Specs._Fill, _Specs._Fill_length}; - for (; _Fill_left > 0; --_Fill_left) { - _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; + template + _NODISCARD _OutputIt _Write_sign(_OutputIt _Out, const _Fmt_sign _Sgn, const bool _Is_negative) { + if (_Is_negative) { + *_Out++ = '-'; + } else { + switch (_Sgn) { + case _Fmt_sign::_Plus: + *_Out++ = '+'; + break; + case _Fmt_sign::_Space: + *_Out++ = ' '; + break; + case _Fmt_sign::_None: + case _Fmt_sign::_Minus: + break; + } + } + return _Out; } - _Out = _Fn(_STD move(_Out)); - - for (; _Fill_right > 0; --_Fill_right) { - _Out = _RANGES copy(_Fill_char, _STD move(_Out)).out; + inline void _Buffer_to_uppercase(char* _First, const char* _Last) { + for (; _First != _Last; ++_First) { + *_First = static_cast(_CSTD toupper(*_First)); + } } - return _Out; -} + template + using _Make_standard_integer = conditional_t, make_signed_t<_Ty>, make_unsigned_t<_Ty>>; -template -_NODISCARD constexpr string_view _Get_integral_prefix(const char _Type, const _Integral _Value) noexcept { - switch (_Type) { - case 'b': - return "0b"sv; - case 'B': - return "0B"sv; - case 'x': - return "0x"sv; - case 'X': - return "0X"sv; - case 'o': - if (_Value != _Integral{0}) { - return "0"sv; - } - return {}; - default: - return {}; + template + _NODISCARD constexpr bool _In_bounds(const _Ty _Value) { + return _STD in_range<_Make_standard_integer<_CharT>>(static_cast<_Make_standard_integer<_Ty>>(_Value)); } -} -template -_NODISCARD _OutputIt _Write_sign(_OutputIt _Out, const _Fmt_sign _Sgn, const bool _Is_negative) { - if (_Is_negative) { - *_Out++ = '-'; - } else { - switch (_Sgn) { - case _Fmt_sign::_Plus: - *_Out++ = '+'; - break; - case _Fmt_sign::_Space: - *_Out++ = ' '; - break; - case _Fmt_sign::_None: - case _Fmt_sign::_Minus: - break; + _NODISCARD inline int _Count_separators(size_t _Digits, const string_view _Groups) { + if (_Groups.empty()) { + return 0; } - } - return _Out; -} -inline void _Buffer_to_uppercase(char* _First, const char* _Last) { - for (; _First != _Last; ++_First) { - *_First = static_cast(_CSTD toupper(*_First)); - } -} - -template -using _Make_standard_integer = conditional_t, make_signed_t<_Ty>, make_unsigned_t<_Ty>>; - -template -_NODISCARD constexpr bool _In_bounds(const _Ty _Value) { - return _STD in_range<_Make_standard_integer<_CharT>>(static_cast<_Make_standard_integer<_Ty>>(_Value)); -} + // Calculate the amount of separators that are going to be inserted based on the groupings of the locale. + int _Separators = 0; + auto _Group_it = _Groups.begin(); + while (_Digits > static_cast(*_Group_it)) { + _Digits -= static_cast(*_Group_it); + ++_Separators; + if (_Group_it + 1 != _Groups.end()) { + ++_Group_it; + } + } -_NODISCARD inline int _Count_separators(size_t _Digits, const string_view _Groups) { - if (_Groups.empty()) { - return 0; + return _Separators; } - // Calculate the amount of separators that are going to be inserted based on the groupings of the locale. - int _Separators = 0; - auto _Group_it = _Groups.begin(); - while (_Digits > static_cast(*_Group_it)) { - _Digits -= static_cast(*_Group_it); - ++_Separators; - if (_Group_it + 1 != _Groups.end()) { - ++_Group_it; + template + _NODISCARD _OutputIt _Write_separated_integer(const char* _First, const char* const _Last, + const string_view _Groups, const _CharT _Separator, int _Separators, _OutputIt _Out) { + auto _Group_it = _Groups.begin(); + auto _Repeats = 0; + auto _Grouped = 0; + + for (int _Section = 0; _Section < _Separators; ++_Section) { + _Grouped += *_Group_it; + if (_Group_it + 1 != _Groups.end()) { + ++_Group_it; + } else { + ++_Repeats; + } } - } + _Out = _Widen_and_copy<_CharT>(_First, _Last - _Grouped, _STD move(_Out)); + _First = _Last - _Grouped; - return _Separators; -} + for (; _Separators > 0; --_Separators) { + if (_Repeats > 0) { + --_Repeats; + } else { + --_Group_it; + } -template -_NODISCARD _OutputIt _Write_separated_integer(const char* _First, const char* const _Last, const string_view _Groups, - const _CharT _Separator, int _Separators, _OutputIt _Out) { - auto _Group_it = _Groups.begin(); - auto _Repeats = 0; - auto _Grouped = 0; - - for (int _Section = 0; _Section < _Separators; ++_Section) { - _Grouped += *_Group_it; - if (_Group_it + 1 != _Groups.end()) { - ++_Group_it; - } else { - ++_Repeats; + *_Out++ = _Separator; + _Out = _Widen_and_copy<_CharT>(_First, _First + *_Group_it, _STD move(_Out)); + _First += *_Group_it; } + _STL_INTERNAL_CHECK(_First == _Last); + return _Out; } - _Out = _Widen_and_copy<_CharT>(_First, _Last - _Grouped, _STD move(_Out)); - _First = _Last - _Grouped; - - for (; _Separators > 0; --_Separators) { - if (_Repeats > 0) { - --_Repeats; - } else { - --_Group_it; - } - *_Out++ = _Separator; - _Out = _Widen_and_copy<_CharT>(_First, _First + *_Group_it, _STD move(_Out)); - _First += *_Group_it; + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate, const _Basic_format_specs<_CharT>&, _Lazy_locale) { + _STL_INTERNAL_CHECK(false); + return _Out; } - _STL_INTERNAL_CHECK(_First == _Last); - return _Out; -} -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, monostate, const _Basic_format_specs<_CharT>&, _Lazy_locale) { - _STL_INTERNAL_CHECK(false); - return _Out; -} + template + _NODISCARD _OutputIt _Write_integral( + _OutputIt _Out, _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Write_integral( - _OutputIt _Out, _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); +#if _HAS_CXX23 + template + _NODISCARD _OutputIt _Write_escaped( + _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim); +#endif // _HAS_CXX23 -template - requires (!_CharT_or_bool<_Integral, _CharT>) -_NODISCARD _OutputIt - _Fmt_write(_OutputIt _Out, _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); + template + requires (!_CharT_or_bool<_Integral, _CharT>) + _NODISCARD _OutputIt + _Fmt_write(_OutputIt _Out, _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const void* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const void* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale); -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale); #pragma warning(push) #pragma warning(disable : 4296) // '<': expression is always false -template -_NODISCARD _OutputIt _Write_integral( - _OutputIt _Out, const _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type == 'c') { - if (!_In_bounds<_CharT>(_Value)) { - if constexpr (is_same_v<_CharT, char>) { - _Throw_format_error("integral cannot be stored in char"); - } else { - _Throw_format_error("integral cannot be stored in wchar_t"); + template + _NODISCARD _OutputIt _Write_integral( + _OutputIt _Out, const _Integral _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type == 'c') { + if (!_In_bounds<_CharT>(_Value)) { + if constexpr (is_same_v<_CharT, char>) { + _Throw_format_error("integral cannot be stored in char"); + } else { + _Throw_format_error("integral cannot be stored in wchar_t"); + } } + _Specs._Alt = false; + return _Fmt_write(_STD move(_Out), static_cast<_CharT>(_Value), _Specs, _Locale); } - _Specs._Alt = false; - return _Fmt_write(_STD move(_Out), static_cast<_CharT>(_Value), _Specs, _Locale); - } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); - if (_Specs._Sgn == _Fmt_sign::_None) { - _Specs._Sgn = _Fmt_sign::_Minus; - } + if (_Specs._Sgn == _Fmt_sign::_None) { + _Specs._Sgn = _Fmt_sign::_Minus; + } - int _Base = 10; - bool _To_upper = false; + int _Base = 10; + bool _To_upper = false; - switch (_Specs._Type) { - case 'B': - _To_upper = true; - [[fallthrough]]; - case 'b': - _Base = 2; - break; - case 'X': - _To_upper = true; - [[fallthrough]]; - case 'x': - _Base = 16; - break; - case 'o': - _Base = 8; - break; - } + switch (_Specs._Type) { + case 'B': + _To_upper = true; + [[fallthrough]]; + case 'b': + _Base = 2; + break; + case 'X': + _To_upper = true; + [[fallthrough]]; + case 'x': + _Base = 16; + break; + case 'o': + _Base = 8; + break; + } - // long long -1 representation in binary is 64 bits + sign - char _Buffer[65]; - const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Base); - _STL_ASSERT(_Ec == errc{}, "to_chars failed"); + // long long -1 representation in binary is 64 bits + sign + char _Buffer[65]; + const auto [_End, _Ec] = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Base); + _STL_ASSERT(_Ec == errc{}, "to_chars failed"); - auto _Buffer_start = _Buffer; - auto _Width = static_cast(_End - _Buffer_start); + auto _Buffer_start = _Buffer; + auto _Width = static_cast(_End - _Buffer_start); - if (_Value >= _Integral{0}) { - if (_Specs._Sgn != _Fmt_sign::_Minus) { - _Width += 1; + if (_Value >= _Integral{0}) { + if (_Specs._Sgn != _Fmt_sign::_Minus) { + _Width += 1; + } + } else { + // Remove the '-', it will be dealt with directly + _Buffer_start += 1; } - } else { - // Remove the '-', it will be dealt with directly - _Buffer_start += 1; - } - if (_To_upper) { - _Buffer_to_uppercase(_Buffer_start, _End); - } + if (_To_upper) { + _Buffer_to_uppercase(_Buffer_start, _End); + } - string_view _Prefix; - if (_Specs._Alt) { - _Prefix = _Get_integral_prefix(_Specs._Type, _Value); - _Width += static_cast(_Prefix.size()); - } + string_view _Prefix; + if (_Specs._Alt) { + _Prefix = _Get_integral_prefix(_Specs._Type, _Value); + _Width += static_cast(_Prefix.size()); + } - auto _Separators = 0; - string _Groups; - if (_Specs._Localized) { - _Groups = _STD use_facet>(_Locale._Get()).grouping(); - _Separators = _Count_separators(static_cast(_End - _Buffer_start), _Groups); - // TRANSITION, separators may be wider for wide chars - _Width += _Separators; - } + auto _Separators = 0; + string _Groups; + if (_Specs._Localized) { + _Groups = _STD use_facet>(_Locale._Get()).grouping(); + _Separators = _Count_separators(static_cast(_End - _Buffer_start), _Groups); + // TRANSITION, separators may be wider for wide chars + _Width += _Separators; + } + + const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None; + auto _Writer = [&, _End = _End](_OutputIt _Out) { + _Out = _Write_sign(_STD move(_Out), _Specs._Sgn, _Value < _Integral{0}); + _Out = _Widen_and_copy<_CharT>(_Prefix.data(), _Prefix.data() + _Prefix.size(), _STD move(_Out)); + if (_Write_leading_zeroes && _Width < _Specs._Width) { + _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); + } - const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None; - auto _Writer = [&, _End = _End](_OutputIt _Out) { - _Out = _Write_sign(_STD move(_Out), _Specs._Sgn, _Value < _Integral{0}); - _Out = _Widen_and_copy<_CharT>(_Prefix.data(), _Prefix.data() + _Prefix.size(), _STD move(_Out)); - if (_Write_leading_zeroes && _Width < _Specs._Width) { - _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); - } + if (_Separators > 0) { + return _Write_separated_integer(_Buffer_start, _End, _Groups, + _STD use_facet>(_Locale._Get()).thousands_sep(), // + _Separators, _STD move(_Out)); + } + return _Widen_and_copy<_CharT>(_Buffer_start, _End, _STD move(_Out)); + }; - if (_Separators > 0) { - return _Write_separated_integer(_Buffer_start, _End, _Groups, - _STD use_facet>(_Locale._Get()).thousands_sep(), // - _Separators, _STD move(_Out)); + if (_Write_leading_zeroes) { + return _Writer(_STD move(_Out)); } - return _Widen_and_copy<_CharT>(_Buffer_start, _End, _STD move(_Out)); - }; - if (_Write_leading_zeroes) { - return _Writer(_STD move(_Out)); + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); } - - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); -} #pragma warning(pop) -template - requires (!_CharT_or_bool<_Integral, _CharT>) -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); -} - -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type != '\0' && _Specs._Type != 's') { - return _Write_integral(_STD move(_Out), static_cast(_Value), _Specs, _Locale); + template + requires (!_CharT_or_bool<_Integral, _CharT>) + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _Integral _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const bool _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type != '\0' && _Specs._Type != 's') { + return _Write_integral(_STD move(_Out), static_cast(_Value), _Specs, _Locale); + } - if (_Specs._Localized) { - _Specs._Localized = false; - const auto& _Facet = _STD use_facet>(_Locale._Get()); - return _Fmt_write(_STD move(_Out), - _Value ? static_cast>(_Facet.truename()) - : static_cast>(_Facet.falsename()), - _Specs, _Locale); - } + _STL_INTERNAL_CHECK(_Specs._Precision == -1); - if constexpr (is_same_v<_CharT, wchar_t>) { - return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false", _Specs, _Locale); - } else { - return _Fmt_write(_STD move(_Out), _Value ? "true" : "false", _Specs, _Locale); - } -} + if (_Specs._Localized) { + _Specs._Localized = false; + const auto& _Facet = _STD use_facet>(_Locale._Get()); + return _Fmt_write(_STD move(_Out), + _Value ? static_cast>(_Facet.truename()) + : static_cast>(_Facet.falsename()), + _Specs, _Locale); + } -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { - if (_Specs._Type != '\0' && _Specs._Type != 'c') { - return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); + if constexpr (is_same_v<_CharT, wchar_t>) { + return _Fmt_write(_STD move(_Out), _Value ? L"true" : L"false", _Specs, _Locale); + } else { + return _Fmt_write(_STD move(_Out), _Value ? "true" : "false", _Specs, _Locale); + } } - _STL_INTERNAL_CHECK(_Specs._Precision == -1); + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT _Value, _Basic_format_specs<_CharT> _Specs, _Lazy_locale _Locale) { + if (_Specs._Type != '\0' && _Specs._Type != 'c' +#if _HAS_CXX23 + && _Specs._Type != '?' +#endif // _HAS_CXX23 + ) { + return _Write_integral(_STD move(_Out), _Value, _Specs, _Locale); + } + + _STL_INTERNAL_CHECK(_Specs._Precision == -1); - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, _Locale); -} +#if _HAS_CXX23 + if (_Specs._Type == '?') { + return _Write_escaped(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, '\''); + } +#endif // _HAS_CXX23 -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - auto _Sgn = _Specs._Sgn; - if (_Sgn == _Fmt_sign::_None) { - _Sgn = _Fmt_sign::_Minus; - } - - auto _To_upper = false; - auto _Format = chars_format::general; - auto _Exponent = '\0'; - auto _Precision = _Specs._Precision; - - switch (_Specs._Type) { - case 'A': - _To_upper = true; - [[fallthrough]]; - case 'a': - _Format = chars_format::hex; - _Exponent = 'p'; - break; - case 'E': - _To_upper = true; - [[fallthrough]]; - case 'e': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::scientific; - _Exponent = 'e'; - break; - case 'F': - _To_upper = true; - [[fallthrough]]; - case 'f': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::fixed; - break; - case 'G': - _To_upper = true; - [[fallthrough]]; - case 'g': - if (_Precision == -1) { - _Precision = 6; - } - _Format = chars_format::general; - _Exponent = 'e'; - break; + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{&_Value, 1}, _Specs, _Locale); } - // Consider the powers of 2 in decimal: - // 2^-1 = 0.5 - // 2^-2 = 0.25 - // 2^-3 = 0.125 - // 2^-4 = 0.0625 - // Each power of 2 consumes one more decimal digit. This is because: - // 2^-N * 5^-N = 10^-N - // 2^-N = 10^-N * 5^N - // Example: 2^-4 = 10^-4 * 5^4 = 0.0001 * 625 - // Therefore, the min subnormal 2^-1074 consumes 1074 digits of precision (digits after the decimal point). - // We need 3 more characters for a potential negative sign, the zero integer part, and the decimal point. - // Therefore, the precision can be clamped to 1074. - // The largest number consumes 309 digits before the decimal point. With a precision of 1074, and it being - // negative, it would use a buffer of size 1074+309+2. We need to add an additional number to the max - // exponent to accommodate the ones place. - constexpr auto _Max_precision = 1074; - constexpr auto _Buffer_size = _Max_precision + DBL_MAX_10_EXP + 3; - char _Buffer[_Buffer_size]; - to_chars_result _Result; - - auto _Extra_precision = 0; - if (_Precision > _Max_precision) { - _Extra_precision = _Precision - _Max_precision; - _Precision = _Max_precision; - } - - const auto _Is_negative = (_STD signbit)(_Value); - - if ((_STD isnan)(_Value)) { - _Result.ptr = _Buffer; - if (_Is_negative) { - ++_Result.ptr; // pretend to skip over a '-' that to_chars would put in _Buffer[0] + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _Float _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + auto _Sgn = _Specs._Sgn; + if (_Sgn == _Fmt_sign::_None) { + _Sgn = _Fmt_sign::_Minus; } - _CSTD memcpy(_Result.ptr, "nan", 3); - _Result.ptr += 3; - } else { - if (_Precision == -1) { - _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format); + auto _To_upper = false; + auto _Format = chars_format::general; + auto _Exponent = '\0'; + auto _Precision = _Specs._Precision; + + switch (_Specs._Type) { + case 'A': + _To_upper = true; + [[fallthrough]]; + case 'a': + _Format = chars_format::hex; + _Exponent = 'p'; + break; + case 'E': + _To_upper = true; + [[fallthrough]]; + case 'e': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::scientific; + _Exponent = 'e'; + break; + case 'F': + _To_upper = true; + [[fallthrough]]; + case 'f': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::fixed; + break; + case 'G': + _To_upper = true; + [[fallthrough]]; + case 'g': + if (_Precision == -1) { + _Precision = 6; + } + _Format = chars_format::general; + _Exponent = 'e'; + break; + } + + // Consider the powers of 2 in decimal: + // 2^-1 = 0.5 + // 2^-2 = 0.25 + // 2^-3 = 0.125 + // 2^-4 = 0.0625 + // Each power of 2 consumes one more decimal digit. This is because: + // 2^-N * 5^-N = 10^-N + // 2^-N = 10^-N * 5^N + // Example: 2^-4 = 10^-4 * 5^4 = 0.0001 * 625 + // Therefore, the min subnormal 2^-1074 consumes 1074 digits of precision (digits after the decimal point). + // We need 3 more characters for a potential negative sign, the zero integer part, and the decimal point. + // Therefore, the precision can be clamped to 1074. + // The largest number consumes 309 digits before the decimal point. With a precision of 1074, and it being + // negative, it would use a buffer of size 1074+309+2. We need to add an additional number to the max + // exponent to accommodate the ones place. + constexpr auto _Max_precision = 1074; + constexpr auto _Buffer_size = _Max_precision + DBL_MAX_10_EXP + 3; + char _Buffer[_Buffer_size]; + to_chars_result _Result; + + auto _Extra_precision = 0; + if (_Precision > _Max_precision) { + _Extra_precision = _Precision - _Max_precision; + _Precision = _Max_precision; + } + + const auto _Is_negative = (_STD signbit)(_Value); + + if ((_STD isnan)(_Value)) { + _Result.ptr = _Buffer; + if (_Is_negative) { + ++_Result.ptr; // pretend to skip over a '-' that to_chars would put in _Buffer[0] + } + + _CSTD memcpy(_Result.ptr, "nan", 3); + _Result.ptr += 3; } else { - _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format, _Precision); + if (_Precision == -1) { + _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format); + } else { + _Result = _STD to_chars(_Buffer, _STD end(_Buffer), _Value, _Format, _Precision); + } + + _STL_ASSERT(_Result.ec == errc{}, "to_chars failed"); } - _STL_ASSERT(_Result.ec == errc{}, "to_chars failed"); - } + auto _Buffer_start = _Buffer; + auto _Width = static_cast(_Result.ptr - _Buffer_start); - auto _Buffer_start = _Buffer; - auto _Width = static_cast(_Result.ptr - _Buffer_start); + if (_Is_negative) { + // Remove the '-', it will be dealt with directly + _Buffer_start += 1; + } else { + if (_Sgn != _Fmt_sign::_Minus) { + _Width += 1; + } + } - if (_Is_negative) { - // Remove the '-', it will be dealt with directly - _Buffer_start += 1; - } else { - if (_Sgn != _Fmt_sign::_Minus) { - _Width += 1; + if (_To_upper) { + _Buffer_to_uppercase(_Buffer_start, _Result.ptr); + _Exponent = static_cast(_CSTD toupper(_Exponent)); } - } - if (_To_upper) { - _Buffer_to_uppercase(_Buffer_start, _Result.ptr); - _Exponent = static_cast(_CSTD toupper(_Exponent)); - } + const auto _Is_finite = (_STD isfinite)(_Value); - const auto _Is_finite = (_STD isfinite)(_Value); + auto _Append_decimal = false; + auto _Exponent_start = _Result.ptr; + auto _Radix_point = _Result.ptr; + auto _Integral_end = _Result.ptr; + auto _Zeroes_to_append = 0; + auto _Separators = 0; + string _Groups; - auto _Append_decimal = false; - auto _Exponent_start = _Result.ptr; - auto _Radix_point = _Result.ptr; - auto _Integral_end = _Result.ptr; - auto _Zeroes_to_append = 0; - auto _Separators = 0; - string _Groups; + if (_Is_finite) { + if (_Specs._Alt || _Specs._Localized) { + for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { + if (*_It == '.') { + _Radix_point = _It; + } else if (*_It == _Exponent) { + _Exponent_start = _It; + } + } + _Integral_end = (_STD min)(_Radix_point, _Exponent_start); - if (_Is_finite) { - if (_Specs._Alt || _Specs._Localized) { - for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { - if (*_It == '.') { - _Radix_point = _It; - } else if (*_It == _Exponent) { - _Exponent_start = _It; + if (_Specs._Alt && _Radix_point == _Result.ptr) { + // TRANSITION, decimal point may be wider + ++_Width; + _Append_decimal = true; } - } - _Integral_end = (_STD min)(_Radix_point, _Exponent_start); - if (_Specs._Alt && _Radix_point == _Result.ptr) { - // TRANSITION, decimal point may be wider - ++_Width; - _Append_decimal = true; + if (_Specs._Localized) { + _Groups = _STD use_facet>(_Locale._Get()).grouping(); + _Separators = _Count_separators(static_cast(_Integral_end - _Buffer_start), _Groups); + } } - if (_Specs._Localized) { - _Groups = _STD use_facet>(_Locale._Get()).grouping(); - _Separators = _Count_separators(static_cast(_Integral_end - _Buffer_start), _Groups); + switch (_Format) { + case chars_format::hex: + case chars_format::scientific: + if (_Extra_precision != 0) { + // Trailing zeroes are in front of the exponent + while (*--_Exponent_start != _Exponent) { + } + } + [[fallthrough]]; + case chars_format::fixed: + _Zeroes_to_append = _Extra_precision; + break; + case chars_format::general: + if (_Specs._Alt) { + auto _Digits = static_cast(_Exponent_start - _Buffer_start); + + if (!_Append_decimal) { + --_Digits; + } + + _Zeroes_to_append = _Extra_precision + _Precision - _Digits; + + // Leading zeroes are not significant if we used fixed point notation. + if (_Exponent_start == _Result.ptr && _STD abs(_Value) < 1.0 && _Value != 0.0) { + for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { + if (*_It == '0') { + ++_Zeroes_to_append; + } else if (*_It != '.') { + break; + } + } + } + } + break; + default: + _STL_UNREACHABLE; } } - switch (_Format) { - case chars_format::hex: - case chars_format::scientific: - if (_Extra_precision != 0) { - // Trailing zeroes are in front of the exponent - while (*--_Exponent_start != _Exponent) { - } + _Width += _Zeroes_to_append; + + const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None && _Is_finite; + + auto _Writer = [&](_OutputIt _Out) { + _Out = _Write_sign(_STD move(_Out), _Sgn, _Is_negative); + + if (_Write_leading_zeroes && _Width < _Specs._Width) { + _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); } - [[fallthrough]]; - case chars_format::fixed: - _Zeroes_to_append = _Extra_precision; - break; - case chars_format::general: - if (_Specs._Alt) { - auto _Digits = static_cast(_Exponent_start - _Buffer_start); - if (!_Append_decimal) { - --_Digits; + if (_Specs._Localized) { + const auto& _Facet = _STD use_facet>(_Locale._Get()); + + _Out = _Write_separated_integer( + _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); + if (_Radix_point != _Result.ptr || _Append_decimal) { + *_Out++ = _Facet.decimal_point(); + _Append_decimal = false; + } + _Buffer_start = _Integral_end; + if (_Radix_point != _Result.ptr) { + ++_Buffer_start; } + } - _Zeroes_to_append = _Extra_precision + _Precision - _Digits; + _Out = _Widen_and_copy<_CharT>(_Buffer_start, _Exponent_start, _STD move(_Out)); + if (_Specs._Alt && _Append_decimal) { + *_Out++ = '.'; + } - // Leading zeroes are not significant if we used fixed point notation. - if (_Exponent_start == _Result.ptr && _STD abs(_Value) < 1.0 && _Value != 0.0) { - for (auto _It = _Buffer_start; _It < _Result.ptr; ++_It) { - if (*_It == '0') { - ++_Zeroes_to_append; - } else if (*_It != '.') { - break; - } - } - } + for (; _Zeroes_to_append > 0; --_Zeroes_to_append) { + *_Out++ = '0'; } - break; - default: - _STL_UNREACHABLE; + + return _Widen_and_copy<_CharT>(_Exponent_start, _Result.ptr, _STD move(_Out)); + }; + + if (_Write_leading_zeroes) { + return _Writer(_STD move(_Out)); + } + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); + } + + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const void* const _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { + _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'p'); + _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); + _STL_INTERNAL_CHECK(!_Specs._Alt); + _STL_INTERNAL_CHECK(_Specs._Precision == -1); + _STL_INTERNAL_CHECK(!_Specs._Leading_zero); + _STL_INTERNAL_CHECK(!_Specs._Localized); + + // Since the bit width of 0 is 0x0, special-case it instead of complicating the math even more. + int _Width = 3; + if (_Value != nullptr) { + // Compute the bit width of the pointer (i.e. how many bits it takes to be represented). + // Add 3 to the bit width so we always round up on the division. + // Divide that by the amount of bits a hexit represents (log2(16) = log2(2^4) = 4). + // Add 2 for the 0x prefix. + _Width = 2 + (_STD bit_width(reinterpret_cast(_Value)) + 3) / 4; } + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, + [=](_OutputIt _Out) { return _Fmt_write<_CharT>(_STD move(_Out), _Value); }); } - _Width += _Zeroes_to_append; + template + _NODISCARD _OutputIt _Fmt_write( + _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value}, _Specs, _Locale); + } - const bool _Write_leading_zeroes = _Specs._Leading_zero && _Specs._Alignment == _Fmt_align::_None && _Is_finite; + // width iterator for UTF-8 and UTF-16 + template + class _Measure_string_prefix_iterator_utf { + private: + _Grapheme_break_property_iterator<_CharT> _WrappedIter; - auto _Writer = [&](_OutputIt _Out) { - _Out = _Write_sign(_STD move(_Out), _Sgn, _Is_negative); + public: + _NODISCARD constexpr bool operator==(const _Measure_string_prefix_iterator_utf&) const noexcept = default; - if (_Write_leading_zeroes && _Width < _Specs._Width) { - _Out = _RANGES fill_n(_STD move(_Out), _Specs._Width - _Width, _CharT{'0'}); + _NODISCARD constexpr bool operator==(default_sentinel_t) const noexcept { + return _WrappedIter == default_sentinel; } - if (_Specs._Localized) { - const auto& _Facet = _STD use_facet>(_Locale._Get()); + using difference_type = ptrdiff_t; + using value_type = int; - _Out = _Write_separated_integer( - _Buffer_start, _Integral_end, _Groups, _Facet.thousands_sep(), _Separators, _STD move(_Out)); - if (_Radix_point != _Result.ptr || _Append_decimal) { - *_Out++ = _Facet.decimal_point(); - _Append_decimal = false; - } - _Buffer_start = _Integral_end; - if (_Radix_point != _Result.ptr) { - ++_Buffer_start; - } + constexpr _Measure_string_prefix_iterator_utf(const _CharT* _First, const _CharT* _Last) + : _WrappedIter(_First, _Last) {} + + constexpr _Measure_string_prefix_iterator_utf() = default; + + _NODISCARD constexpr value_type operator*() const { + return _Unicode_width_estimate(*_WrappedIter); } - _Out = _Widen_and_copy<_CharT>(_Buffer_start, _Exponent_start, _STD move(_Out)); - if (_Specs._Alt && _Append_decimal) { - *_Out++ = '.'; + constexpr _Measure_string_prefix_iterator_utf& operator++() noexcept { + ++_WrappedIter; + return *this; } - for (; _Zeroes_to_append > 0; --_Zeroes_to_append) { - *_Out++ = '0'; + constexpr _Measure_string_prefix_iterator_utf operator++(int) noexcept { + auto _Old = *this; + ++*this; + return _Old; } - return _Widen_and_copy<_CharT>(_Exponent_start, _Result.ptr, _STD move(_Out)); + _NODISCARD constexpr const _CharT* _Position() const { + return _WrappedIter._Position(); + } }; - if (_Write_leading_zeroes) { - return _Writer(_STD move(_Out)); - } + class _Measure_string_prefix_iterator_legacy { + private: + _Fmt_codec _Codec = _Get_fmt_codec(); + const char* _First = nullptr; + const char* _Last = nullptr; + int _Units = 0; + + void _Update_units() { + if (_First < _Last) { + _Units = _Codec._Units_in_next_character(_First, _Last); + } else { + _Units = -1; + } + } - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, _Writer); -} + public: + _NODISCARD bool operator==(default_sentinel_t) const noexcept { + return _First == _Last; + } + _NODISCARD bool operator==(const _Measure_string_prefix_iterator_legacy& _Rhs) const noexcept { + return _First == _Rhs._First && _Last == _Rhs._Last; + } -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const void* const _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { - _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'p'); - _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); - _STL_INTERNAL_CHECK(!_Specs._Alt); - _STL_INTERNAL_CHECK(_Specs._Precision == -1); - _STL_INTERNAL_CHECK(!_Specs._Leading_zero); - _STL_INTERNAL_CHECK(!_Specs._Localized); - - // Since the bit width of 0 is 0x0, special-case it instead of complicating the math even more. - int _Width = 3; - if (_Value != nullptr) { - // Compute the bit width of the pointer (i.e. how many bits it takes to be represented). - // Add 3 to the bit width so we always round up on the division. - // Divide that by the amount of bits a hexit represents (log2(16) = log2(2^4) = 4). - // Add 2 for the 0x prefix. - _Width = 2 + (_STD bit_width(reinterpret_cast(_Value)) + 3) / 4; - } - - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Right, - [=](_OutputIt _Out) { return _Fmt_write<_CharT>(_STD move(_Out), _Value); }); -} + using difference_type = ptrdiff_t; + using value_type = int; -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const _CharT* _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale _Locale) { - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value}, _Specs, _Locale); -} + _Measure_string_prefix_iterator_legacy(const char* _First_val, const char* _Last_val) + : _First(_First_val), _Last(_Last_val) { + _Update_units(); + } -// width iterator for UTF-8 and UTF-16 -template -class _Measure_string_prefix_iterator_utf { -private: - _Grapheme_break_property_iterator<_CharT> _WrappedIter; + _Measure_string_prefix_iterator_legacy() = default; -public: - _NODISCARD constexpr bool operator==(const _Measure_string_prefix_iterator_utf&) const noexcept = default; + _Measure_string_prefix_iterator_legacy& operator++() noexcept { + _First += _Units; + _Update_units(); + return *this; + } + _Measure_string_prefix_iterator_legacy operator++(int) noexcept { + auto _Old = *this; + ++*this; + return _Old; + } + _NODISCARD value_type operator*() const noexcept { + return _Units; + } - _NODISCARD constexpr bool operator==(default_sentinel_t) const noexcept { - return _WrappedIter == default_sentinel; - } + _NODISCARD const char* _Position() const noexcept { + return _First; + } + }; - using difference_type = ptrdiff_t; - using value_type = int; + template + using _Measure_string_prefix_iterator = + conditional_t && !_Is_execution_charset_self_synchronizing(), + _Measure_string_prefix_iterator_legacy, _Measure_string_prefix_iterator_utf<_CharT>>; - constexpr _Measure_string_prefix_iterator_utf(const _CharT* _First, const _CharT* _Last) - : _WrappedIter(_First, _Last) {} + template + _NODISCARD const _CharT* _Measure_string_prefix(const basic_string_view<_CharT> _Value, int& _Width) { + // Returns a pointer past-the-end of the largest prefix of _Value that fits in _Width, or all + // of _Value if _Width is negative. Updates _Width to the estimated width of that prefix. + const int _Max_width = _Width; + const auto _First = _Value.data(); + const auto _Last = _First + _Value.size(); + _Measure_string_prefix_iterator<_CharT> _Pfx_iter(_First, _Last); + int _Estimated_width = 0; // the estimated width of [_First, _Pfx_iter) + + constexpr auto _Max_int = (numeric_limits::max)(); + + while (_Pfx_iter != default_sentinel) { + if (_Estimated_width == _Max_width && _Max_width >= 0) { + // We're at our maximum length + break; + } - constexpr _Measure_string_prefix_iterator_utf() = default; + const int _Character_width = *_Pfx_iter; - _NODISCARD constexpr value_type operator*() const { - return _Unicode_width_estimate(*_WrappedIter); - } + if (_Max_int - _Character_width < _Estimated_width) { // avoid overflow + // Either _Max_width isn't set, or adding this character will exceed it. + if (_Max_width < 0) { // unset; saturate width estimate and take all characters + _Width = _Max_int; + return _Last; + } + break; + } - constexpr _Measure_string_prefix_iterator_utf& operator++() noexcept { - ++_WrappedIter; - return *this; - } + _Estimated_width += _Character_width; + if (_Estimated_width > _Max_width && _Max_width >= 0) { + // with this character, we exceed the maximum length + _Estimated_width -= _Character_width; + break; + } + ++_Pfx_iter; + } - constexpr _Measure_string_prefix_iterator_utf operator++(int) noexcept { - auto _Old = *this; - ++*this; - return _Old; + _Width = _Estimated_width; + return _Pfx_iter._Position(); } - _NODISCARD constexpr const _CharT* _Position() const { - return _WrappedIter._Position(); +#if _HAS_CXX23 + _NODISCARD constexpr bool _Is_printable(char32_t _Val) { + return __printable_property_data._Get_property_for_codepoint(_Val) == __printable_property_values::_Yes_value; } -}; -class _Measure_string_prefix_iterator_legacy { -private: - _Fmt_codec _Codec = _Get_fmt_codec(); - const char* _First = nullptr; - const char* _Last = nullptr; - int _Units = 0; - - void _Update_units() { - if (_First < _Last) { - _Units = _Codec._Units_in_next_character(_First, _Last); - } else { - _Units = -1; - } + _NODISCARD constexpr bool _Is_grapheme_extend(char32_t _Val) { + // TRANSITION, should reuse _Grapheme_Break_property_data to save space. + // (Grapheme_Extend=Yes is Grapheme_Cluster_Break=Extend minus Emoji_Modifier=Yes.) + return _Grapheme_Extend_property_data._Get_property_for_codepoint(_Val) + == _Grapheme_Extend_property_values::_Grapheme_Extend_value; } -public: - _NODISCARD bool operator==(default_sentinel_t) const noexcept { - return _First == _Last; - } - _NODISCARD bool operator==(const _Measure_string_prefix_iterator_legacy& _Rhs) const noexcept { - return _First == _Rhs._First && _Last == _Rhs._Last; - } + template + _NODISCARD _OutputIt _Write_escaped(_OutputIt _Out, basic_string_view<_CharT> _Value, char _Delim) { + auto _First = _Value.data(); + const auto _Last = _First + _Value.size(); + const auto& _Codec = _Get_fmt_codec<_CharT>(); - using difference_type = ptrdiff_t; - using value_type = int; + _STL_INTERNAL_CHECK(_Delim == '"' || _Delim == '\''); + *_Out++ = static_cast<_CharT>(_Delim); - _Measure_string_prefix_iterator_legacy(const char* _First_val, const char* _Last_val) - : _First(_First_val), _Last(_Last_val) { - _Update_units(); - } + bool _Escape_grapheme_extend = true; - _Measure_string_prefix_iterator_legacy() = default; + char _Buffer[8]; - _Measure_string_prefix_iterator_legacy& operator++() noexcept { - _First += _Units; - _Update_units(); - return *this; - } - _Measure_string_prefix_iterator_legacy operator++(int) noexcept { - auto _Old = *this; - ++*this; - return _Old; - } - _NODISCARD value_type operator*() const noexcept { - return _Units; - } + while (_First != _Last) { + const auto _Ch = *_First; - _NODISCARD const char* _Position() const noexcept { - return _First; - } -}; + if (_Ch == static_cast<_CharT>('\t')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\t)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\n')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\n)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\r')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\r)")); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>(_Delim)) { + *_Out++ = static_cast<_CharT>('\\'); + *_Out++ = static_cast<_CharT>(_Delim); + _Escape_grapheme_extend = true; + ++_First; + } else if (_Ch == static_cast<_CharT>('\\')) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\\)")); + _Escape_grapheme_extend = true; + ++_First; + } else { + char32_t _Decoded_ch; + const auto [_Next, _Is_usv] = _Codec._Decode(_First, _Last, _Decoded_ch); -template -using _Measure_string_prefix_iterator = - conditional_t && !_Is_execution_charset_self_synchronizing(), - _Measure_string_prefix_iterator_legacy, _Measure_string_prefix_iterator_utf<_CharT>>; + if (_Is_usv) { + const bool _Needs_escape = + !_Is_printable(_Decoded_ch) || (_Escape_grapheme_extend && _Is_grapheme_extend(_Decoded_ch)); -template -_NODISCARD const _CharT* _Measure_string_prefix(const basic_string_view<_CharT> _Value, int& _Width) { - // Returns a pointer past-the-end of the largest prefix of _Value that fits in _Width, or all - // of _Value if _Width is negative. Updates _Width to the estimated width of that prefix. - const int _Max_width = _Width; - const auto _First = _Value.data(); - const auto _Last = _First + _Value.size(); - _Measure_string_prefix_iterator<_CharT> _Pfx_iter(_First, _Last); - int _Estimated_width = 0; // the estimated width of [_First, _Pfx_iter) - - constexpr auto _Max_int = (numeric_limits::max)(); - - while (_Pfx_iter != default_sentinel) { - if (_Estimated_width == _Max_width && _Max_width >= 0) { - // We're at our maximum length - break; - } + if (_Needs_escape) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\u{)")); + + const auto [_End, _Ec] = + _STD to_chars(_Buffer, _STD end(_Buffer), static_cast(_Decoded_ch), 16); + _STL_INTERNAL_CHECK(_Ec == errc{}); + + _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); + + *_Out++ = static_cast<_CharT>('}'); + _Escape_grapheme_extend = true; + } else { + _Out = _STD _Copy_unchecked(_First, _Next, _STD move(_Out)); + _Escape_grapheme_extend = false; + } + + _First = _Next; + } else { + for (; _First != _Next; ++_First) { + _Out = _Fmt_write(_STD move(_Out), _STATICALLY_WIDEN(_CharT, R"(\x{)")); + + const auto [_End, _Ec] = _STD to_chars( + _Buffer, _STD end(_Buffer), static_cast>(*_First), 16); + _STL_INTERNAL_CHECK(_Ec == errc{}); - const int _Character_width = *_Pfx_iter; + _Out = _Widen_and_copy<_CharT>(_Buffer, _End, _STD move(_Out)); - if (_Max_int - _Character_width < _Estimated_width) { // avoid overflow - // Either _Max_width isn't set, or adding this character will exceed it. - if (_Max_width < 0) { // unset; saturate width estimate and take all characters - _Width = _Max_int; - return _Last; + *_Out++ = static_cast<_CharT>('}'); + } + _Escape_grapheme_extend = true; + } } - break; } - _Estimated_width += _Character_width; - if (_Estimated_width > _Max_width && _Max_width >= 0) { - // with this character, we exceed the maximum length - _Estimated_width -= _Character_width; - break; - } - ++_Pfx_iter; + *_Out++ = static_cast<_CharT>(_Delim); + + return _STD move(_Out); } - _Width = _Estimated_width; - return _Pfx_iter._Position(); -} + template + _NODISCARD _OutputIt _Write_escaped( + _OutputIt _Out, basic_string_view<_CharT> _Value, _Basic_format_specs<_CharT> _Specs, char _Delim) { + if (_Specs._Precision < 0 && _Specs._Width <= 0) { + return _Write_escaped(_STD move(_Out), _Value, _Delim); + } -template -_NODISCARD _OutputIt _Fmt_write( - _OutputIt _Out, const basic_string_view<_CharT> _Value, const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { - _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'c' || _Specs._Type == 's'); - _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); - _STL_INTERNAL_CHECK(!_Specs._Alt); - _STL_INTERNAL_CHECK(!_Specs._Leading_zero); + basic_string<_CharT> _Temp; + { + _Fmt_iterator_buffer>, _CharT> _Buf(back_insert_iterator{_Temp}); + (void) _Write_escaped(back_insert_iterator<_Fmt_buffer<_CharT>>{_Buf}, _Value, _Delim); + } - if (_Specs._Precision < 0 && _Specs._Width <= 0) { - return _Fmt_write(_STD move(_Out), _Value); + int _Width = _Specs._Precision; + const _CharT* _Last = _Measure_string_prefix<_CharT>(_Temp, _Width); + + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [&_Temp, _Last](_OutputIt _Out) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Temp.data(), _Last}); + }); } +#endif // _HAS_CXX23 - int _Width = _Specs._Precision; - const _CharT* _Last = _Measure_string_prefix(_Value, _Width); + template + _NODISCARD _OutputIt _Fmt_write(_OutputIt _Out, const basic_string_view<_CharT> _Value, + const _Basic_format_specs<_CharT>& _Specs, _Lazy_locale) { + _STL_INTERNAL_CHECK(_Specs._Type == '\0' || _Specs._Type == 'c' || _Specs._Type == 's' || _Specs._Type == '?'); + _STL_INTERNAL_CHECK(_Specs._Sgn == _Fmt_sign::_None); + _STL_INTERNAL_CHECK(!_Specs._Alt); + _STL_INTERNAL_CHECK(!_Specs._Leading_zero); - return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [=](_OutputIt _Out) { - return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value.data(), _Last}); - }); -} +#if _HAS_CXX23 + if (_Specs._Type == '?') { + return _Write_escaped(_STD move(_Out), _Value, _Specs, '"'); + } +#endif // _HAS_CXX23 -// This is the visitor that's used for "simple" replacement fields. -// It could be a generic lambda, but that's bad for throughput. -// A simple replacement field is a replacement field that's just "{}", -// without any format specs. -template -struct _Default_arg_formatter { - using _Context = basic_format_context<_OutputIt, _CharT>; + if (_Specs._Precision < 0 && _Specs._Width <= 0) { + return _Fmt_write(_STD move(_Out), _Value); + } - _OutputIt _Out; - basic_format_args<_Context> _Args; - _Lazy_locale _Loc; + int _Width = _Specs._Precision; + const _CharT* _Last = _Measure_string_prefix(_Value, _Width); - template - _OutputIt operator()(_Ty _Val) && { - return _Fmt_write<_CharT>(_STD move(_Out), _Val); + return _Write_aligned(_STD move(_Out), _Width, _Specs, _Fmt_align::_Left, [=](_OutputIt _Out) { + return _Fmt_write(_STD move(_Out), basic_string_view<_CharT>{_Value.data(), _Last}); + }); } - _OutputIt operator()(typename basic_format_arg<_Context>::handle _Handle) && { - basic_format_parse_context<_CharT> _Parse_ctx({}); - basic_format_context<_OutputIt, _CharT> _Format_ctx(_STD move(_Out), _Args, _Loc); - _Handle.format(_Parse_ctx, _Format_ctx); - return _Format_ctx.out(); - } -}; + // This is the visitor that's used for "simple" replacement fields. + // It could be a generic lambda, but that's bad for throughput. + // A simple replacement field is a replacement field that's just "{}", + // without any format specs. + template + struct _Default_arg_formatter { + using _Context = basic_format_context<_OutputIt, _CharT>; -// Visitor used for replacement fields that contain specs -template -struct _Arg_formatter { - using _Context = basic_format_context<_OutputIt, _CharT>; + _OutputIt _Out; + basic_format_args<_Context> _Args; + _Lazy_locale _Loc; - _Context* _Ctx = nullptr; - _Basic_format_specs<_CharT>* _Specs = nullptr; + template + _OutputIt operator()(_Ty _Val) && { + return _Fmt_write<_CharT>(_STD move(_Out), _Val); + } - _OutputIt operator()(typename basic_format_arg<_Context>::handle) { - _STL_VERIFY(false, "The custom handler should be structurally unreachable for _Arg_formatter"); - _STL_INTERNAL_CHECK(_Ctx); - return _Ctx->out(); - } + _OutputIt operator()(typename basic_format_arg<_Context>::handle _Handle) && { + basic_format_parse_context<_CharT> _Parse_ctx({}); + basic_format_context<_OutputIt, _CharT> _Format_ctx(_STD move(_Out), _Args, _Loc); + _Handle.format(_Parse_ctx, _Format_ctx); + return _Format_ctx.out(); + } + }; - template - _OutputIt operator()(_Ty _Val) { - _STL_INTERNAL_CHECK(_Specs); - _STL_INTERNAL_CHECK(_Ctx); - return _Fmt_write(_Ctx->out(), _Val, *_Specs, _Ctx->_Get_lazy_locale()); - } -}; + // Visitor used for replacement fields that contain specs + template + struct _Arg_formatter { + using _Context = basic_format_context<_OutputIt, _CharT>; -// Special compile time version of _Parse_format_specs. This version is parameterized on -// the type of the argument associated with the format specifier, since we don't really -// care about avoiding code bloat for code that never runs at runtime, and we can't form -// the erased basic_format_args structure at compile time. -template -consteval typename _ParseContext::iterator _Compile_time_parse_format_specs(_ParseContext& _Pc) { - using _CharT = typename _ParseContext::char_type; - using _Context = basic_format_context>, _CharT>; - using _ArgTraits = _Format_arg_traits<_Context>; - using _FormattedTypeMapping = typename _ArgTraits::template _Storage_type<_Ty>; - // If the type is going to use a custom formatter we should just use that, - // instead of trying to instantiate a custom formatter for its erased handle - // type - using _FormattedType = conditional_t::handle>, - _Ty, _FormattedTypeMapping>; - formatter<_FormattedType, _CharT> _Formatter{}; - return _Formatter.parse(_Pc); -} + _Context* _Ctx = nullptr; + _Basic_format_specs<_CharT>* _Specs = nullptr; -// set of format parsing actions that only checks for validity -template -struct _Format_checker { - using _ParseContext = basic_format_parse_context<_CharT>; - using _ParseFunc = typename _ParseContext::iterator (*)(_ParseContext&); - - static constexpr size_t _Num_args = sizeof...(_Args); - _ParseContext _Parse_context; - _ParseFunc _Parse_funcs[_Num_args > 0 ? _Num_args : 1]; - - consteval explicit _Format_checker(basic_string_view<_CharT> _Fmt) noexcept - : _Parse_context(_Fmt, _Num_args), _Parse_funcs{&_Compile_time_parse_format_specs<_Args, _ParseContext>...} {} - constexpr void _On_text(const _CharT*, const _CharT*) const noexcept {} - constexpr void _On_replacement_field(size_t, const _CharT*) const noexcept {} - constexpr const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT*) { - _Parse_context.advance_to(_Parse_context.begin() + (_First - _Parse_context.begin()._Unwrapped())); - if (_Id < _Num_args) { - auto _Iter = _Parse_funcs[_Id](_Parse_context); // TRANSITION, VSO-1451773 (workaround: named variable) - return _Iter._Unwrapped(); - } else { - return _First; + _OutputIt operator()(typename basic_format_arg<_Context>::handle) { + _STL_VERIFY(false, "The custom handler should be structurally unreachable for _Arg_formatter"); + _STL_INTERNAL_CHECK(_Ctx); + return _Ctx->out(); } - } -}; -// The top level set of parsing "actions". -template -struct _Format_handler { - using _OutputIt = back_insert_iterator<_Fmt_buffer<_CharT>>; - using _Context = basic_format_context<_OutputIt, _CharT>; + template + _OutputIt operator()(_Ty _Val) { + _STL_INTERNAL_CHECK(_Specs); + _STL_INTERNAL_CHECK(_Ctx); + return _Fmt_write(_Ctx->out(), _Val, *_Specs, _Ctx->_Get_lazy_locale()); + } + }; - basic_format_parse_context<_CharT> _Parse_context; - _Context _Ctx; + // Special compile time version of _Parse_format_specs. This version is parameterized on + // the type of the argument associated with the format specifier, since we don't really + // care about avoiding code bloat for code that never runs at runtime, and we can't form + // the erased basic_format_args structure at compile time. + template + consteval typename _ParseContext::iterator _Compile_time_parse_format_specs(_ParseContext& _Pc) { + using _CharT = typename _ParseContext::char_type; + using _Context = basic_format_context>, _CharT>; + using _ArgTraits = _Format_arg_traits<_Context>; + using _FormattedTypeMapping = typename _ArgTraits::template _Storage_type<_Ty>; + // If the type is going to use a custom formatter we should just use that, + // instead of trying to instantiate a custom formatter for its erased handle + // type + using _FormattedType = + conditional_t::handle>, _Ty, + _FormattedTypeMapping>; + formatter<_FormattedType, _CharT> _Formatter{}; + return _Formatter.parse(_Pc); + } + + // set of format parsing actions that only checks for validity + template + struct _Format_checker { + using _ParseContext = basic_format_parse_context<_CharT>; + using _ParseFunc = typename _ParseContext::iterator (*)(_ParseContext&); + + static constexpr size_t _Num_args = sizeof...(_Args); + _ParseContext _Parse_context; + _ParseFunc _Parse_funcs[_Num_args > 0 ? _Num_args : 1]; + + consteval explicit _Format_checker(basic_string_view<_CharT> _Fmt) noexcept + : _Parse_context(_Fmt, _Num_args), _Parse_funcs{ + &_Compile_time_parse_format_specs<_Args, _ParseContext>...} {} + constexpr void _On_text(const _CharT*, const _CharT*) const noexcept {} + constexpr void _On_replacement_field(size_t, const _CharT*) const noexcept {} + constexpr const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT*) { + _Parse_context.advance_to(_Parse_context.begin() + (_First - _Parse_context.begin()._Unwrapped())); + if (_Id < _Num_args) { + auto _Iter = _Parse_funcs[_Id](_Parse_context); // TRANSITION, VSO-1451773 (workaround: named variable) + return _Iter._Unwrapped(); + } else { + return _First; + } + } + }; - explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args) - : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args) {} + // The top level set of parsing "actions". + template + struct _Format_handler { + using _OutputIt = back_insert_iterator<_Fmt_buffer<_CharT>>; + using _Context = basic_format_context<_OutputIt, _CharT>; - explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args, - const _Lazy_locale& _Loc) - : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args, _Loc) {} + basic_format_parse_context<_CharT> _Parse_context; + _Context _Ctx; - void _On_text(const _CharT* _First, const _CharT* _Last) { - _Ctx.advance_to(_RANGES _Copy_unchecked(_First, _Last, _Ctx.out()).out); - } + explicit _Format_handler( + _OutputIt _Out, basic_string_view<_CharT> _Str, basic_format_args<_Context> _Format_args) + : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args) {} - void _On_replacement_field(const size_t _Id, const _CharT*) { - auto _Arg = _Get_arg(_Ctx, _Id); - _Ctx.advance_to(_STD visit_format_arg( - _Default_arg_formatter<_OutputIt, _CharT>{_Ctx.out(), _Ctx._Get_args(), _Ctx._Get_lazy_locale()}, _Arg)); - } + explicit _Format_handler(_OutputIt _Out, basic_string_view<_CharT> _Str, + basic_format_args<_Context> _Format_args, const _Lazy_locale& _Loc) + : _Parse_context(_Str), _Ctx(_STD move(_Out), _Format_args, _Loc) {} - const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT* _Last) { - _Parse_context.advance_to(_Parse_context.begin() + (_First - &*_Parse_context.begin())); - auto _Arg = _Get_arg(_Ctx, _Id); - if (_Arg._Active_state == _Basic_format_arg_type::_Custom_type) { - _Arg._Custom_state.format(_Parse_context, _Ctx); - return _Parse_context.begin()._Unwrapped(); + void _On_text(const _CharT* _First, const _CharT* _Last) { + _Ctx.advance_to(_RANGES _Copy_unchecked(_First, _Last, _Ctx.out()).out); } - _Basic_format_specs<_CharT> _Specs; - _Specs_checker<_Specs_handler, _Context>> _Handler( - _Specs_handler, _Context>{_Specs, _Parse_context, _Ctx}, - _Arg._Active_state); - _First = _Parse_format_specs(_First, _Last, _Handler); - if (_First == _Last || *_First != '}') { - _Throw_format_error("Missing '}' in format string."); + void _On_replacement_field(const size_t _Id, const _CharT*) { + auto _Arg = _Get_arg(_Ctx, _Id); + _Ctx.advance_to(_STD visit_format_arg( + _Default_arg_formatter<_OutputIt, _CharT>{_Ctx.out(), _Ctx._Get_args(), _Ctx._Get_lazy_locale()}, + _Arg)); } - _Ctx.advance_to(_STD visit_format_arg( - _Arg_formatter<_OutputIt, _CharT>{._Ctx = _STD addressof(_Ctx), ._Specs = _STD addressof(_Specs)}, _Arg)); - return _First; - } -}; + const _CharT* _On_format_specs(const size_t _Id, const _CharT* _First, const _CharT* _Last) { + _Parse_context.advance_to(_Parse_context.begin() + (_First - &*_Parse_context.begin())); + auto _Arg = _Get_arg(_Ctx, _Id); + if (_Arg._Active_state == _Basic_format_arg_type::_Custom_type) { + _Arg._Custom_state.format(_Parse_context, _Ctx); + return _Parse_context.begin()._Unwrapped(); + } + + _Basic_format_specs<_CharT> _Specs; + _Specs_checker<_Specs_handler, _Context>> _Handler( + _Specs_handler, _Context>{_Specs, _Parse_context, _Ctx}, + _Arg._Active_state); + _First = _Parse_format_specs(_First, _Last, _Handler); + if (_First == _Last || *_First != '}') { + _Throw_format_error("Missing '}' in format string."); + } + + _Ctx.advance_to(_STD visit_format_arg( + _Arg_formatter<_OutputIt, _CharT>{._Ctx = _STD addressof(_Ctx), ._Specs = _STD addressof(_Specs)}, + _Arg)); + return _First; + } + }; +#if _HAS_CXX23 +} // inline namespace __p2286 +#endif // _HAS_CXX23 // Generic formatter definition, the deleted default constructor // makes it "disabled" as per N4928 [format.formatter.spec]/5 @@ -3293,41 +3524,48 @@ struct formatter { formatter operator=(const formatter&) = delete; }; -template -struct _Formatter_base { - using _Pc = basic_format_parse_context<_CharT>; - - constexpr typename _Pc::iterator parse(_Pc& _ParseCtx) { - _Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler(_Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType); - const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler); - if (_It != _ParseCtx._Unchecked_end() && *_It != '}') { - _Throw_format_error("Missing '}' in format string."); +#if _HAS_CXX23 +inline namespace __p2286 { +#endif // _HAS_CXX23 + template + struct _Formatter_base { + using _Pc = basic_format_parse_context<_CharT>; + + constexpr typename _Pc::iterator parse(_Pc& _ParseCtx) { + _Specs_checker<_Dynamic_specs_handler<_Pc>> _Handler( + _Dynamic_specs_handler<_Pc>{_Specs, _ParseCtx}, _ArgType); + const auto _It = _Parse_format_specs(_ParseCtx._Unchecked_begin(), _ParseCtx._Unchecked_end(), _Handler); + if (_It != _ParseCtx._Unchecked_end() && *_It != '}') { + _Throw_format_error("Missing '}' in format string."); + } + return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin()); } - return _ParseCtx.begin() + (_It - _ParseCtx._Unchecked_begin()); - } - template - typename _FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const { - _Dynamic_format_specs<_CharT> _Format_specs = _Specs; - if (_Specs._Dynamic_width_index >= 0) { - _Format_specs._Width = - _Get_dynamic_specs<_Width_checker>(_FormatCtx.arg(static_cast(_Specs._Dynamic_width_index))); - } + template + typename _FormatContext::iterator format(const _Ty& _Val, _FormatContext& _FormatCtx) const { + _Dynamic_format_specs<_CharT> _Format_specs = _Specs; + if (_Specs._Dynamic_width_index >= 0) { + _Format_specs._Width = _Get_dynamic_specs<_Width_checker>( + _FormatCtx.arg(static_cast(_Specs._Dynamic_width_index))); + } - if (_Specs._Dynamic_precision_index >= 0) { - _Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>( - _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); - } + if (_Specs._Dynamic_precision_index >= 0) { + _Format_specs._Precision = _Get_dynamic_specs<_Precision_checker>( + _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); + } - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{_Val}); - } + return _STD visit_format_arg( + _Arg_formatter{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, + basic_format_arg<_FormatContext>{_Val}); + } -private: - _Dynamic_format_specs<_CharT> _Specs; -}; + private: + _Dynamic_format_specs<_CharT> _Specs; + }; +#if _HAS_CXX23 +} // inline namespace __p2286 +#endif // _HAS_CXX23 #define _FORMAT_SPECIALIZE_FOR(_Type, _ArgType) \ template <_Format_supported_charT _CharT> \ @@ -3422,141 +3660,147 @@ _NODISCARD auto make_wformat_args(_Args&&... _Vals) { return _Format_arg_store{_Vals...}; } -_EXPORT_STD template _OutputIt> -_OutputIt vformat_to(_OutputIt _Out, const string_view _Fmt, const format_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, char{}); - if constexpr (is_same_v<_OutputIt, _Fmt_it>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); +#if _HAS_CXX23 +inline namespace __p2286 { +#endif // _HAS_CXX23 + _EXPORT_STD template _OutputIt> + _OutputIt vformat_to(_OutputIt _Out, const string_view _Fmt, const format_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, char{}); + if constexpr (is_same_v<_OutputIt, _Fmt_it>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); + } } -} -_EXPORT_STD template _OutputIt> -_OutputIt vformat_to(_OutputIt _Out, const wstring_view _Fmt, const wformat_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, wchar_t{}); - if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); + _EXPORT_STD template _OutputIt> + _OutputIt vformat_to(_OutputIt _Out, const wstring_view _Fmt, const wformat_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, wchar_t{}); + if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); + } } -} -_EXPORT_STD template _OutputIt> -_OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, const format_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, char{}); - if constexpr (is_same_v<_OutputIt, _Fmt_it>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); + _EXPORT_STD template _OutputIt> + _OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const string_view _Fmt, const format_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, char{}); + if constexpr (is_same_v<_OutputIt, _Fmt_it>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, char> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_it{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); + } } -} -_EXPORT_STD template _OutputIt> -_OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { - // Make `_Parse_format_string` type-dependent to defer instantiation: - using _Dependent_char = decltype((void) _Out, wchar_t{}); - if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { - _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Out; - } else { - _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); - _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); - _Parse_format_string(_Fmt, _Handler); - return _Buf._Out(); + _EXPORT_STD template _OutputIt> + _OutputIt vformat_to(_OutputIt _Out, const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { + // Make `_Parse_format_string` type-dependent to defer instantiation: + using _Dependent_char = decltype((void) _Out, wchar_t{}); + if constexpr (is_same_v<_OutputIt, _Fmt_wit>) { + _Format_handler<_Dependent_char> _Handler(_Out, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Out; + } else { + _Fmt_iterator_buffer<_OutputIt, wchar_t> _Buf(_STD move(_Out)); + _Format_handler<_Dependent_char> _Handler(_Fmt_wit{_Buf}, _Fmt, _Args, _Lazy_locale{_Loc}); + _Parse_format_string(_Fmt, _Handler); + return _Buf._Out(); + } } -} -_EXPORT_STD template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_format_args(_Args...)); -} + _EXPORT_STD template _OutputIt, class... _Types> + _OutputIt format_to(_OutputIt _Out, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_format_args(_Args...)); + } -_EXPORT_STD template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_wformat_args(_Args...)); -} + _EXPORT_STD template _OutputIt, class... _Types> + _OutputIt format_to(_OutputIt _Out, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Fmt.get(), _STD make_wformat_args(_Args...)); + } -_EXPORT_STD template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_format_args(_Args...)); -} + _EXPORT_STD template _OutputIt, class... _Types> + _OutputIt format_to(_OutputIt _Out, const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_format_args(_Args...)); + } -_EXPORT_STD template _OutputIt, class... _Types> -_OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); -} + _EXPORT_STD template _OutputIt, class... _Types> + _OutputIt format_to(_OutputIt _Out, const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat_to(_STD move(_Out), _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + } -_EXPORT_STD template // improves throughput, see GH-2329 -_NODISCARD string vformat(const string_view _Fmt, const format_args _Args) { - string _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); - return _Str; -} + _EXPORT_STD template // improves throughput, see GH-2329 + _NODISCARD string vformat(const string_view _Fmt, const format_args _Args) { + string _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); + return _Str; + } -_EXPORT_STD template // improves throughput, see GH-2329 -_NODISCARD wstring vformat(const wstring_view _Fmt, const wformat_args _Args) { - wstring _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); - return _Str; -} + _EXPORT_STD template // improves throughput, see GH-2329 + _NODISCARD wstring vformat(const wstring_view _Fmt, const wformat_args _Args) { + wstring _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Fmt, _Args); + return _Str; + } -_EXPORT_STD template // improves throughput, see GH-2329 -_NODISCARD string vformat(const locale& _Loc, const string_view _Fmt, const format_args _Args) { - string _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); - return _Str; -} + _EXPORT_STD template // improves throughput, see GH-2329 + _NODISCARD string vformat(const locale& _Loc, const string_view _Fmt, const format_args _Args) { + string _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); + return _Str; + } -_EXPORT_STD template // improves throughput, see GH-2329 -_NODISCARD wstring vformat(const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { - wstring _Str; - _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); - _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); - return _Str; -} + _EXPORT_STD template // improves throughput, see GH-2329 + _NODISCARD wstring vformat(const locale& _Loc, const wstring_view _Fmt, const wformat_args _Args) { + wstring _Str; + _Str.reserve(_Fmt.size() + _Args._Estimate_required_capacity()); + _STD vformat_to(back_insert_iterator{_Str}, _Loc, _Fmt, _Args); + return _Str; + } -_EXPORT_STD template -_NODISCARD string format(const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Fmt.get(), _STD make_format_args(_Args...)); -} + _EXPORT_STD template + _NODISCARD string format(const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Fmt.get(), _STD make_format_args(_Args...)); + } -_EXPORT_STD template -_NODISCARD wstring format(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Fmt.get(), _STD make_wformat_args(_Args...)); -} + _EXPORT_STD template + _NODISCARD wstring format(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Fmt.get(), _STD make_wformat_args(_Args...)); + } -_EXPORT_STD template -_NODISCARD string format(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Loc, _Fmt.get(), _STD make_format_args(_Args...)); -} + _EXPORT_STD template + _NODISCARD string format(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Loc, _Fmt.get(), _STD make_format_args(_Args...)); + } -_EXPORT_STD template -_NODISCARD wstring format(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - return _STD vformat(_Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); -} + _EXPORT_STD template + _NODISCARD wstring format(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + return _STD vformat(_Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + } +#if _HAS_CXX23 +} // inline namespace __p2286 +#endif // _HAS_CXX23 _EXPORT_STD template struct format_to_n_result { @@ -3564,67 +3808,72 @@ struct format_to_n_result { iter_difference_t<_OutputIt> size; }; -_EXPORT_STD template _OutputIt, class... _Types> -format_to_n_result<_OutputIt> format_to_n( - _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; -} +#if _HAS_CXX23 +inline namespace __p2286 { +#endif // _HAS_CXX23 + _EXPORT_STD template _OutputIt, class... _Types> + format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, + const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; + } -_EXPORT_STD template _OutputIt, class... _Types> -format_to_n_result<_OutputIt> format_to_n( - _OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; -} + _EXPORT_STD template _OutputIt, class... _Types> + format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, + const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; + } -_EXPORT_STD template _OutputIt, class... _Types> -format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, - const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; -} + _EXPORT_STD template _OutputIt, class... _Types> + format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, + const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, char, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; + } -_EXPORT_STD template _OutputIt, class... _Types> -format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, const locale& _Loc, - const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); - _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - return {.out = _Buf._Out(), .size = _Buf._Count()}; -} + _EXPORT_STD template _OutputIt, class... _Types> + format_to_n_result<_OutputIt> format_to_n(_OutputIt _Out, const iter_difference_t<_OutputIt> _Max, + const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_iterator_buffer<_OutputIt, wchar_t, _Fmt_fixed_buffer_traits> _Buf(_STD move(_Out), _Max); + _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + return {.out = _Buf._Out(), .size = _Buf._Count()}; + } -_EXPORT_STD template -_NODISCARD size_t formatted_size(const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); - return _Buf._Count(); -} + _EXPORT_STD template + _NODISCARD size_t formatted_size(const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_it{_Buf}, _Fmt.get(), _STD make_format_args(_Args...)); + return _Buf._Count(); + } -_EXPORT_STD template -_NODISCARD size_t formatted_size(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); - return _Buf._Count(); -} + _EXPORT_STD template + _NODISCARD size_t formatted_size(const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_wit{_Buf}, _Fmt.get(), _STD make_wformat_args(_Args...)); + return _Buf._Count(); + } -_EXPORT_STD template -_NODISCARD size_t formatted_size(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); - return _Buf._Count(); -} + _EXPORT_STD template + _NODISCARD size_t formatted_size(const locale& _Loc, const format_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_it{_Buf}, _Loc, _Fmt.get(), _STD make_format_args(_Args...)); + return _Buf._Count(); + } -_EXPORT_STD template -_NODISCARD size_t formatted_size(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { - _Fmt_counting_buffer _Buf; - _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); - return _Buf._Count(); -} + _EXPORT_STD template + _NODISCARD size_t formatted_size(const locale& _Loc, const wformat_string<_Types...> _Fmt, _Types&&... _Args) { + _Fmt_counting_buffer _Buf; + _STD vformat_to(_Fmt_wit{_Buf}, _Loc, _Fmt.get(), _STD make_wformat_args(_Args...)); + return _Buf._Count(); + } #if _HAS_CXX23 +} // inline namespace __p2286 + enum class _Add_newline : bool { _Nope, _Yes }; _NODISCARD inline string _Unescape_braces(const _Add_newline _Add_nl, const string_view _Old_str) { diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index b1fc9a6c944..5952cab3179 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -337,6 +337,8 @@ // P2186R2 Removing Garbage Collection Support // P2273R3 constexpr unique_ptr // P2278R4 cbegin Should Always Return A Constant Iterator +// P2286R8 Formatting Ranges +// (only the '?' format specifier for strings and characters) // P2291R3 constexpr Integral // P2302R4 ranges::contains, ranges::contains_subrange // P2321R2 zip @@ -362,6 +364,7 @@ // P2540R1 Empty Product For Certain Views // P2549R1 unexpected::error() // P2652R2 Disallowing User Specialization Of allocator_traits +// P2713R1 Escaping Improvements In std::format // _HAS_CXX23 and _SILENCE_ALL_CXX23_DEPRECATION_WARNINGS control: // P1413R3 Deprecate aligned_storage And aligned_union diff --git a/tests/std/test.lst b/tests/std/test.lst index 4915e01ab03..3cfd1ab9ed2 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -569,6 +569,9 @@ tests\P2278R4_const_span tests\P2278R4_ranges_const_iterator_machinery tests\P2278R4_ranges_const_range_machinery tests\P2278R4_views_as_const +tests\P2286R8_formatting_ranges +tests\P2286R8_formatting_ranges_legacy_text_encoding +tests\P2286R8_formatting_ranges_utf8 tests\P2302R4_ranges_alg_contains tests\P2302R4_ranges_alg_contains_subrange tests\P2321R2_proxy_reference diff --git a/tests/std/tests/P2286R8_formatting_ranges/env.lst b/tests/std/tests/P2286R8_formatting_ranges/env.lst new file mode 100644 index 00000000000..18e2d7c71ec --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst diff --git a/tests/std/tests/P2286R8_formatting_ranges/test.cpp b/tests/std/tests/P2286R8_formatting_ranges/test.cpp new file mode 100644 index 00000000000..c735ff84dac --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges/test.cpp @@ -0,0 +1,125 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +using namespace std; + +template +[[nodiscard]] constexpr const CharT* choose_literal(const char* const str, const wchar_t* const wstr) noexcept { + if constexpr (is_same_v) { + return str; + } else { + return wstr; + } +} + +#define STR(Literal) (choose_literal(Literal, L##Literal)) + +template +auto make_testing_format_args(Args&&... vals) { + if constexpr (is_same_v) { + return make_wformat_args(forward(vals)...); + } else { + return make_format_args(forward(vals)...); + } +} + +template +void test_escaped_character() { + assert(format(STR("{:?}"), T('\t')) == STR(R"('\t')")); + assert(format(STR("{:?}"), T('\n')) == STR(R"('\n')")); + assert(format(STR("{:?}"), T('\r')) == STR(R"('\r')")); + assert(format(STR("{:?}"), T('\"')) == STR(R"('"')")); + assert(format(STR("{:?}"), T('\'')) == STR(R"('\'')")); + assert(format(STR("{:?}"), T('\\')) == STR(R"('\\')")); + + assert(format(STR("{:?}"), T('\0')) == STR(R"('\u{0}')")); + assert(format(STR("{:?}"), T('\v')) == STR(R"('\u{b}')")); + assert(format(STR("{:?}"), T('\f')) == STR(R"('\u{c}')")); + assert(format(STR("{:?}"), T('\x7F')) == STR(R"('\u{7f}')")); + + assert(format(STR("{:?}"), T(' ')) == STR("' '")); + assert(format(STR("{:?}"), T('~')) == STR("'~'")); + + if constexpr (is_same_v && is_same_v) { + assert(format(L"{:?}", L'\xA0') == LR"('\u{a0}')"); // U+00A0 NO-BREAK SPACE + assert(format(L"{:?}", L'\x300') == LR"('\u{300}')"); // U+0300 COMBINING GRAVE ACCENT + + assert(format(L"{:?}", L'\xA1') == L"'\xA1'"); // U+00A1 INVERTED EXCLAMATION MARK + + assert(format(L"{:?}", L'\xD800') == LR"('\x{d800}')"); + assert(format(L"{:?}", L'\xDFFF') == LR"('\x{dfff}')"); + } +} + +template +void test_escaped_string() { + assert(format(STR("{:?}"), STR("\t")) == STR(R"("\t")")); + assert(format(STR("{:?}"), STR("\n")) == STR(R"("\n")")); + assert(format(STR("{:?}"), STR("\r")) == STR(R"("\r")")); + assert(format(STR("{:?}"), STR("\"")) == STR("\"\\\"\"")); + assert(format(STR("{:?}"), STR("\'")) == STR(R"("'")")); + assert(format(STR("{:?}"), STR("\\")) == STR(R"("\\")")); + + assert(format(STR("{:?}"), STR("\v")) == STR(R"("\u{b}")")); + assert(format(STR("{:?}"), STR("\f")) == STR(R"("\u{c}")")); + assert(format(STR("{:?}"), STR("\x7F")) == STR(R"("\u{7f}")")); + + assert(format(STR("{:?}"), STR(" ")) == STR("\" \"")); + assert(format(STR("{:?}"), STR("~")) == STR("\"~\"")); + + assert(format(STR("[{:?}]"), basic_string{STR("\0 \n \t \x02 \x1b"), 9}) == STR(R"(["\u{0} \n \t \u{2} \u{1b}"])")); + assert(format(STR("[{:?}]"), basic_string_view{STR("\0 \n \t \x02 \x1b"), 9}) + == STR(R"(["\u{0} \n \t \u{2} \u{1b}"])")); + + if constexpr (is_same_v) { + assert(format(L"{:?}", L"\xA0") == LR"("\u{a0}")"); // U+00A0 NO-BREAK SPACE + assert(format(L"{:?}", L"\U0010FFFF") == LR"("\u{10ffff}")"); // noncharacter + assert(format(L"{:?}", L"\x300") == LR"("\u{300}")"); // U+0300 COMBINING GRAVE ACCENT + + assert(format(L"{:?}", L"\xA1") == L"\"\xA1\""); // U+00A1 INVERTED EXCLAMATION MARK + assert(format(L"{:?}", L"\U00010000") == L"\"\U00010000\""); // U+10000 LINEAR B SYLLABLE B008 A + + assert(format(L"{:?}", L"\xD800") == L"\"\\x{d800}\""); + assert(format(L"{:?}", L"\xDFFF") == L"\"\\x{dfff}\""); + assert(format(L"{:?}", L"\xDFFF\xD800") == L"\"\\x{dfff}\\x{d800}\""); + + assert(format(L"{:?}", L"\xA0\x300") == L"\"\\u{a0}\\u{300}\""); + assert(format(L"{:?}", L" \x300") == L"\" \x300\""); + assert(format(L"{:?}", L"~\x300") == L"\"~\x300\""); + } +} + +template +void test_format_specs() { + assert(format(STR("{:5?}"), T('\n')) == STR(R"('\n' )")); + try { + (void) vformat(STR("{:.3?}"), make_testing_format_args(T('\n'))); + assert(false); + } catch (const format_error&) { + } + + assert(format(STR("{:5?}"), STR("\n")) == STR(R"("\n" )")); + assert(format(STR("{:.3?}"), STR("\n")) == STR(R"("\n)")); + assert(format(STR("{:5.3?}"), STR("\n")) == STR(R"("\n )")); + assert(format(STR("{:>5.3?}"), STR("\n")) == STR(R"( "\n)")); +} + +int main() { + test_escaped_character(); + test_escaped_character(); + test_escaped_character(); + + test_escaped_string(); + test_escaped_string(); + + test_format_specs(); + test_format_specs(); + test_format_specs(); +} diff --git a/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/env.lst b/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/env.lst new file mode 100644 index 00000000000..3e3264e4bcc --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/env.lst @@ -0,0 +1,28 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +# This is `concepts_latest_matrix.lst` with `/execution-charset:.932` added. +# clang is excluded since it doesn't support non-UTF-8 execution charsets. + +RUNALL_INCLUDE ..\prefix.lst +RUNALL_CROSSLIST +PM_CL="/w14640 /Zc:threadSafeInit- /EHsc /std:c++latest /execution-charset:.932" +RUNALL_CROSSLIST +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:noexceptTypes-" +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" +PM_CL="/MD /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:char8_t- /Zc:preprocessor" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /Zc:wchar_t-" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" +PM_CL="/MDd /D_ITERATOR_DEBUG_LEVEL=2 /permissive- /fp:except /Zc:preprocessor" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /permissive-" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /analyze:only /analyze:autolog-" +PM_CL="/MT /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=0 /permissive- /fp:strict" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=1 /permissive-" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /permissive" +PM_CL="/MTd /D_ITERATOR_DEBUG_LEVEL=2 /permissive- /analyze:only /analyze:autolog-" +# PM_CL="/permissive- /BE /c /MD" +# PM_CL="/permissive- /BE /c /MTd" +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /permissive- /MD" +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /permissive- /MTd /fp:strict" +# PM_COMPILER="clang-cl" PM_CL="-fno-ms-compatibility -fno-delayed-template-parsing -Wno-unqualified-std-cast-call /permissive- /MT /fp:strict -fsanitize=undefined -fno-sanitize-recover=undefined" diff --git a/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/test.cpp b/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/test.cpp new file mode 100644 index 00000000000..9473f66c566 --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges_legacy_text_encoding/test.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include + +using namespace std; + +void test_escaped_string() { + assert(format("{:?}", "\x81\x40") == "\"\\u{3000}\""); // U+3000 IDEOGRAPHIC SPACE + + assert(format("{:?}", "\x81\x41") == "\"\x81\x41\""); + + assert(format("{:?}", "\x81") == "\"\\x{81}\""); + assert(format("{:?}", "\xEB!") == "\"\\x{eb}!\""); + + assert(format("{:?}", "\x81\x40\x40\x81") == "\"\\u{3000}\x40\\x{81}\""); +} + +int main() { + test_escaped_string(); +} diff --git a/tests/std/tests/P2286R8_formatting_ranges_utf8/env.lst b/tests/std/tests/P2286R8_formatting_ranges_utf8/env.lst new file mode 100644 index 00000000000..4ca6faed472 --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges_utf8/env.lst @@ -0,0 +1,6 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_latest_matrix.lst +RUNALL_CROSSLIST +PM_CL="/utf-8" diff --git a/tests/std/tests/P2286R8_formatting_ranges_utf8/test.cpp b/tests/std/tests/P2286R8_formatting_ranges_utf8/test.cpp new file mode 100644 index 00000000000..5c21fb5423c --- /dev/null +++ b/tests/std/tests/P2286R8_formatting_ranges_utf8/test.cpp @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include + +using namespace std; + +void test_escaped_string() { + assert(format("{:?}", "\u00A0") == "\"\\u{a0}\""); // U+00A0 NO-BREAK SPACE + assert(format("{:?}", "\u0300") == "\"\\u{300}\""); // U+0300 COMBINING GRAVE ACCENT + + assert(format("{:?}", "\u00A1") == "\"\u00A1\""); // U+00A1 INVERTED EXCLAMATION MARK + assert(format("{:?}", "\U00010000") == "\"\U00010000\""); // U+10000 LINEAR B SYLLABLE B008 A + + assert(format("{:?}", "\xC0\x80") == "\"\\x{c0}\\x{80}\""); // ill-formed code unit sequence + + assert(format("{:?}", "\u00A0\u0300") == "\"\\u{a0}\\u{300}\""); + assert(format("{:?}", " \u0300") == "\" \u0300\""); + assert(format("{:?}", "a\u0300") == "\"a\u0300\""); +} + +int main() { + test_escaped_string(); + + assert(setlocale(LC_ALL, ".1252") != nullptr); + test_escaped_string(); + + assert(setlocale(LC_ALL, ".932") != nullptr); + test_escaped_string(); + + assert(setlocale(LC_ALL, ".UTF-8") != nullptr); + test_escaped_string(); +} diff --git a/tools/unicode_properties_parse/.gitignore b/tools/unicode_properties_parse/.gitignore index 5e0f64d267b..94b365a6e24 100644 --- a/tools/unicode_properties_parse/.gitignore +++ b/tools/unicode_properties_parse/.gitignore @@ -5,5 +5,7 @@ # they can be downloaded from unicode.org. # See the documentation in each script for more info. emoji-data.txt +DerivedCoreProperties.txt +DerivedGeneralCategory.txt GraphemeBreakProperty.txt GraphemeBreakTest.txt diff --git a/tools/unicode_properties_parse/grapheme_break_property_data_gen.py b/tools/unicode_properties_parse/grapheme_break_property_data_gen.py index 6002a40f343..9254a31efe6 100644 --- a/tools/unicode_properties_parse/grapheme_break_property_data_gen.py +++ b/tools/unicode_properties_parse/grapheme_break_property_data_gen.py @@ -70,12 +70,21 @@ def compact_property_ranges(input: list[PropertyRange]) -> list[PropertyRange]: DATA_ARRAY_TEMPLATE = """ {filename} {timestamp} -inline constexpr _Unicode_property_data<_{prop_name}_property_values, {size}> _{prop_name}_property_data{{ +inline constexpr _Unicode_property_data<_{prop_name}_property_values, {size}, {is_binary_property}> + _{prop_name}_property_data{{ {{{lower_bounds}}}, {{{props_and_size}}} }}; """ +INTERVALS_TEMPLATE = """ +{filename} +{timestamp} +inline constexpr char32_t _{prop_name}_ranges[{size}] = {{ + {data} +}}; +""" + MSVC_FORMAT_UCD_TABLES_HPP_TEMPLATE = """ // __msvc_format_ucd_tables.hpp internal header @@ -152,7 +161,7 @@ def compact_property_ranges(input: list[PropertyRange]) -> list[PropertyRange]: _STD_BEGIN -template +template struct _Unicode_property_data {{ uint32_t _Lower_bounds[_NumRanges]; uint16_t _Props_and_size[_NumRanges]; @@ -165,11 +174,17 @@ def compact_property_ranges(input: list[PropertyRange]) -> list[PropertyRange]: --_Upper_idx; const uint32_t _Lower_bound = _Lower_bounds[_Upper_idx]; const uint16_t _Data = _Props_and_size[_Upper_idx]; - const uint16_t _Size = static_cast(_Data & 0x0FFF); - const _ValueEnum _Prop = static_cast<_ValueEnum>((_Data & 0xF000) >> 12); _STL_INTERNAL_CHECK(_Code_point >= _Lower_bound); - if (_Code_point < _Lower_bound + _Size) {{ - return _Prop; + if constexpr (_Is_binary_property) {{ + if (_Code_point < _Lower_bound + _Data) {{ + return static_cast<_ValueEnum>(0); + }} + }} else {{ + const uint16_t _Size = static_cast(_Data & 0x0FFF); + const _ValueEnum _Prop = static_cast<_ValueEnum>((_Data & 0xF000) >> 12); + if (_Code_point < _Lower_bound + _Size) {{ + return _Prop; + }} }} return _No_value_constant; }} @@ -180,25 +195,28 @@ def compact_property_ranges(input: list[PropertyRange]) -> list[PropertyRange]: // // _Extended_Pictographic_property_data comes from ucd/emoji/emoji-data.txt. // +// __printable_property_data comes from ucd/extracted/DerivedGeneralCategory.txt. +// +// _Grapheme_Extend_property_data comes from ucd/DerivedCoreProperties.txt. +// // The enums containing the values for the properties are also generated, in order to ensure they match // up correctly with how we're parsing them. // -// Both sets of data tables are generated by tools/unicode_properties_parse/grapheme_break_property_data_gen.py in the +// All sets of data tables are generated by tools/unicode_properties_parse/grapheme_break_property_data_gen.py in the // https://github.com/microsoft/stl repository. // // The data format is a set of arrays for each character property. The first is an array of uint32_t encoding // the lower bound of each range of codepoints that has the given property. -// The second is an array of uint16_t encoding both the range size and property value as follows: -// 16 12 0 -// +-----------------------------------------------------+ -// | property_value | range_size | -// +-----------------------------------------------------+ -// that is: the size is stored in the least significant 12 bits -// (leading to a max size of 4095), and the property value is stored in the most significant 4 bits, -// leading to a maximum of 16 property values. -// -// Note that the Extended_Pictographic property only has one value, and we encode it as zero in the most significant 4 -// bits, so the most significant 4 bits of _Props_and_size are "unused", in some sense. +// The second is an array of uint16_t. +// - For enumerated properties, this array encodes both the range size and property value as follows: +// 16 12 0 +// +-----------------------------------------------------+ +// | property_value | range_size | +// +-----------------------------------------------------+ +// that is: the size is stored in the least significant 12 bits +// (leading to a max size of 4095), and the property value is stored in the most significant 4 bits, +// leading to a maximum of 16 property values. +// - For binary properties, this array simply stores the range size. // // Codepoint ranges may not overlap, and, within one property, a codepoint may only appear once. Furthermore the // codepoint lower bounds appear in sorted (ascending) order. @@ -215,21 +233,26 @@ def compact_property_ranges(input: list[PropertyRange]) -> list[PropertyRange]: #endif // __MSVC_FORMAT_UCD_TABLES_HPP """ -def property_ranges_to_table(ranges: list[PropertyRange], props: list[str]) -> PropertyTable: +def property_ranges_to_table(ranges: list[PropertyRange], props: list[str], is_binary_property: bool) -> PropertyTable: result = PropertyTable() for range in sorted(ranges, key=lambda x: x.lower): result.lower_bounds.append(range.lower) size = (range.upper - range.lower) + 1 - assert size <= 0x0FFF - prop_idx = props.index(range.prop) - result.props_and_range.append(size | (prop_idx << 12)) + if is_binary_property: + assert size <= 0xFFFF + result.props_and_range.append(size) + else: + assert size <= 0x0FFF + prop_idx = props.index(range.prop) + result.props_and_range.append(size | (prop_idx << 12)) return result def generate_cpp_data(filename: str, timestamp: str, prop_name: str, ranges: list[PropertyRange]) -> str: result = StringIO() prop_values = sorted(set(x.prop for x in ranges)) - table = property_ranges_to_table(ranges, prop_values) + is_binary_property = len(prop_values) == 1 + table = property_ranges_to_table(ranges, prop_values, is_binary_property) enumerator_values = [PROP_VALUE_ENUMERATOR_TEMPLATE.format( x) for x in prop_values] result.write(PROP_VALUE_ENUM_TEMPLATE.lstrip().format( @@ -237,15 +260,25 @@ def generate_cpp_data(filename: str, timestamp: str, prop_name: str, ranges: lis result.write("\n") result.write(DATA_ARRAY_TEMPLATE.lstrip().format(filename=filename, timestamp=timestamp, prop_name=prop_name, size=len(table.lower_bounds), + is_binary_property='true' if is_binary_property else 'false', lower_bounds=",".join(["0x" + format(x, 'x') for x in table.lower_bounds]), props_and_size=",".join(["0x" + format(x, 'x') for x in table.props_and_range]))) return result.getvalue() +def read_file(filename: str) -> list[PropertyRange]: + data_path = Path(__file__).absolute().with_name(filename) + with data_path.open(encoding='utf-8') as f: + filename = f.readline().replace("#", "//").rstrip() + timestamp = f.readline().replace("#", "//").rstrip() + ranges = compact_property_ranges([x for line in f if (x := parse_property_line(line))]) + return filename, timestamp, ranges + + def generate_data_tables() -> str: """ Generate Unicode data for inclusion into from - GraphemeBreakProperty.txt and emoji-data.txt. + GraphemeBreakProperty.txt, emoji-data.txt, DerivedGeneralCategory.txt, and DerivedCoreProperties.txt GraphemeBreakProperty.txt can be found at https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/GraphemeBreakProperty.txt @@ -253,28 +286,34 @@ def generate_data_tables() -> str: emoji-data.txt can be found at https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-data.txt - Both files are expected to be in the same directory as this script. + DerivedGeneralCategory.txt can be found at + https://www.unicode.org/Public/UCD/latest/ucd/extracted/DerivedGeneralCategory.txt + + DerivedCoreProperties.txt can be found at + https://www.unicode.org/Public/UCD/latest/ucd/DerivedCoreProperties.txt + + All files are expected to be in the same directory as this script. """ - gbp_data_path = Path(__file__).absolute().with_name("GraphemeBreakProperty.txt") - emoji_data_path = Path(__file__).absolute().with_name("emoji-data.txt") - gbp_filename = "" - gbp_timestamp = "" - emoji_filename = "" - emoji_timestamp = "" - gbp_ranges = list() - emoji_ranges = list() - with gbp_data_path.open(encoding='utf-8') as f: - gbp_filename = f.readline().replace("#", "//").rstrip() - gbp_timestamp = f.readline().replace("#", "//").rstrip() - gbp_ranges = compact_property_ranges([x for line in f if (x := parse_property_line(line))]) - with emoji_data_path.open(encoding='utf-8') as f: - emoji_filename = f.readline().replace("#", "//").rstrip() - emoji_timestamp = f.readline().replace("#", "//").rstrip() - emoji_ranges = compact_property_ranges([x for line in f if (x := parse_property_line(line))]) + gbp_filename, gbp_timestamp, gbp_ranges = read_file("GraphemeBreakProperty.txt") + emoji_filename, emoji_timestamp, emoji_ranges = read_file("emoji-data.txt") + cat_filename, cat_timestamp, cat_ranges = read_file("DerivedGeneralCategory.txt") + derived_filename, derived_timestamp, derived_ranges = read_file("DerivedCoreProperties.txt") + + printable_ranges = compact_property_ranges(sorted([ + PropertyRange(x.lower, x.upper, "Yes") + for x in cat_ranges + if x.prop not in ('Cc', 'Cf', 'Cs', 'Co', 'Cn', 'Zl', 'Zp', 'Zs') or chr(x.lower) == ' ' + ], key=lambda x: x.lower)) + gpb_cpp_data = generate_cpp_data(gbp_filename, gbp_timestamp, "Grapheme_Break", gbp_ranges) emoji_cpp_data = generate_cpp_data(emoji_filename, emoji_timestamp, "Extended_Pictographic", [ x for x in emoji_ranges if x.prop == "Extended_Pictographic"]) - return "\n".join([gpb_cpp_data, emoji_cpp_data]) + # _printable follows a different naming scheme, to indicate that it is a fake Unicode property. + printable_cpp_data = generate_cpp_data(cat_filename, cat_timestamp, "_printable", printable_ranges) + grapheme_extend_cpp_data = generate_cpp_data(derived_filename, derived_timestamp, "Grapheme_Extend", [ + x for x in derived_ranges if x.prop == "Grapheme_Extend"]) + + return "\n".join([gpb_cpp_data, emoji_cpp_data, printable_cpp_data, grapheme_extend_cpp_data]) if __name__ == "__main__":