From a69ba8d9954b59468466016a355c7ca26ad27690 Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Sat, 23 Jan 2021 16:51:45 -0800 Subject: [PATCH 1/8] charconv internal functions for wchar_t buffers --- stl/inc/xcharconv_ryu.h | 250 ++++++++++++---------- stl/inc/xcharconv_ryu_tables.h | 17 +- tests/std/tests/P0067R5_charconv/test.cpp | 8 + 3 files changed, 166 insertions(+), 109 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index 1b2b95a8e05..4e1c24a2a1e 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -39,6 +39,8 @@ #if _STL_COMPILER_PREPROCESSOR #include +#include +#include #include #include @@ -389,7 +391,16 @@ _NODISCARD inline uint32_t __mulShift_mod1e9(const uint64_t __m, const uint64_t* #endif // ^^^ intrinsics unavailable ^^^ } -inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, char* const __result) { +#define _WIDEN(_TYPE, _CHAR) (is_same_v<_TYPE,char> ? _CHAR : L##_CHAR) + +template +void _Copy_digits_from_table(_CharT* _Dst, ptrdiff_t _Offset) +{ + _CSTD memcpy(_Dst, __DIGIT_TABLE<_CharT> + _Offset, 2 * sizeof(_CharT)); +} + +template +inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, _CharT* const __result) { uint32_t __i = 0; while (__digits >= 10000) { #ifdef __clang__ // TRANSITION, LLVM-38217 @@ -400,21 +411,21 @@ inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, char* __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + __olength - __i - 4, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(__result + __olength - __i - 2, __c0); + _Copy_digits_from_table(__result + __olength - __i - 4, __c1); __i += 4; } if (__digits >= 100) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(__result + __olength - __i - 2, __c); __i += 2; } if (__digits >= 10) { const uint32_t __c = __digits << 1; - _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(__result + __olength - __i - 2, __c); } else { - __result[0] = static_cast('0' + __digits); + __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } } @@ -429,43 +440,56 @@ inline void __append_d_digits(const uint32_t __olength, uint32_t __digits, char* __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(__result + __olength + 1 - __i - 2, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + __olength + 1 - __i - 4, __DIGIT_TABLE + __c1, 2); + _CSTD memcpy(__result + __olength + 1 - __i - 2, __DIGIT_TABLE + __c0, 2); + _CSTD memcpy(__result + __olength + 1 - __i - 4, __DIGIT_TABLE + __c1, 2); __i += 4; } if (__digits >= 100) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - _CSTD memcpy(__result + __olength + 1 - __i - 2, __DIGIT_TABLE + __c, 2); + _CSTD memcpy(__result + __olength + 1 - __i - 2, __DIGIT_TABLE + __c, 2); __i += 2; } if (__digits >= 10) { const uint32_t __c = __digits << 1; - __result[2] = __DIGIT_TABLE[__c + 1]; + __result[2] = __DIGIT_TABLE[__c + 1]; __result[1] = '.'; - __result[0] = __DIGIT_TABLE[__c]; + __result[0] = __DIGIT_TABLE[__c]; } else { __result[1] = '.'; __result[0] = static_cast('0' + __digits); } } -inline void __append_c_digits(const uint32_t __count, uint32_t __digits, char* const __result) { +template +inline void _Fill_string_zero(_CharT* _Dst, size_t _Size) { + if constexpr (is_same_v<_CharT, char>) { + memset(_Dst, '0', _Size); + } else { + for (; 0 < _Size; --_Size, (void) ++_Dst) { + *_Dst = _WIDEN(_CharT, '0'); + } + } +} + +template +inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* const __result) { uint32_t __i = 0; for (; __i < __count - 1; __i += 2) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - _CSTD memcpy(__result + __count - __i - 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(__result + __count - __i - 2, __c); } if (__i < __count) { - const char __c = static_cast('0' + (__digits % 10)); + const _CharT __c = static_cast<_CharT>(_WIDEN(_CharT, '0') + (__digits % 10)); __result[__count - __i - 1] = __c; } } -inline void __append_nine_digits(uint32_t __digits, char* const __result) { +template +inline void __append_nine_digits(uint32_t __digits, _CharT* const __result) { if (__digits == 0) { - _CSTD memset(__result, '0', 9); + _Fill_string_zero(__result, 9); return; } @@ -478,10 +502,10 @@ inline void __append_nine_digits(uint32_t __digits, char* const __result) { __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(__result + 7 - __i, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + 5 - __i, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(__result + 7 - __i, __c0); + _Copy_digits_from_table(__result + 5 - __i, __c1); } - __result[0] = static_cast('0' + __digits); + __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } _NODISCARD inline uint32_t __indexForExponent(const uint32_t __e) { @@ -497,9 +521,10 @@ _NODISCARD inline uint32_t __lengthForIndex(const uint32_t __idx) { return (__log10Pow2(16 * static_cast(__idx)) + 1 + 16 + 8) / 9; } -_NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const _Last, const double __d, +template +_NODISCARD pair<_CharT*, errc> __d2fixed_buffered_n(_CharT* _First, _CharT* const _Last, const double __d, const uint32_t __precision) { - char* const _Original_first = _First; + _CharT* const _Original_first = _First; const uint64_t __bits = __double_to_bits(__d); @@ -513,10 +538,10 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const return { _Last, errc::value_too_large }; } - *_First++ = '0'; + *_First++ = _WIDEN(_CharT, '0'); if (__precision > 0) { - *_First++ = '.'; - _CSTD memset(_First, '0', __precision); + *_First++ = _WIDEN(_CharT, '.'); + _Fill_string_zero(_First, __precision); _First += __precision; } return { _First, errc{} }; @@ -568,13 +593,13 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const if (_First == _Last) { return { _Last, errc::value_too_large }; } - *_First++ = '0'; + *_First++ = _WIDEN(_CharT, '0'); } if (__precision > 0) { if (_First == _Last) { return { _Last, errc::value_too_large }; } - *_First++ = '.'; + *_First++ = _WIDEN(_CharT, '.'); } if (__e2 < 0) { const int32_t __idx = -__e2 / 16; @@ -587,14 +612,14 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const if (_Last - _First < static_cast(__precision)) { return { _Last, errc::value_too_large }; } - _CSTD memset(_First, '0', __precision); + _Fill_string_zero(_First, __precision); _First += __precision; } else if (__i < __MIN_BLOCK_2[__idx]) { __i = __MIN_BLOCK_2[__idx]; if (_Last - _First < static_cast(9 * __i)) { return { _Last, errc::value_too_large }; } - _CSTD memset(_First, '0', 9 * __i); + _Fill_string_zero(_First, 9 * __i); _First += 9 * __i; } for (; __i < __blocks; ++__i) { @@ -607,7 +632,7 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const if (_Last - _First < static_cast(__fill)) { return { _Last, errc::value_too_large }; } - _CSTD memset(_First, '0', __fill); + _Fill_string_zero(_First, __fill); _First += __fill; break; } @@ -647,31 +672,31 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const } } if (__roundUp != 0) { - char* _Round = _First; - char* _Dot = _Last; + _CharT* _Round = _First; + _CharT* _Dot = _Last; while (true) { if (_Round == _Original_first) { - _Round[0] = '1'; + _Round[0] = _WIDEN(_CharT, '1'); if (_Dot != _Last) { - _Dot[0] = '0'; - _Dot[1] = '.'; + _Dot[0] = _WIDEN(_CharT, '0'); + _Dot[1] = _WIDEN(_CharT, '.'); } if (_First == _Last) { return { _Last, errc::value_too_large }; } - *_First++ = '0'; + *_First++ = _WIDEN(_CharT, '0'); break; } --_Round; - const char __c = _Round[0]; + const _CharT __c = _Round[0]; if (__c == '.') { _Dot = _Round; - } else if (__c == '9') { - _Round[0] = '0'; + } else if (__c == _WIDEN(_CharT, '9')) { + _Round[0] = _WIDEN(_CharT, '0'); __roundUp = 1; } else { if (__roundUp == 1 || __c % 2 != 0) { - _Round[0] = __c + 1; + _Round[0] = static_cast<_CharT>(__c + 1); } break; } @@ -681,7 +706,7 @@ _NODISCARD inline to_chars_result __d2fixed_buffered_n(char* _First, char* const if (_Last - _First < static_cast(__precision)) { return { _Last, errc::value_too_large }; } - _CSTD memset(_First, '0', __precision); + _Fill_string_zero(_First, __precision); _First += __precision; } return { _First, errc{} }; @@ -919,11 +944,11 @@ _NODISCARD inline to_chars_result __d2exp_buffered_n(char* _First, char* const _ if (__exp >= 100) { const int32_t __c = __exp % 10; - _CSTD memcpy(_First, __DIGIT_TABLE + 2 * (__exp / 10), 2); + _CSTD memcpy(_First, __DIGIT_TABLE + 2 * (__exp / 10), 2); _First[2] = static_cast('0' + __c); _First += 3; } else { - _CSTD memcpy(_First, __DIGIT_TABLE + 2 * __exp, 2); + _CSTD memcpy(_First, __DIGIT_TABLE + 2 * __exp, 2); _First += 2; } @@ -1175,7 +1200,8 @@ _NODISCARD inline __floating_decimal_32 __f2d(const uint32_t __ieeeMantissa, con return __fd; } -_NODISCARD inline to_chars_result _Large_integer_to_chars(char* const _First, char* const _Last, +template +_NODISCARD inline pair<_CharT*, errc> _Large_integer_to_chars(_CharT* const _First, _CharT* const _Last, const uint32_t _Mantissa2, const int32_t _Exponent2) { // Print the integer _Mantissa2 * 2^_Exponent2 exactly. @@ -1283,7 +1309,7 @@ _NODISCARD inline to_chars_result _Large_integer_to_chars(char* const _First, ch return { _Last, errc::value_too_large }; } - char* _Result = _First; + _CharT* _Result = _First; // Print _Data[0]. While it's up to 10 digits, // which is more than Ryu generates, the code below can handle this. @@ -1299,7 +1325,8 @@ _NODISCARD inline to_chars_result _Large_integer_to_chars(char* const _First, ch return { _Result, errc{} }; } -_NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _Last, const __floating_decimal_32 __v, +template +_NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _Last, const __floating_decimal_32 __v, chars_format _Fmt, const uint32_t __ieeeMantissa, const uint32_t __ieeeExponent) { // Step 5: Print the decimal representation. uint32_t __output = __v.__mantissa; @@ -1385,7 +1412,7 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La return { _Last, errc::value_too_large }; } - char* _Mid; + _CharT* _Mid; if (_Ryu_exponent > 0) { // case "172900" bool _Can_use_ryu; @@ -1448,35 +1475,35 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(_Mid -= 2, __c0); + _Copy_digits_from_table(_Mid -= 2, __c1); } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(_Mid -= 2, __c); } if (__output >= 10) { const uint32_t __c = __output << 1; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(_Mid -= 2, __c); } else { - *--_Mid = static_cast('0' + __output); + *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output); } if (_Ryu_exponent > 0) { // case "172900" with _Can_use_ryu // Performance note: it might be more efficient to do this immediately after setting _Mid. - _CSTD memset(_First + __olength, '0', static_cast(_Ryu_exponent)); + _Fill_string_zero(_First + __olength, static_cast(_Ryu_exponent)); } else if (_Ryu_exponent == 0) { // case "1729" // Done! } else if (_Whole_digits > 0) { // case "17.29" // Performance note: moving digits might not be optimal. - _CSTD memmove(_First, _First + 1, static_cast(_Whole_digits)); + _CSTD memmove(_First, _First + 1, static_cast(_Whole_digits) * sizeof(_CharT)); _First[_Whole_digits] = '.'; } else { // case "0.001729" // Performance note: a larger memset() followed by overwriting '.' might be more efficient. - _First[0] = '0'; - _First[1] = '.'; - _CSTD memset(_First + 2, '0', static_cast(-_Whole_digits)); + _First[0] = _WIDEN(_CharT, '0'); + _First[1] = _WIDEN(_CharT, '.'); + _Fill_string_zero(_First + 2, static_cast(-_Whole_digits)); } return { _First + _Total_fixed_length, errc{} }; @@ -1487,7 +1514,7 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La if (_Last - _First < static_cast(_Total_scientific_length)) { return { _Last, errc::value_too_large }; } - char* const __result = _First; + _CharT* const __result = _First; // Print the decimal digits. uint32_t __i = 0; @@ -1500,49 +1527,53 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(__result + __olength - __i - 1, __c0); + _Copy_digits_from_table(__result + __olength - __i - 3, __c1); __i += 4; } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(__result + __olength - __i - 1, __c); __i += 2; } if (__output >= 10) { const uint32_t __c = __output << 1; // We can't use memcpy here: the decimal dot goes between these two digits. - __result[2] = __DIGIT_TABLE[__c + 1]; - __result[0] = __DIGIT_TABLE[__c]; + __result[2] = __DIGIT_TABLE<_CharT>[__c + 1]; + __result[0] = __DIGIT_TABLE<_CharT>[__c]; } else { - __result[0] = static_cast('0' + __output); + __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output); } // Print decimal point if needed. uint32_t __index; if (__olength > 1) { - __result[1] = '.'; + __result[1] = _WIDEN(_CharT, '.'); __index = __olength + 1; } else { __index = 1; } // Print the exponent. - __result[__index++] = 'e'; + __result[__index++] = _WIDEN(_CharT, 'e'); if (_Scientific_exponent < 0) { - __result[__index++] = '-'; + __result[__index++] = _WIDEN(_CharT, '-'); _Scientific_exponent = -_Scientific_exponent; } else { - __result[__index++] = '+'; + __result[__index++] = _WIDEN(_CharT, '+'); } - _CSTD memcpy(__result + __index, __DIGIT_TABLE + 2 * _Scientific_exponent, 2); + _Copy_digits_from_table(__result + __index, 2 * _Scientific_exponent); __index += 2; return { _First + _Total_scientific_length, errc{} }; } +_NODISCARD inline to_chars_result _Convert_to_chars_result(const pair& _Pair) { + return {_Pair.first, _Pair.second}; +} + _NODISCARD inline to_chars_result __f2s_buffered_n(char* const _First, char* const _Last, const float __f, const chars_format _Fmt) { @@ -1586,12 +1617,12 @@ _NODISCARD inline to_chars_result __f2s_buffered_n(char* const _First, char* con // (Subnormals are different, but they'll be rejected by the _Exponent2 test here, so they can be ignored.) if (_Exponent2 > 0) { - return _Large_integer_to_chars(_First, _Last, _Mantissa2, _Exponent2); + return _Convert_to_chars_result(_Large_integer_to_chars(_First, _Last, _Mantissa2, _Exponent2)); } } const __floating_decimal_32 __v = __f2d(__ieeeMantissa, __ieeeExponent); - return __to_chars(_First, _Last, __v, _Fmt, __ieeeMantissa, __ieeeExponent); + return _Convert_to_chars_result(__to_chars(_First, _Last, __v, _Fmt, __ieeeMantissa, __ieeeExponent)); } // ^^^^^^^^^^ DERIVED FROM f2s.c ^^^^^^^^^^ @@ -1897,7 +1928,8 @@ _NODISCARD inline __floating_decimal_64 __d2d(const uint64_t __ieeeMantissa, con return __fd; } -_NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _Last, const __floating_decimal_64 __v, +template +_NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _Last, const __floating_decimal_64 __v, chars_format _Fmt, const double __f) { // Step 5: Print the decimal representation. uint64_t __output = __v.__mantissa; @@ -1989,7 +2021,7 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La return { _Last, errc::value_too_large }; } - char* _Mid; + _CharT* _Mid; if (_Ryu_exponent > 0) { // case "172900" bool _Can_use_ryu; @@ -2072,10 +2104,10 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c1, 2); - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __d0, 2); - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __d1, 2); + _Copy_digits_from_table(_Mid -= 2, __c0); + _Copy_digits_from_table(_Mid -= 2, __c1); + _Copy_digits_from_table(_Mid -= 2, __d0); + _Copy_digits_from_table(_Mid -= 2, __d1); } uint32_t __output2 = static_cast(__output); while (__output2 >= 10000) { @@ -2087,35 +2119,35 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(_Mid -= 2, __c0); + _Copy_digits_from_table(_Mid -= 2, __c1); } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(_Mid -= 2, __c); } if (__output2 >= 10) { const uint32_t __c = __output2 << 1; - _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(_Mid -= 2, __c); } else { - *--_Mid = static_cast('0' + __output2); + *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output2); } if (_Ryu_exponent > 0) { // case "172900" with _Can_use_ryu // Performance note: it might be more efficient to do this immediately after setting _Mid. - _CSTD memset(_First + __olength, '0', static_cast(_Ryu_exponent)); + _Fill_string_zero(_First + __olength, static_cast(_Ryu_exponent)); } else if (_Ryu_exponent == 0) { // case "1729" // Done! } else if (_Whole_digits > 0) { // case "17.29" // Performance note: moving digits might not be optimal. - _CSTD memmove(_First, _First + 1, static_cast(_Whole_digits)); - _First[_Whole_digits] = '.'; + _CSTD memmove(_First, _First + 1, static_cast(_Whole_digits) * sizeof(_CharT)); + _First[_Whole_digits] = _WIDEN(_CharT, '.'); } else { // case "0.001729" // Performance note: a larger memset() followed by overwriting '.' might be more efficient. - _First[0] = '0'; - _First[1] = '.'; - _CSTD memset(_First + 2, '0', static_cast(-_Whole_digits)); + _First[0] = _WIDEN(_CharT, '0'); + _First[1] = _WIDEN(_CharT, '.'); + _Fill_string_zero(_First + 2, static_cast(-_Whole_digits)); } return { _First + _Total_fixed_length, errc{} }; @@ -2126,7 +2158,7 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La if (_Last - _First < static_cast(_Total_scientific_length)) { return { _Last, errc::value_too_large }; } - char* const __result = _First; + _CharT* const __result = _First; // Print the decimal digits. uint32_t __i = 0; @@ -2147,10 +2179,10 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La const uint32_t __c1 = (__c / 100) << 1; const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE + __c1, 2); - _CSTD memcpy(__result + __olength - __i - 5, __DIGIT_TABLE + __d0, 2); - _CSTD memcpy(__result + __olength - __i - 7, __DIGIT_TABLE + __d1, 2); + _Copy_digits_from_table(__result + __olength - __i - 1, __c0); + _Copy_digits_from_table(__result + __olength - __i - 3, __c1); + _Copy_digits_from_table(__result + __olength - __i - 5, __d0); + _Copy_digits_from_table(__result + __olength - __i - 7, __d1); __i += 8; } uint32_t __output2 = static_cast(__output); @@ -2163,56 +2195,58 @@ _NODISCARD inline to_chars_result __to_chars(char* const _First, char* const _La __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE + __c0, 2); - _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE + __c1, 2); + _Copy_digits_from_table(__result + __olength - __i - 1, __c0); + _Copy_digits_from_table(__result + __olength - __i - 3, __c1); __i += 4; } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE + __c, 2); + _Copy_digits_from_table(__result + __olength - __i - 1, __c); __i += 2; } if (__output2 >= 10) { const uint32_t __c = __output2 << 1; // We can't use memcpy here: the decimal dot goes between these two digits. - __result[2] = __DIGIT_TABLE[__c + 1]; - __result[0] = __DIGIT_TABLE[__c]; + __result[2] = __DIGIT_TABLE<_CharT>[__c + 1]; + __result[0] = __DIGIT_TABLE<_CharT>[__c]; } else { - __result[0] = static_cast('0' + __output2); + __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output2); } // Print decimal point if needed. uint32_t __index; if (__olength > 1) { - __result[1] = '.'; + __result[1] = _WIDEN(_CharT, '.'); __index = __olength + 1; } else { __index = 1; } // Print the exponent. - __result[__index++] = 'e'; + __result[__index++] = _WIDEN(_CharT, 'e'); if (_Scientific_exponent < 0) { - __result[__index++] = '-'; + __result[__index++] = _WIDEN(_CharT, '-'); _Scientific_exponent = -_Scientific_exponent; } else { - __result[__index++] = '+'; + __result[__index++] = _WIDEN(_CharT, '+'); } if (_Scientific_exponent >= 100) { const int32_t __c = _Scientific_exponent % 10; - _CSTD memcpy(__result + __index, __DIGIT_TABLE + 2 * (_Scientific_exponent / 10), 2); - __result[__index + 2] = static_cast('0' + __c); + _Copy_digits_from_table(__result + __index, 2 * (_Scientific_exponent / 10)); + __result[__index + 2] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __c); __index += 3; } else { - _CSTD memcpy(__result + __index, __DIGIT_TABLE + 2 * _Scientific_exponent, 2); + _Copy_digits_from_table(__result + __index, 2 * _Scientific_exponent); __index += 2; } return { _First + _Total_scientific_length, errc{} }; } +#undef _WIDEN + _NODISCARD inline bool __d2d_small_int(const uint64_t __ieeeMantissa, const uint32_t __ieeeExponent, __floating_decimal_64* const __v) { const uint64_t __m2 = (1ull << __DOUBLE_MANTISSA_BITS) | __ieeeMantissa; @@ -2296,7 +2330,7 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con // exponents here and skipping Ryu. Calling __d2fixed_buffered_n() with precision 0 is valid for all integers // (so it's okay if we call it with a Ryu-friendly value). if (_Exponent2 > 0) { - return __d2fixed_buffered_n(_First, _Last, __f, 0); + return _Convert_to_chars_result(__d2fixed_buffered_n(_First, _Last, __f, 0)); } } @@ -2320,7 +2354,7 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con __v = __d2d(__ieeeMantissa, __ieeeExponent); } - return __to_chars(_First, _Last, __v, _Fmt, __f); + return _Convert_to_chars_result(__to_chars(_First, _Last, __v, _Fmt, __f)); } // ^^^^^^^^^^ DERIVED FROM d2s.c ^^^^^^^^^^ @@ -2376,7 +2410,7 @@ _NODISCARD to_chars_result _Floating_to_chars_fixed_precision( return {_Last, errc::value_too_large}; } - return __d2fixed_buffered_n(_First, _Last, _Value, static_cast(_Precision)); + return _Convert_to_chars_result(__d2fixed_buffered_n(_First, _Last, _Value, static_cast(_Precision))); } _STD_END diff --git a/stl/inc/xcharconv_ryu_tables.h b/stl/inc/xcharconv_ryu_tables.h index 508d3479fdf..c5b5d184fd4 100644 --- a/stl/inc/xcharconv_ryu_tables.h +++ b/stl/inc/xcharconv_ryu_tables.h @@ -63,7 +63,9 @@ _STD_BEGIN // A table of all two-digit numbers. This is used to speed up decimal digit // generation by copying pairs of digits into the final output. -inline constexpr char __DIGIT_TABLE[200] = { +template inline constexpr T __DIGIT_TABLE[] = {}; + +template <> inline constexpr char __DIGIT_TABLE[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', @@ -76,6 +78,19 @@ inline constexpr char __DIGIT_TABLE[200] = { '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; +template<> inline constexpr wchar_t __DIGIT_TABLE[200] = { + L'0',L'0',L'0',L'1',L'0',L'2',L'0',L'3',L'0',L'4',L'0',L'5',L'0',L'6',L'0',L'7',L'0',L'8',L'0',L'9', + L'1',L'0',L'1',L'1',L'1',L'2',L'1',L'3',L'1',L'4',L'1',L'5',L'1',L'6',L'1',L'7',L'1',L'8',L'1',L'9', + L'2',L'0',L'2',L'1',L'2',L'2',L'2',L'3',L'2',L'4',L'2',L'5',L'2',L'6',L'2',L'7',L'2',L'8',L'2',L'9', + L'3',L'0',L'3',L'1',L'3',L'2',L'3',L'3',L'3',L'4',L'3',L'5',L'3',L'6',L'3',L'7',L'3',L'8',L'3',L'9', + L'4',L'0',L'4',L'1',L'4',L'2',L'4',L'3',L'4',L'4',L'4',L'5',L'4',L'6',L'4',L'7',L'4',L'8',L'4',L'9', + L'5',L'0',L'5',L'1',L'5',L'2',L'5',L'3',L'5',L'4',L'5',L'5',L'5',L'6',L'5',L'7',L'5',L'8',L'5',L'9', + L'6',L'0',L'6',L'1',L'6',L'2',L'6',L'3',L'6',L'4',L'6',L'5',L'6',L'6',L'6',L'7',L'6',L'8',L'6',L'9', + L'7',L'0',L'7',L'1',L'7',L'2',L'7',L'3',L'7',L'4',L'7',L'5',L'7',L'6',L'7',L'7',L'7',L'8',L'7',L'9', + L'8',L'0',L'8',L'1',L'8',L'2',L'8',L'3',L'8',L'4',L'8',L'5',L'8',L'6',L'8',L'7',L'8',L'8',L'8',L'9', + L'9',L'0',L'9',L'1',L'9',L'2',L'9',L'3',L'9',L'4',L'9',L'5',L'9',L'6',L'9',L'7',L'9',L'8',L'9',L'9' +}; + // ^^^^^^^^^^ DERIVED FROM digit_table.h ^^^^^^^^^^ // vvvvvvvvvv DERIVED FROM d2s_full_table.h vvvvvvvvvv diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index 466a8d72d7c..1d293c42ef1 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include "double_fixed_precision_to_chars_test_cases_1.hpp" #include "double_fixed_precision_to_chars_test_cases_2.hpp" @@ -1077,6 +1078,13 @@ void test_right_shift_64_bits_with_rounding() { assert(_Right_shift_with_rounding(0xffff'ffff'ffff'ffffULL, 64, false) == 1); } +// GH-1569 - Test instantiation of wchar_t helpers. +template pair std::__to_chars( + wchar_t* const, wchar_t* const, const __floating_decimal_32, chars_format, const uint32_t, const uint32_t); +template pair std::__to_chars( + wchar_t* const, wchar_t* const, const __floating_decimal_64, chars_format, const double); +template pair std::__d2fixed_buffered_n(wchar_t*, wchar_t* const, const double, const uint32_t); + int main(int argc, char** argv) { const auto start = chrono::steady_clock::now(); From 2d5acb7a49008c3fa73c43741e5c914048c97f69 Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Mon, 25 Jan 2021 08:41:47 -0800 Subject: [PATCH 2/8] Fixes x86 test failures. --- stl/inc/xcharconv_ryu.h | 8 ++++---- stl/inc/xcharconv_ryu_tables.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index 4e1c24a2a1e..638c9921dc7 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -394,7 +394,7 @@ _NODISCARD inline uint32_t __mulShift_mod1e9(const uint64_t __m, const uint64_t* #define _WIDEN(_TYPE, _CHAR) (is_same_v<_TYPE,char> ? _CHAR : L##_CHAR) template -void _Copy_digits_from_table(_CharT* _Dst, ptrdiff_t _Offset) +void _Copy_digits_from_table(_CharT* _Dst, uint32_t _Offset) { _CSTD memcpy(_Dst, __DIGIT_TABLE<_CharT> + _Offset, 2 * sizeof(_CharT)); } @@ -1564,7 +1564,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __result[__index++] = _WIDEN(_CharT, '+'); } - _Copy_digits_from_table(__result + __index, 2 * _Scientific_exponent); + _Copy_digits_from_table(__result + __index, static_cast(2 * _Scientific_exponent)); __index += 2; return { _First + _Total_scientific_length, errc{} }; @@ -2234,11 +2234,11 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L if (_Scientific_exponent >= 100) { const int32_t __c = _Scientific_exponent % 10; - _Copy_digits_from_table(__result + __index, 2 * (_Scientific_exponent / 10)); + _Copy_digits_from_table(__result + __index, static_cast(2 * (_Scientific_exponent / 10))); __result[__index + 2] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __c); __index += 3; } else { - _Copy_digits_from_table(__result + __index, 2 * _Scientific_exponent); + _Copy_digits_from_table(__result + __index, static_cast(2 * _Scientific_exponent)); __index += 2; } diff --git a/stl/inc/xcharconv_ryu_tables.h b/stl/inc/xcharconv_ryu_tables.h index c5b5d184fd4..e24c77b7611 100644 --- a/stl/inc/xcharconv_ryu_tables.h +++ b/stl/inc/xcharconv_ryu_tables.h @@ -63,7 +63,7 @@ _STD_BEGIN // A table of all two-digit numbers. This is used to speed up decimal digit // generation by copying pairs of digits into the final output. -template inline constexpr T __DIGIT_TABLE[] = {}; +template inline constexpr _CharT __DIGIT_TABLE[] = {_CharT{}}; template <> inline constexpr char __DIGIT_TABLE[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', From f5edcd79c9fbb3a414302498666dab9c2b9eef7b Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Mon, 25 Jan 2021 23:01:40 -0800 Subject: [PATCH 3/8] fill_n for zero filling --- stl/inc/xcharconv_ryu.h | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index 638c9921dc7..cbdf817bc84 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -43,6 +43,7 @@ #include #include #include +#include #ifdef _M_X64 #include // for _umul128() and __shiftright128() @@ -391,7 +392,7 @@ _NODISCARD inline uint32_t __mulShift_mod1e9(const uint64_t __m, const uint64_t* #endif // ^^^ intrinsics unavailable ^^^ } -#define _WIDEN(_TYPE, _CHAR) (is_same_v<_TYPE,char> ? _CHAR : L##_CHAR) +#define _WIDEN(_TYPE, _CHAR) _STD get<_TYPE>(_STD make_pair(_CHAR, L##_CHAR)) template void _Copy_digits_from_table(_CharT* _Dst, uint32_t _Offset) @@ -461,17 +462,6 @@ inline void __append_d_digits(const uint32_t __olength, uint32_t __digits, char* } } -template -inline void _Fill_string_zero(_CharT* _Dst, size_t _Size) { - if constexpr (is_same_v<_CharT, char>) { - memset(_Dst, '0', _Size); - } else { - for (; 0 < _Size; --_Size, (void) ++_Dst) { - *_Dst = _WIDEN(_CharT, '0'); - } - } -} - template inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* const __result) { uint32_t __i = 0; @@ -489,7 +479,7 @@ inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* template inline void __append_nine_digits(uint32_t __digits, _CharT* const __result) { if (__digits == 0) { - _Fill_string_zero(__result, 9); + _STD fill_n(__result, 9, _WIDEN(_CharT, '0')); return; } @@ -541,7 +531,7 @@ _NODISCARD pair<_CharT*, errc> __d2fixed_buffered_n(_CharT* _First, _CharT* cons *_First++ = _WIDEN(_CharT, '0'); if (__precision > 0) { *_First++ = _WIDEN(_CharT, '.'); - _Fill_string_zero(_First, __precision); + _STD fill_n(_First, __precision, _WIDEN(_CharT, '0')); _First += __precision; } return { _First, errc{} }; @@ -612,14 +602,14 @@ _NODISCARD pair<_CharT*, errc> __d2fixed_buffered_n(_CharT* _First, _CharT* cons if (_Last - _First < static_cast(__precision)) { return { _Last, errc::value_too_large }; } - _Fill_string_zero(_First, __precision); + _STD fill_n(_First, __precision, _WIDEN(_CharT, '0')); _First += __precision; } else if (__i < __MIN_BLOCK_2[__idx]) { __i = __MIN_BLOCK_2[__idx]; if (_Last - _First < static_cast(9 * __i)) { return { _Last, errc::value_too_large }; } - _Fill_string_zero(_First, 9 * __i); + _STD fill_n(_First, 9 * __i, _WIDEN(_CharT, '0')); _First += 9 * __i; } for (; __i < __blocks; ++__i) { @@ -632,7 +622,7 @@ _NODISCARD pair<_CharT*, errc> __d2fixed_buffered_n(_CharT* _First, _CharT* cons if (_Last - _First < static_cast(__fill)) { return { _Last, errc::value_too_large }; } - _Fill_string_zero(_First, __fill); + _STD fill_n(_First, __fill, _WIDEN(_CharT, '0')); _First += __fill; break; } @@ -706,7 +696,7 @@ _NODISCARD pair<_CharT*, errc> __d2fixed_buffered_n(_CharT* _First, _CharT* cons if (_Last - _First < static_cast(__precision)) { return { _Last, errc::value_too_large }; } - _Fill_string_zero(_First, __precision); + _STD fill_n(_First, __precision, _WIDEN(_CharT, '0')); _First += __precision; } return { _First, errc{} }; @@ -1492,7 +1482,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L if (_Ryu_exponent > 0) { // case "172900" with _Can_use_ryu // Performance note: it might be more efficient to do this immediately after setting _Mid. - _Fill_string_zero(_First + __olength, static_cast(_Ryu_exponent)); + _STD fill_n(_First + __olength, _Ryu_exponent, _WIDEN(_CharT, '0')); } else if (_Ryu_exponent == 0) { // case "1729" // Done! } else if (_Whole_digits > 0) { // case "17.29" @@ -1503,7 +1493,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L // Performance note: a larger memset() followed by overwriting '.' might be more efficient. _First[0] = _WIDEN(_CharT, '0'); _First[1] = _WIDEN(_CharT, '.'); - _Fill_string_zero(_First + 2, static_cast(-_Whole_digits)); + _STD fill_n(_First + 2, -_Whole_digits, _WIDEN(_CharT, '0')); } return { _First + _Total_fixed_length, errc{} }; @@ -2136,7 +2126,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L if (_Ryu_exponent > 0) { // case "172900" with _Can_use_ryu // Performance note: it might be more efficient to do this immediately after setting _Mid. - _Fill_string_zero(_First + __olength, static_cast(_Ryu_exponent)); + _STD fill_n(_First + __olength, _Ryu_exponent, _WIDEN(_CharT, '0')); } else if (_Ryu_exponent == 0) { // case "1729" // Done! } else if (_Whole_digits > 0) { // case "17.29" @@ -2147,7 +2137,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L // Performance note: a larger memset() followed by overwriting '.' might be more efficient. _First[0] = _WIDEN(_CharT, '0'); _First[1] = _WIDEN(_CharT, '.'); - _Fill_string_zero(_First + 2, static_cast(-_Whole_digits)); + _STD fill_n(_First + 2, -_Whole_digits, _WIDEN(_CharT, '0')); } return { _First + _Total_fixed_length, errc{} }; From 23b022d9b51998bae24b8e0748aa9232c13bdec0 Mon Sep 17 00:00:00 2001 From: Matt Stephanson Date: Wed, 27 Jan 2021 22:29:11 -0800 Subject: [PATCH 4/8] code review feedback - actually call wide Ryu functions - Widen __[df]2s_buffered_n - Don't wrap memcpy calls. - Use ternary operator and cast for static widen. --- stl/inc/xcharconv_ryu.h | 110 ++++++------- tests/std/tests/P0067R5_charconv/test.cpp | 43 ++++++ tests/std/tests/P0067R5_charconv/test.hpp | 12 ++ .../P0067R5_charconv/wchar_test_cases.hpp | 144 ++++++++++++++++++ 4 files changed, 256 insertions(+), 53 deletions(-) create mode 100644 tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index cbdf817bc84..a3dc16f7c6c 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -392,13 +392,7 @@ _NODISCARD inline uint32_t __mulShift_mod1e9(const uint64_t __m, const uint64_t* #endif // ^^^ intrinsics unavailable ^^^ } -#define _WIDEN(_TYPE, _CHAR) _STD get<_TYPE>(_STD make_pair(_CHAR, L##_CHAR)) - -template -void _Copy_digits_from_table(_CharT* _Dst, uint32_t _Offset) -{ - _CSTD memcpy(_Dst, __DIGIT_TABLE<_CharT> + _Offset, 2 * sizeof(_CharT)); -} +#define _WIDEN(_TYPE, _CHAR) static_cast<_TYPE>(is_same_v<_TYPE, char> ? _CHAR : L##_CHAR) template inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, _CharT* const __result) { @@ -412,19 +406,19 @@ inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, _Char __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(__result + __olength - __i - 2, __c0); - _Copy_digits_from_table(__result + __olength - __i - 4, __c1); + memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 4, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__digits >= 100) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - _Copy_digits_from_table(__result + __olength - __i - 2, __c); + memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__digits >= 10) { const uint32_t __c = __digits << 1; - _Copy_digits_from_table(__result + __olength - __i - 2, __c); + memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } @@ -468,7 +462,7 @@ inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* for (; __i < __count - 1; __i += 2) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - _Copy_digits_from_table(__result + __count - __i - 2, __c); + memcpy(__result + __count - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__i < __count) { const _CharT __c = static_cast<_CharT>(_WIDEN(_CharT, '0') + (__digits % 10)); @@ -492,8 +486,8 @@ inline void __append_nine_digits(uint32_t __digits, _CharT* const __result) { __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(__result + 7 - __i, __c0); - _Copy_digits_from_table(__result + 5 - __i, __c1); + memcpy(__result + 7 - __i, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(__result + 5 - __i, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } @@ -1465,17 +1459,17 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(_Mid -= 2, __c0); - _Copy_digits_from_table(_Mid -= 2, __c1); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - _Copy_digits_from_table(_Mid -= 2, __c); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__output >= 10) { const uint32_t __c = __output << 1; - _Copy_digits_from_table(_Mid -= 2, __c); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output); } @@ -1517,14 +1511,14 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(__result + __olength - __i - 1, __c0); - _Copy_digits_from_table(__result + __olength - __i - 3, __c1); + memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - _Copy_digits_from_table(__result + __olength - __i - 1, __c); + memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__output >= 10) { @@ -1554,7 +1548,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __result[__index++] = _WIDEN(_CharT, '+'); } - _Copy_digits_from_table(__result + __index, static_cast(2 * _Scientific_exponent)); + memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); __index += 2; return { _First + _Total_scientific_length, errc{} }; @@ -1564,7 +1558,8 @@ _NODISCARD inline to_chars_result _Convert_to_chars_result(const pair +_NODISCARD pair<_CharT*, errc> __f2s_buffered_n(_CharT* const _First, _CharT* const _Last, const float __f, const chars_format _Fmt) { // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. @@ -1577,7 +1572,11 @@ _NODISCARD inline to_chars_result __f2s_buffered_n(char* const _First, char* con return { _Last, errc::value_too_large }; } - _CSTD memcpy(_First, "0e+00", 5); + if constexpr (is_same_v<_CharT,char>) { + _CSTD memcpy(_First, "0e+00", 5); + } else { + _CSTD memcpy(_First, L"0e+00", 5 * sizeof(wchar_t)); + } return { _First + 5, errc{} }; } @@ -1587,7 +1586,7 @@ _NODISCARD inline to_chars_result __f2s_buffered_n(char* const _First, char* con return { _Last, errc::value_too_large }; } - *_First = '0'; + *_First = _WIDEN(_CharT, '0'); return { _First + 1, errc{} }; } @@ -1607,12 +1606,12 @@ _NODISCARD inline to_chars_result __f2s_buffered_n(char* const _First, char* con // (Subnormals are different, but they'll be rejected by the _Exponent2 test here, so they can be ignored.) if (_Exponent2 > 0) { - return _Convert_to_chars_result(_Large_integer_to_chars(_First, _Last, _Mantissa2, _Exponent2)); + return _Large_integer_to_chars(_First, _Last, _Mantissa2, _Exponent2); } } const __floating_decimal_32 __v = __f2d(__ieeeMantissa, __ieeeExponent); - return _Convert_to_chars_result(__to_chars(_First, _Last, __v, _Fmt, __ieeeMantissa, __ieeeExponent)); + return __to_chars(_First, _Last, __v, _Fmt, __ieeeMantissa, __ieeeExponent); } // ^^^^^^^^^^ DERIVED FROM f2s.c ^^^^^^^^^^ @@ -2094,10 +2093,10 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - _Copy_digits_from_table(_Mid -= 2, __c0); - _Copy_digits_from_table(_Mid -= 2, __c1); - _Copy_digits_from_table(_Mid -= 2, __d0); - _Copy_digits_from_table(_Mid -= 2, __d1); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); } uint32_t __output2 = static_cast(__output); while (__output2 >= 10000) { @@ -2109,17 +2108,17 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(_Mid -= 2, __c0); - _Copy_digits_from_table(_Mid -= 2, __c1); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - _Copy_digits_from_table(_Mid -= 2, __c); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__output2 >= 10) { const uint32_t __c = __output2 << 1; - _Copy_digits_from_table(_Mid -= 2, __c); + memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output2); } @@ -2169,10 +2168,10 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L const uint32_t __c1 = (__c / 100) << 1; const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - _Copy_digits_from_table(__result + __olength - __i - 1, __c0); - _Copy_digits_from_table(__result + __olength - __i - 3, __c1); - _Copy_digits_from_table(__result + __olength - __i - 5, __d0); - _Copy_digits_from_table(__result + __olength - __i - 7, __d1); + memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 5, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 7, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); __i += 8; } uint32_t __output2 = static_cast(__output); @@ -2185,14 +2184,14 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - _Copy_digits_from_table(__result + __olength - __i - 1, __c0); - _Copy_digits_from_table(__result + __olength - __i - 3, __c1); + memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - _Copy_digits_from_table(__result + __olength - __i - 1, __c); + memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__output2 >= 10) { @@ -2224,19 +2223,17 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L if (_Scientific_exponent >= 100) { const int32_t __c = _Scientific_exponent % 10; - _Copy_digits_from_table(__result + __index, static_cast(2 * (_Scientific_exponent / 10))); + memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * (_Scientific_exponent / 10), 2 * sizeof(_CharT)); __result[__index + 2] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __c); __index += 3; } else { - _Copy_digits_from_table(__result + __index, static_cast(2 * _Scientific_exponent)); + memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); __index += 2; } return { _First + _Total_scientific_length, errc{} }; } -#undef _WIDEN - _NODISCARD inline bool __d2d_small_int(const uint64_t __ieeeMantissa, const uint32_t __ieeeExponent, __floating_decimal_64* const __v) { const uint64_t __m2 = (1ull << __DOUBLE_MANTISSA_BITS) | __ieeeMantissa; @@ -2269,7 +2266,8 @@ _NODISCARD inline bool __d2d_small_int(const uint64_t __ieeeMantissa, const uint return true; } -_NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* const _Last, const double __f, +template +_NODISCARD pair<_CharT*, errc> __d2s_buffered_n(_CharT* const _First, _CharT* const _Last, const double __f, const chars_format _Fmt) { // Step 1: Decode the floating-point number, and unify normalized and subnormal cases. @@ -2282,7 +2280,11 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con return { _Last, errc::value_too_large }; } - _CSTD memcpy(_First, "0e+00", 5); + if constexpr (is_same_v<_CharT,char>) { + _CSTD memcpy(_First, "0e+00", 5); + } else { + _CSTD memcpy(_First, L"0e+00", 5 * sizeof(wchar_t)); + } return { _First + 5, errc{} }; } @@ -2292,7 +2294,7 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con return { _Last, errc::value_too_large }; } - *_First = '0'; + *_First = _WIDEN(_CharT, '0'); return { _First + 1, errc{} }; } @@ -2320,7 +2322,7 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con // exponents here and skipping Ryu. Calling __d2fixed_buffered_n() with precision 0 is valid for all integers // (so it's okay if we call it with a Ryu-friendly value). if (_Exponent2 > 0) { - return _Convert_to_chars_result(__d2fixed_buffered_n(_First, _Last, __f, 0)); + return __d2fixed_buffered_n(_First, _Last, __f, 0); } } @@ -2344,7 +2346,7 @@ _NODISCARD inline to_chars_result __d2s_buffered_n(char* const _First, char* con __v = __d2d(__ieeeMantissa, __ieeeExponent); } - return _Convert_to_chars_result(__to_chars(_First, _Last, __v, _Fmt, __f)); + return __to_chars(_First, _Last, __v, _Fmt, __f); } // ^^^^^^^^^^ DERIVED FROM d2s.c ^^^^^^^^^^ @@ -2355,9 +2357,9 @@ template _NODISCARD to_chars_result _Floating_to_chars_ryu( char* const _First, char* const _Last, const _Floating _Value, const chars_format _Fmt) noexcept { if constexpr (is_same_v<_Floating, float>) { - return __f2s_buffered_n(_First, _Last, _Value, _Fmt); + return _Convert_to_chars_result(__f2s_buffered_n(_First, _Last, _Value, _Fmt)); } else { - return __d2s_buffered_n(_First, _Last, _Value, _Fmt); + return _Convert_to_chars_result(__d2s_buffered_n(_First, _Last, _Value, _Fmt)); } } @@ -2405,6 +2407,8 @@ _NODISCARD to_chars_result _Floating_to_chars_fixed_precision( _STD_END +#undef _WIDEN + #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index 1d293c42ef1..dc176a90ed4 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -45,6 +45,7 @@ #include "float_hex_precision_to_chars_test_cases.hpp" #include "float_scientific_precision_to_chars_test_cases.hpp" #include "float_to_chars_test_cases.hpp" +#include "wchar_test_cases.hpp" #include using namespace std; @@ -1078,6 +1079,46 @@ void test_right_shift_64_bits_with_rounding() { assert(_Right_shift_with_rounding(0xffff'ffff'ffff'ffffULL, 64, false) == 1); } +void wchar_tests() { + static_assert(sizeof(__DIGIT_TABLE) == sizeof(__DIGIT_TABLE) / sizeof(wchar_t)); + auto& fac = use_facet>(locale{}); + for (size_t i = 0; i < sizeof(__DIGIT_TABLE); ++i) { + assert(fac.widen(__DIGIT_TABLE[i]) == __DIGIT_TABLE[i]); + } + + wchar_t buffer[32]; + for (const auto& t : double_to_wide_test_cases) { + auto result = __d2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); + const wstring_view sv(t.correct); + assert(equal(buffer, result.first, sv.begin(), sv.end())); + } + + for (const auto& t : float_to_wide_test_cases) { + auto result = __f2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); + const wstring_view sv(t.correct); + assert(equal(buffer, result.first, sv.begin(), sv.end())); + } + + wchar_t correct_lo[] = L"0.0001020304"; + wchar_t correct_hi[] = L"0.0506070809"; + double val_lo = 0.0001020304; + double val_hi = 0.0506070809; + for (int i = 0; i < 10; ++i) { + auto result = __d2fixed_buffered_n(begin(buffer), end(buffer), val_lo, 10); + assert(equal(buffer, result.first, correct_lo)); + + result = __d2fixed_buffered_n(begin(buffer), end(buffer), val_hi, 10); + assert(equal(buffer, result.first, correct_hi)); + + val_lo += 0.1010101010; + val_hi += 0.1010101010; + for (int j = 2; j <= 10; j += 2) { + ++correct_lo[j]; + ++correct_hi[j]; + } + } +} + // GH-1569 - Test instantiation of wchar_t helpers. template pair std::__to_chars( wchar_t* const, wchar_t* const, const __floating_decimal_32, chars_format, const uint32_t, const uint32_t); @@ -1098,6 +1139,8 @@ int main(int argc, char** argv) { test_right_shift_64_bits_with_rounding(); + wchar_tests(); + const auto finish = chrono::steady_clock::now(); const long long ms = chrono::duration_cast(finish - start).count(); diff --git a/tests/std/tests/P0067R5_charconv/test.hpp b/tests/std/tests/P0067R5_charconv/test.hpp index b20c766395e..bf49464ff4c 100644 --- a/tests/std/tests/P0067R5_charconv/test.hpp +++ b/tests/std/tests/P0067R5_charconv/test.hpp @@ -31,6 +31,12 @@ struct FloatToCharsTestCase { const char* correct; }; +struct FloatToWideTestCase { + float value; + chars_format fmt; + const wchar_t* correct; +}; + struct FloatPrecisionToCharsTestCase { float value; chars_format fmt; @@ -52,6 +58,12 @@ struct DoubleToCharsTestCase { const char* correct; }; +struct DoubleToWideTestCase { + double value; + chars_format fmt; + const wchar_t* correct; +}; + struct DoublePrecisionToCharsTestCase { double value; chars_format fmt; diff --git a/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp new file mode 100644 index 00000000000..25c81e44714 --- /dev/null +++ b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#pragma once + +#include + +#include "test.hpp" +using namespace std; + +// The wchar_t machinery is currently limited to a subset of the Ryu code. It is known to not handle: negative numbers, +// inifnity, NaN, or hex formatting. + +inline constexpr DoubleToWideTestCase double_to_wide_test_cases[] = { + // Test special cases (zero, inf, nan) and an ordinary case. Also test negative signs. + {0.0, chars_format::scientific, L"0e+00"}, + //{-0.0, chars_format::scientific, L"-0e+00"}, + //{double_inf, chars_format::scientific, L"inf"}, + //{-double_inf, chars_format::scientific, L"-inf"}, + //{double_nan, chars_format::scientific, L"nan"}, + //{-double_nan, chars_format::scientific, L"-nan(ind)"}, + //{double_nan_payload, chars_format::scientific, L"nan"}, + //{-double_nan_payload, chars_format::scientific, L"-nan"}, + {2.018, chars_format::scientific, L"2.018e+00"}, + //{-2.018, chars_format::scientific, L"-2.018e+00"}, + {0.2018, chars_format::scientific, L"2.018e-01"}, + //{-0.2018, chars_format::scientific, L"-2.018e-01"}, + + // Ditto for fixed, which doesn't emit exponents. + {0.0, chars_format::fixed, L"0"}, + //{-0.0, chars_format::fixed, L"-0"}, + //{double_inf, chars_format::fixed, L"inf"}, + //{-double_inf, chars_format::fixed, L"-inf"}, + //{double_nan, chars_format::fixed, L"nan"}, + //{-double_nan, chars_format::fixed, L"-nan(ind)"}, + //{double_nan_payload, chars_format::fixed, L"nan"}, + //{-double_nan_payload, chars_format::fixed, L"-nan"}, + {2.018, chars_format::fixed, L"2.018"}, + //{-2.018, chars_format::fixed, L"-2.018"}, + + // Ditto for general, which selects fixed for the scientific exponent 0. + {0.0, chars_format::general, L"0"}, + //{-0.0, chars_format::general, L"-0"}, + //{double_inf, chars_format::general, L"inf"}, + //{-double_inf, chars_format::general, L"-inf"}, + //{double_nan, chars_format::general, L"nan"}, + //{-double_nan, chars_format::general, L"-nan(ind)"}, + //{double_nan_payload, chars_format::general, L"nan"}, + //{-double_nan_payload, chars_format::general, L"-nan"}, + {2.018, chars_format::general, L"2.018"}, + //{-2.018, chars_format::general, L"-2.018"}, + + // Ditto for plain, which selects fixed because it's shorter for these values. + {0.0, chars_format{}, L"0"}, + //{-0.0, chars_format{}, L"-0"}, + //{double_inf, chars_format{}, L"inf"}, + //{-double_inf, chars_format{}, L"-inf"}, + //{double_nan, chars_format{}, L"nan"}, + //{-double_nan, chars_format{}, L"-nan(ind)"}, + //{double_nan_payload, chars_format{}, L"nan"}, + //{-double_nan_payload, chars_format{}, L"-nan"}, + {2.018, chars_format{}, L"2.018"}, + //{-2.018, chars_format{}, L"-2.018"}, + + // Ditto for hex. + //{0.0, chars_format::hex, L"0p+0"}, + //{-0.0, chars_format::hex, L"-0p+0"}, + //{double_inf, chars_format::hex, L"inf"}, + //{-double_inf, chars_format::hex, L"-inf"}, + //{double_nan, chars_format::hex, L"nan"}, + //{-double_nan, chars_format::hex, L"-nan(ind)"}, + //{double_nan_payload, chars_format::hex, L"nan"}, + //{-double_nan_payload, chars_format::hex, L"-nan"}, + //{0x1.729p+0, chars_format::hex, L"1.729p+0"}, + //{-0x1.729p+0, chars_format::hex, L"-1.729p+0"}, + //{0x1.729p-1, chars_format::hex, L"1.729p-1"}, + //{-0x1.729p-1, chars_format::hex, L"-1.729p-1"}, +}; + +inline constexpr FloatToWideTestCase float_to_wide_test_cases[] = { + // Test special cases (zero, inf, nan) and an ordinary case. Also test negative signs. + {0.0f, chars_format::scientific, L"0e+00"}, + //{-0.0f, chars_format::scientific, L"-0e+00"}, + //{float_inf, chars_format::scientific, L"inf"}, + //{-float_inf, chars_format::scientific, L"-inf"}, + //{float_nan, chars_format::scientific, L"nan"}, + //{-float_nan, chars_format::scientific, L"-nan(ind)"}, + //{float_nan_payload, chars_format::scientific, L"nan"}, + //{-float_nan_payload, chars_format::scientific, L"-nan"}, + {2.018f, chars_format::scientific, L"2.018e+00"}, + //{-2.018f, chars_format::scientific, L"-2.018e+00"}, + {0.2018f, chars_format::scientific, L"2.018e-01"}, + //{-0.2018f, chars_format::scientific, L"-2.018e-01"}, + + // Ditto for fixed, which doesn't emit exponents. + {0.0f, chars_format::fixed, L"0"}, + //{-0.0f, chars_format::fixed, L"-0"}, + //{float_inf, chars_format::fixed, L"inf"}, + //{-float_inf, chars_format::fixed, L"-inf"}, + //{float_nan, chars_format::fixed, L"nan"}, + //{-float_nan, chars_format::fixed, L"-nan(ind)"}, + //{float_nan_payload, chars_format::fixed, L"nan"}, + //{-float_nan_payload, chars_format::fixed, L"-nan"}, + {2.018f, chars_format::fixed, L"2.018"}, + //{-2.018f, chars_format::fixed, L"-2.018"}, + + // Ditto for general, which selects fixed for the scientific exponent 0. + {0.0f, chars_format::general, L"0"}, + //{-0.0f, chars_format::general, L"-0"}, + //{float_inf, chars_format::general, L"inf"}, + //{-float_inf, chars_format::general, L"-inf"}, + //{float_nan, chars_format::general, L"nan"}, + //{-float_nan, chars_format::general, L"-nan(ind)"}, + //{float_nan_payload, chars_format::general, L"nan"}, + //{-float_nan_payload, chars_format::general, L"-nan"}, + {2.018f, chars_format::general, L"2.018"}, + //{-2.018f, chars_format::general, L"-2.018"}, + + // Ditto for plain, which selects fixed because it's shorter for these values. + {0.0f, chars_format{}, L"0"}, + //{-0.0f, chars_format{}, L"-0"}, + //{float_inf, chars_format{}, L"inf"}, + //{-float_inf, chars_format{}, L"-inf"}, + //{float_nan, chars_format{}, L"nan"}, + //{-float_nan, chars_format{}, L"-nan(ind)"}, + //{float_nan_payload, chars_format{}, L"nan"}, + //{-float_nan_payload, chars_format{}, L"-nan"}, + {2.018f, chars_format{}, L"2.018"}, + //{-2.018f, chars_format{}, L"-2.018"}, + + // Ditto for hex. + //{0.0f, chars_format::hex, L"0p+0"}, + //{-0.0f, chars_format::hex, L"-0p+0"}, + //{float_inf, chars_format::hex, L"inf"}, + //{-float_inf, chars_format::hex, L"-inf"}, + //{float_nan, chars_format::hex, L"nan"}, + //{-float_nan, chars_format::hex, L"-nan(ind)"}, + //{float_nan_payload, chars_format::hex, L"nan"}, + //{-float_nan_payload, chars_format::hex, L"-nan"}, + //{0x1.729p+0f, chars_format::hex, L"1.729p+0"}, + //{-0x1.729p+0f, chars_format::hex, L"-1.729p+0"}, + //{0x1.729p-1f, chars_format::hex, L"1.729p-1"}, + //{-0x1.729p-1f, chars_format::hex, L"-1.729p-1"}, +}; From a124a0bd1dc37dc6afe845d51cc3228cb31f3951 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Feb 2021 21:25:52 -0800 Subject: [PATCH 5/8] Code review feedback. --- stl/inc/xcharconv_ryu.h | 6 +++--- stl/inc/xcharconv_ryu_tables.h | 2 +- tests/std/tests/P0067R5_charconv/test.cpp | 10 +++++----- tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index a3dc16f7c6c..399593e0218 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -1185,7 +1185,7 @@ _NODISCARD inline __floating_decimal_32 __f2d(const uint32_t __ieeeMantissa, con } template -_NODISCARD inline pair<_CharT*, errc> _Large_integer_to_chars(_CharT* const _First, _CharT* const _Last, +_NODISCARD pair<_CharT*, errc> _Large_integer_to_chars(_CharT* const _First, _CharT* const _Last, const uint32_t _Mantissa2, const int32_t _Exponent2) { // Print the integer _Mantissa2 * 2^_Exponent2 exactly. @@ -1572,7 +1572,7 @@ _NODISCARD pair<_CharT*, errc> __f2s_buffered_n(_CharT* const _First, _CharT* co return { _Last, errc::value_too_large }; } - if constexpr (is_same_v<_CharT,char>) { + if constexpr (is_same_v<_CharT, char>) { _CSTD memcpy(_First, "0e+00", 5); } else { _CSTD memcpy(_First, L"0e+00", 5 * sizeof(wchar_t)); @@ -2280,7 +2280,7 @@ _NODISCARD pair<_CharT*, errc> __d2s_buffered_n(_CharT* const _First, _CharT* co return { _Last, errc::value_too_large }; } - if constexpr (is_same_v<_CharT,char>) { + if constexpr (is_same_v<_CharT, char>) { _CSTD memcpy(_First, "0e+00", 5); } else { _CSTD memcpy(_First, L"0e+00", 5 * sizeof(wchar_t)); diff --git a/stl/inc/xcharconv_ryu_tables.h b/stl/inc/xcharconv_ryu_tables.h index e24c77b7611..87bc0c2b34c 100644 --- a/stl/inc/xcharconv_ryu_tables.h +++ b/stl/inc/xcharconv_ryu_tables.h @@ -78,7 +78,7 @@ template <> inline constexpr char __DIGIT_TABLE[200] = { '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; -template<> inline constexpr wchar_t __DIGIT_TABLE[200] = { +template <> inline constexpr wchar_t __DIGIT_TABLE[200] = { L'0',L'0',L'0',L'1',L'0',L'2',L'0',L'3',L'0',L'4',L'0',L'5',L'0',L'6',L'0',L'7',L'0',L'8',L'0',L'9', L'1',L'0',L'1',L'1',L'1',L'2',L'1',L'3',L'1',L'4',L'1',L'5',L'1',L'6',L'1',L'7',L'1',L'8',L'1',L'9', L'2',L'0',L'2',L'1',L'2',L'2',L'2',L'3',L'2',L'4',L'2',L'5',L'2',L'6',L'2',L'7',L'2',L'8',L'2',L'9', diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index dc176a90ed4..a46661fb6bc 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -25,7 +26,6 @@ #include #include #include -#include #include "double_fixed_precision_to_chars_test_cases_1.hpp" #include "double_fixed_precision_to_chars_test_cases_2.hpp" @@ -1080,21 +1080,21 @@ void test_right_shift_64_bits_with_rounding() { } void wchar_tests() { - static_assert(sizeof(__DIGIT_TABLE) == sizeof(__DIGIT_TABLE) / sizeof(wchar_t)); + static_assert(size(__DIGIT_TABLE) == size(__DIGIT_TABLE)); auto& fac = use_facet>(locale{}); - for (size_t i = 0; i < sizeof(__DIGIT_TABLE); ++i) { + for (size_t i = 0; i < size(__DIGIT_TABLE); ++i) { assert(fac.widen(__DIGIT_TABLE[i]) == __DIGIT_TABLE[i]); } wchar_t buffer[32]; for (const auto& t : double_to_wide_test_cases) { - auto result = __d2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); + auto result = __d2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); const wstring_view sv(t.correct); assert(equal(buffer, result.first, sv.begin(), sv.end())); } for (const auto& t : float_to_wide_test_cases) { - auto result = __f2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); + auto result = __f2s_buffered_n(begin(buffer), end(buffer), t.value, t.fmt); const wstring_view sv(t.correct); assert(equal(buffer, result.first, sv.begin(), sv.end())); } diff --git a/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp index 25c81e44714..b482ff7d75b 100644 --- a/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp +++ b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp @@ -9,7 +9,7 @@ using namespace std; // The wchar_t machinery is currently limited to a subset of the Ryu code. It is known to not handle: negative numbers, -// inifnity, NaN, or hex formatting. +// infinity, NaN, or hex formatting. inline constexpr DoubleToWideTestCase double_to_wide_test_cases[] = { // Test special cases (zero, inf, nan) and an ordinary case. Also test negative signs. From a1f066991071f04c712026bcbe059366049ed5a5 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Feb 2021 21:27:36 -0800 Subject: [PATCH 6/8] Restore _CSTD memcpy. --- stl/inc/xcharconv_ryu.h | 64 ++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index 399593e0218..580d1fb8bb9 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -406,19 +406,19 @@ inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, _Char __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 4, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 4, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__digits >= 100) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__digits >= 10) { const uint32_t __c = __digits << 1; - memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } @@ -462,7 +462,7 @@ inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* for (; __i < __count - 1; __i += 2) { const uint32_t __c = (__digits % 100) << 1; __digits /= 100; - memcpy(__result + __count - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __count - __i - 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__i < __count) { const _CharT __c = static_cast<_CharT>(_WIDEN(_CharT, '0') + (__digits % 10)); @@ -486,8 +486,8 @@ inline void __append_nine_digits(uint32_t __digits, _CharT* const __result) { __digits /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(__result + 7 - __i, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(__result + 5 - __i, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + 7 - __i, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + 5 - __i, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } __result[0] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __digits); } @@ -1459,17 +1459,17 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__output >= 10) { const uint32_t __c = __output << 1; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output); } @@ -1511,14 +1511,14 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__output >= 100) { const uint32_t __c = (__output % 100) << 1; __output /= 100; - memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__output >= 10) { @@ -1548,7 +1548,7 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __result[__index++] = _WIDEN(_CharT, '+'); } - memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); __index += 2; return { _First + _Total_scientific_length, errc{} }; @@ -2093,10 +2093,10 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); } uint32_t __output2 = static_cast(__output); while (__output2 >= 10000) { @@ -2108,17 +2108,17 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } if (__output2 >= 10) { const uint32_t __c = __output2 << 1; - memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(_Mid -= 2, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); } else { *--_Mid = static_cast<_CharT>(_WIDEN(_CharT, '0') + __output2); } @@ -2168,10 +2168,10 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L const uint32_t __c1 = (__c / 100) << 1; const uint32_t __d0 = (__d % 100) << 1; const uint32_t __d1 = (__d / 100) << 1; - memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 5, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 7, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 5, __DIGIT_TABLE<_CharT> + __d0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 7, __DIGIT_TABLE<_CharT> + __d1, 2 * sizeof(_CharT)); __i += 8; } uint32_t __output2 = static_cast(__output); @@ -2184,14 +2184,14 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L __output2 /= 10000; const uint32_t __c0 = (__c % 100) << 1; const uint32_t __c1 = (__c / 100) << 1; - memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); - memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c0, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 3, __DIGIT_TABLE<_CharT> + __c1, 2 * sizeof(_CharT)); __i += 4; } if (__output2 >= 100) { const uint32_t __c = (__output2 % 100) << 1; __output2 /= 100; - memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __olength - __i - 1, __DIGIT_TABLE<_CharT> + __c, 2 * sizeof(_CharT)); __i += 2; } if (__output2 >= 10) { @@ -2223,11 +2223,11 @@ _NODISCARD pair<_CharT*, errc> __to_chars(_CharT* const _First, _CharT* const _L if (_Scientific_exponent >= 100) { const int32_t __c = _Scientific_exponent % 10; - memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * (_Scientific_exponent / 10), 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * (_Scientific_exponent / 10), 2 * sizeof(_CharT)); __result[__index + 2] = static_cast<_CharT>(_WIDEN(_CharT, '0') + __c); __index += 3; } else { - memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); + _CSTD memcpy(__result + __index, __DIGIT_TABLE<_CharT> + 2 * _Scientific_exponent, 2 * sizeof(_CharT)); __index += 2; } From cf75f18475f21f447b650ba1202b01f63ba66e9b Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Feb 2021 21:39:16 -0800 Subject: [PATCH 7/8] Test digit pairs with a static table. --- tests/std/tests/P0067R5_charconv/test.cpp | 21 ++++------------- tests/std/tests/P0067R5_charconv/test.hpp | 7 ++++++ .../P0067R5_charconv/wchar_test_cases.hpp | 23 +++++++++++++++++++ 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/tests/std/tests/P0067R5_charconv/test.cpp b/tests/std/tests/P0067R5_charconv/test.cpp index a46661fb6bc..f11365572a7 100644 --- a/tests/std/tests/P0067R5_charconv/test.cpp +++ b/tests/std/tests/P0067R5_charconv/test.cpp @@ -1099,23 +1099,10 @@ void wchar_tests() { assert(equal(buffer, result.first, sv.begin(), sv.end())); } - wchar_t correct_lo[] = L"0.0001020304"; - wchar_t correct_hi[] = L"0.0506070809"; - double val_lo = 0.0001020304; - double val_hi = 0.0506070809; - for (int i = 0; i < 10; ++i) { - auto result = __d2fixed_buffered_n(begin(buffer), end(buffer), val_lo, 10); - assert(equal(buffer, result.first, correct_lo)); - - result = __d2fixed_buffered_n(begin(buffer), end(buffer), val_hi, 10); - assert(equal(buffer, result.first, correct_hi)); - - val_lo += 0.1010101010; - val_hi += 0.1010101010; - for (int j = 2; j <= 10; j += 2) { - ++correct_lo[j]; - ++correct_hi[j]; - } + for (const auto& t : wide_digit_pairs_test_cases) { + auto result = __d2fixed_buffered_n(begin(buffer), end(buffer), t.value, static_cast(t.precision)); + const wstring_view sv(t.correct); + assert(equal(buffer, result.first, sv.begin(), sv.end())); } } diff --git a/tests/std/tests/P0067R5_charconv/test.hpp b/tests/std/tests/P0067R5_charconv/test.hpp index bf49464ff4c..3d0275b9899 100644 --- a/tests/std/tests/P0067R5_charconv/test.hpp +++ b/tests/std/tests/P0067R5_charconv/test.hpp @@ -70,3 +70,10 @@ struct DoublePrecisionToCharsTestCase { int precision; const char* correct; }; + +struct DoublePrecisionToWideTestCase { + double value; + chars_format fmt; + int precision; + const wchar_t* correct; +}; diff --git a/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp index b482ff7d75b..795ac517987 100644 --- a/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp +++ b/tests/std/tests/P0067R5_charconv/wchar_test_cases.hpp @@ -11,6 +11,29 @@ using namespace std; // The wchar_t machinery is currently limited to a subset of the Ryu code. It is known to not handle: negative numbers, // infinity, NaN, or hex formatting. +inline constexpr DoublePrecisionToWideTestCase wide_digit_pairs_test_cases[] = { + {0.0001020304, chars_format::fixed, 10, L"0.0001020304"}, + {0.0506070809, chars_format::fixed, 10, L"0.0506070809"}, + {0.1011121314, chars_format::fixed, 10, L"0.1011121314"}, + {0.1516171819, chars_format::fixed, 10, L"0.1516171819"}, + {0.2021222324, chars_format::fixed, 10, L"0.2021222324"}, + {0.2526272829, chars_format::fixed, 10, L"0.2526272829"}, + {0.3031323334, chars_format::fixed, 10, L"0.3031323334"}, + {0.3536373839, chars_format::fixed, 10, L"0.3536373839"}, + {0.4041424344, chars_format::fixed, 10, L"0.4041424344"}, + {0.4546474849, chars_format::fixed, 10, L"0.4546474849"}, + {0.5051525354, chars_format::fixed, 10, L"0.5051525354"}, + {0.5556575859, chars_format::fixed, 10, L"0.5556575859"}, + {0.6061626364, chars_format::fixed, 10, L"0.6061626364"}, + {0.6566676869, chars_format::fixed, 10, L"0.6566676869"}, + {0.7071727374, chars_format::fixed, 10, L"0.7071727374"}, + {0.7576777879, chars_format::fixed, 10, L"0.7576777879"}, + {0.8081828384, chars_format::fixed, 10, L"0.8081828384"}, + {0.8586878889, chars_format::fixed, 10, L"0.8586878889"}, + {0.9091929394, chars_format::fixed, 10, L"0.9091929394"}, + {0.9596979899, chars_format::fixed, 10, L"0.9596979899"}, +}; + inline constexpr DoubleToWideTestCase double_to_wide_test_cases[] = { // Test special cases (zero, inf, nan) and an ordinary case. Also test negative signs. {0.0, chars_format::scientific, L"0e+00"}, From 4dd106c0ea152184275ca3bcc03e98d437aba788 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 3 Feb 2021 21:57:01 -0800 Subject: [PATCH 8/8] Three more inlines. --- stl/inc/xcharconv_ryu.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stl/inc/xcharconv_ryu.h b/stl/inc/xcharconv_ryu.h index 580d1fb8bb9..e76714cbcd7 100644 --- a/stl/inc/xcharconv_ryu.h +++ b/stl/inc/xcharconv_ryu.h @@ -395,7 +395,7 @@ _NODISCARD inline uint32_t __mulShift_mod1e9(const uint64_t __m, const uint64_t* #define _WIDEN(_TYPE, _CHAR) static_cast<_TYPE>(is_same_v<_TYPE, char> ? _CHAR : L##_CHAR) template -inline void __append_n_digits(const uint32_t __olength, uint32_t __digits, _CharT* const __result) { +void __append_n_digits(const uint32_t __olength, uint32_t __digits, _CharT* const __result) { uint32_t __i = 0; while (__digits >= 10000) { #ifdef __clang__ // TRANSITION, LLVM-38217 @@ -457,7 +457,7 @@ inline void __append_d_digits(const uint32_t __olength, uint32_t __digits, char* } template -inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* const __result) { +void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* const __result) { uint32_t __i = 0; for (; __i < __count - 1; __i += 2) { const uint32_t __c = (__digits % 100) << 1; @@ -471,7 +471,7 @@ inline void __append_c_digits(const uint32_t __count, uint32_t __digits, _CharT* } template -inline void __append_nine_digits(uint32_t __digits, _CharT* const __result) { +void __append_nine_digits(uint32_t __digits, _CharT* const __result) { if (__digits == 0) { _STD fill_n(__result, 9, _WIDEN(_CharT, '0')); return;