From 9b350bcdcbca2f97f45c3477401d94e94bef3ab8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 18 Jan 2023 13:34:33 -0800 Subject: [PATCH] Simplify 32-bit impl and improve logic --- .../charconv/detail/integer_search_trees.hpp | 7 ++++++- include/boost/charconv/to_chars.hpp | 21 +++++++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/include/boost/charconv/detail/integer_search_trees.hpp b/include/boost/charconv/detail/integer_search_trees.hpp index 3ef1ff4..30250de 100644 --- a/include/boost/charconv/detail/integer_search_trees.hpp +++ b/include/boost/charconv/detail/integer_search_trees.hpp @@ -13,6 +13,8 @@ #include #include +namespace boost { namespace charconv { namespace detail { + // Generic solution template BOOST_CXX14_CONSTEXPR int num_digits(T x) noexcept @@ -169,7 +171,8 @@ BOOST_CXX14_CONSTEXPR int num_digits(unsigned __int128 x) noexcept { // There is not literal for unsigned __int128 so we need to calculate them using the max value of the // std::uint64_t powers of 10 - constexpr unsigned __int128 digits_39 = static_cast(UINT64_C(10000000000000000000)) * static_cast(UINT64_C(1000000000000000000)); + constexpr unsigned __int128 digits_39 = static_cast(UINT64_C(10000000000000000000)) * + static_cast(UINT64_C(1000000000000000000)); constexpr unsigned __int128 digits_38 = digits_39 / 10; constexpr unsigned __int128 digits_37 = digits_38 / 10; constexpr unsigned __int128 digits_36 = digits_37 / 10; @@ -231,4 +234,6 @@ BOOST_CXX14_CONSTEXPR int num_digits(unsigned __int128 x) noexcept } #endif // 128-bit support +}}} // Namespace boost::charconv::detail + #endif // BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP diff --git a/include/boost/charconv/to_chars.hpp b/include/boost/charconv/to_chars.hpp index 577745b..c7048e7 100644 --- a/include/boost/charconv/to_chars.hpp +++ b/include/boost/charconv/to_chars.hpp @@ -90,10 +90,7 @@ BOOST_CXX14_CONSTEXPR char* decompose32(std::uint32_t value, char* buffer) template BOOST_CXX14_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char* last, Integer value) -{ - // decompose32 will always return 10 digits (including leading 0s) - char buffer[10] {}; - +{ if (!(first <= last)) { return {last, EINVAL}; @@ -103,16 +100,18 @@ BOOST_CXX14_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char* l // If the type is greater than 32 bits we use a binary search tree to figure out how many digits // are present and then decompose the value into two (or more) std::uint32_t of known length so that we // don't have the issue of removing leading zeros from the least significant digits - if (static_cast(value) <= (std::numeric_limits::max)()) + + // TODO: fix this logic for types that could contain values greater than std::uint32_t but don't + // and types smaller than which would overflow on casting + if (std::numeric_limits::digits <= std::numeric_limits::digits || + value <= static_cast((std::numeric_limits::max)())) { + char buffer[10] {}; + const auto num_sig_chars = num_digits(value); + decompose32(value, buffer); - std::size_t i {}; - while (buffer[i] == '0') - { - ++i; - } - std::memcpy(first, buffer + i, sizeof(buffer) - i); + std::memcpy(first, buffer + (sizeof(buffer) - num_sig_chars), num_sig_chars); } else if (static_cast(value) <= (std::numeric_limits::max)()) {