diff --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h --- a/libcxx/include/__charconv/to_chars_base_10.h +++ b/libcxx/include/__charconv/to_chars_base_10.h @@ -10,10 +10,10 @@ #ifndef _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H #define _LIBCPP___CHARCONV_TO_CHARS_BASE_10_H +#include <__algorithm/copy_n.h> #include <__charconv/tables.h> #include <__config> #include -#include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -25,98 +25,97 @@ namespace __itoa { -template -_LIBCPP_HIDE_FROM_ABI char* __append1(char* __buffer, _Tp __value) noexcept { - *__buffer = '0' + static_cast(__value); - return __buffer + 1; +_LIBCPP_HIDE_FROM_ABI inline char* __append1(char* __first, uint32_t __value) noexcept { + *__first = '0' + static_cast(__value); + return __first + 1; } -template -_LIBCPP_HIDE_FROM_ABI char* __append2(char* __buffer, _Tp __value) noexcept { - std::memcpy(__buffer, &__table<>::__digits_base_10[(__value)*2], 2); - return __buffer + 2; +_LIBCPP_HIDE_FROM_ABI inline char* __append2(char* __first, uint32_t __value) noexcept { + return std::copy_n(&__table<>::__digits_base_10[__value * 2], 2, __first); } -template -_LIBCPP_HIDE_FROM_ABI char* __append3(char* __buffer, _Tp __value) noexcept { - return __itoa::__append2(__itoa::__append1(__buffer, (__value) / 100), (__value) % 100); +_LIBCPP_HIDE_FROM_ABI inline char* __append3(char* __first, uint32_t __value) noexcept { + return __itoa::__append2(__itoa::__append1(__first, __value / 100), __value % 100); } -template -_LIBCPP_HIDE_FROM_ABI char* __append4(char* __buffer, _Tp __value) noexcept { - return __itoa::__append2(__itoa::__append2(__buffer, (__value) / 100), (__value) % 100); +_LIBCPP_HIDE_FROM_ABI inline char* __append4(char* __first, uint32_t __value) noexcept { + return __itoa::__append2(__itoa::__append2(__first, __value / 100), __value % 100); } -template -_LIBCPP_HIDE_FROM_ABI char* __append2_no_zeros(char* __buffer, _Tp __value) noexcept { - if (__value < 10) - return __itoa::__append1(__buffer, __value); - else - return __itoa::__append2(__buffer, __value); +_LIBCPP_HIDE_FROM_ABI inline char* __append5(char* __first, uint32_t __value) noexcept { + return __itoa::__append4(__itoa::__append1(__first, __value / 10000), __value % 10000); } -template -_LIBCPP_HIDE_FROM_ABI char* __append4_no_zeros(char* __buffer, _Tp __value) noexcept { - if (__value < 100) - return __itoa::__append2_no_zeros(__buffer, __value); - else if (__value < 1000) - return __itoa::__append3(__buffer, __value); - else - return __itoa::__append4(__buffer, __value); +_LIBCPP_HIDE_FROM_ABI inline char* __append6(char* __first, uint32_t __value) noexcept { + return __itoa::__append4(__itoa::__append2(__first, __value / 10000), __value % 10000); +} + +_LIBCPP_HIDE_FROM_ABI inline char* __append7(char* __first, uint32_t __value) noexcept { + return __itoa::__append6(__itoa::__append1(__first, __value / 1000000), __value % 1000000); } +_LIBCPP_HIDE_FROM_ABI inline char* __append8(char* __first, uint32_t __value) noexcept { + return __itoa::__append6(__itoa::__append2(__first, __value / 1000000), __value % 1000000); +} + +_LIBCPP_HIDE_FROM_ABI inline char* __append9(char* __first, uint32_t __value) noexcept { + return __itoa::__append8(__itoa::__append1(__first, __value / 100000000), __value % 100000000); +} + +// This function is used for uint32_t and uint64_t. template -_LIBCPP_HIDE_FROM_ABI char* __append8_no_zeros(char* __buffer, _Tp __value) noexcept { - if (__value < 10000) - __buffer = __itoa::__append4_no_zeros(__buffer, __value); - else { - __buffer = __itoa::__append4_no_zeros(__buffer, __value / 10000); - __buffer = __itoa::__append4(__buffer, __value % 10000); - } - return __buffer; +_LIBCPP_HIDE_FROM_ABI char* __append10(char* __first, _Tp __value) noexcept { + return __itoa::__append8(__itoa::__append2(__first, static_cast(__value / 100000000)), + static_cast(__value % 100000000)); } -_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(uint32_t __value, char* __buffer) noexcept { - if (__value < 100000000) - __buffer = __itoa::__append8_no_zeros(__buffer, __value); - else { - // __value = aabbbbcccc in decimal - const uint32_t __a = __value / 100000000; // 1 to 42 - __value %= 100000000; - - __buffer = __itoa::__append2_no_zeros(__buffer, __a); - __buffer = __itoa::__append4(__buffer, __value / 10000); - __buffer = __itoa::__append4(__buffer, __value % 10000); +_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u32(char* __first, uint32_t __value) noexcept { + if (__value < 1000000) { + if (__value < 10000) { + if (__value < 100) { + // 0 <= __value < 100 + if (__value < 10) + return __itoa::__append1(__first, __value); + return __itoa::__append2(__first, __value); + } + // 100 <= __value < 10'000 + if (__value < 1000) + return __itoa::__append3(__first, __value); + return __itoa::__append4(__first, __value); + } + + // 10'000 <= __value < 1'000'000 + if (__value < 100000) + return __itoa::__append5(__first, __value); + return __itoa::__append6(__first, __value); } - return __buffer; + // __value => 1'000'000 + if (__value < 100000000) { + // 1'000'000 <= __value < 100'000'000 + if (__value < 10000000) + return __itoa::__append7(__first, __value); + return __itoa::__append8(__first, __value); + } + + // 100'000'000 <= __value < max + if (__value < 1000000000) + return __itoa::__append9(__first, __value); + return __itoa::__append10(__first, __value); } -_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(uint64_t __value, char* __buffer) noexcept { - if (__value < 100000000) - __buffer = __itoa::__append8_no_zeros(__buffer, static_cast(__value)); - else if (__value < 10000000000000000) { - const uint32_t __v0 = static_cast(__value / 100000000); - const uint32_t __v1 = static_cast(__value % 100000000); - - __buffer = __itoa::__append8_no_zeros(__buffer, __v0); - __buffer = __itoa::__append4(__buffer, __v1 / 10000); - __buffer = __itoa::__append4(__buffer, __v1 % 10000); - } else { - const uint32_t __a = static_cast(__value / 10000000000000000); // 1 to 1844 - __value %= 10000000000000000; - - __buffer = __itoa::__append4_no_zeros(__buffer, __a); - - const uint32_t __v0 = static_cast(__value / 100000000); - const uint32_t __v1 = static_cast(__value % 100000000); - __buffer = __itoa::__append4(__buffer, __v0 / 10000); - __buffer = __itoa::__append4(__buffer, __v0 % 10000); - __buffer = __itoa::__append4(__buffer, __v1 / 10000); - __buffer = __itoa::__append4(__buffer, __v1 % 10000); - } +_LIBCPP_HIDE_FROM_ABI inline char* __base_10_u64(char* __buffer, uint64_t __value) noexcept { + if (__value <= UINT32_MAX) + return __itoa::__base_10_u32(__buffer, static_cast(__value)); - return __buffer; + // Numbers in the range UINT32_MAX <= val < 10'000'000'000 always contain 10 + // digits and are outputted after this if statement. + if (__value >= 10000000000) { + // This function properly deterimines the first non-zero leading digit. + __buffer = __itoa::__base_10_u32(__buffer, static_cast(__value / 10000000000)); + __value %= 10000000000; + } + return __itoa::__append10(__buffer, __value); } } // namespace __itoa diff --git a/libcxx/include/charconv b/libcxx/include/charconv --- a/libcxx/include/charconv +++ b/libcxx/include/charconv @@ -125,9 +125,9 @@ return __t - (__v < __table<>::__pow10_64[__t]) + 1; } - static _LIBCPP_HIDE_FROM_ABI char* __convert(_Tp __v, char* __p) + static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { - return __itoa::__base_10_u64(__v, __p); + return __itoa::__base_10_u64(__p, __v); } static _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_64)& __pow() { return __table<>::__pow10_64; } @@ -145,9 +145,9 @@ return __t - (__v < __table<>::__pow10_32[__t]) + 1; } - static _LIBCPP_HIDE_FROM_ABI char* __convert(_Tp __v, char* __p) + static _LIBCPP_HIDE_FROM_ABI char* __convert(char* __p, _Tp __v) { - return __itoa::__base_10_u32(__v, __p); + return __itoa::__base_10_u32(__p, __v); } static _LIBCPP_HIDE_FROM_ABI decltype(__table<>::__pow10_32)& __pow() { return __table<>::__pow10_32; } @@ -262,7 +262,7 @@ auto __diff = __last - __first; if (__tx::digits <= __diff || __tx::__width(__value) <= __diff) - return {__tx::__convert(__value, __first), errc(0)}; + return {__tx::__convert(__first, __value), errc(0)}; else return {__last, errc::value_too_large}; } diff --git a/libcxx/src/charconv.cpp b/libcxx/src/charconv.cpp --- a/libcxx/src/charconv.cpp +++ b/libcxx/src/charconv.cpp @@ -21,13 +21,13 @@ _LIBCPP_FUNC_VIS char* __u32toa(uint32_t value, char* buffer) noexcept { - return __base_10_u32(value, buffer); + return __base_10_u32(buffer, value); } _LIBCPP_FUNC_VIS char* __u64toa(uint64_t value, char* buffer) noexcept { - return __base_10_u64(value, buffer); + return __base_10_u64(buffer, value); } } // namespace __itoa