diff --git a/include/boost/charconv/config.hpp b/include/boost/charconv/config.hpp index 454cc80..1eaeae7 100644 --- a/include/boost/charconv/config.hpp +++ b/include/boost/charconv/config.hpp @@ -7,6 +7,7 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include // This header implements separate compilation features as described in // http://www.boost.org/more/separate_compilation.html @@ -46,8 +47,23 @@ #endif // Use 128 bit integers and supress warnings for using extensions -#if defined(BOOST_HAS_INT128) && !defined(__STRICT_ANSI__) +#if defined(BOOST_HAS_INT128) # define BOOST_CHARCONV_HAS_INT128 +# define BOOST_CHARCONV_INT128_MAX (boost::int128_type)(((boost::uint128_type) 1 << 127) - 1) +# define BOOST_CHARCONV_INT128_MIN (-BOOST_CHARCONV_INT128_MAX - 1) +# define BOOST_CHARCONV_UINT128_MAX ((2 * (boost::uint128_type) BOOST_CHARCONV_INT128_MAX) + 1) +#endif + +#ifndef BOOST_NO_CXX14_CONSTEXPR +# define BOOST_CHARCONV_CXX14_CONSTEXPR BOOST_CXX14_CONSTEXPR +#else +# define BOOST_CHARCONV_CXX14_CONSTEXPR inline +#endif + +#if defined(__GNUC__) && __GNUC__ == 5 +# define BOOST_CHARCONV_GCC5_CONSTEXPR inline +#else +# define BOOST_CHARCONV_GCC5_CONSTEXPR BOOST_CHARCONV_CXX14_CONSTEXPR #endif #endif // BOOST_CHARCONV_CONFIG_HPP_INCLUDED diff --git a/include/boost/charconv/detail/integer_search_trees.hpp b/include/boost/charconv/detail/integer_search_trees.hpp index ebe8398..7123acf 100644 --- a/include/boost/charconv/detail/integer_search_trees.hpp +++ b/include/boost/charconv/detail/integer_search_trees.hpp @@ -167,30 +167,30 @@ static constexpr std::array powers_of_10 = // Assume that if someone is using 128 bit ints they are favoring the top end of the range // Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits) -BOOST_CXX14_CONSTEXPR inline int num_digits(unsigned __int128 x) noexcept +BOOST_CXX14_CONSTEXPR inline int num_digits(boost::uint128_type x) noexcept { - // There is not literal for unsigned __int128 so we need to calculate them using the max value of the + // There is not literal for boost::uint128_type 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_38 = digits_39 / 10; - constexpr unsigned __int128 digits_37 = digits_38 / 10; - constexpr unsigned __int128 digits_36 = digits_37 / 10; - constexpr unsigned __int128 digits_35 = digits_36 / 10; - constexpr unsigned __int128 digits_34 = digits_35 / 10; - constexpr unsigned __int128 digits_33 = digits_34 / 10; - constexpr unsigned __int128 digits_32 = digits_33 / 10; - constexpr unsigned __int128 digits_31 = digits_32 / 10; - constexpr unsigned __int128 digits_30 = digits_31 / 10; - constexpr unsigned __int128 digits_29 = digits_30 / 10; - constexpr unsigned __int128 digits_28 = digits_29 / 10; - constexpr unsigned __int128 digits_27 = digits_28 / 10; - constexpr unsigned __int128 digits_26 = digits_27 / 10; - constexpr unsigned __int128 digits_25 = digits_26 / 10; - constexpr unsigned __int128 digits_24 = digits_25 / 10; - constexpr unsigned __int128 digits_23 = digits_24 / 10; - constexpr unsigned __int128 digits_22 = digits_23 / 10; - constexpr unsigned __int128 digits_21 = digits_22 / 10; + constexpr boost::uint128_type digits_39 = static_cast(UINT64_C(10000000000000000000)) * + static_cast(UINT64_C(1000000000000000000)); + constexpr boost::uint128_type digits_38 = digits_39 / 10; + constexpr boost::uint128_type digits_37 = digits_38 / 10; + constexpr boost::uint128_type digits_36 = digits_37 / 10; + constexpr boost::uint128_type digits_35 = digits_36 / 10; + constexpr boost::uint128_type digits_34 = digits_35 / 10; + constexpr boost::uint128_type digits_33 = digits_34 / 10; + constexpr boost::uint128_type digits_32 = digits_33 / 10; + constexpr boost::uint128_type digits_31 = digits_32 / 10; + constexpr boost::uint128_type digits_30 = digits_31 / 10; + constexpr boost::uint128_type digits_29 = digits_30 / 10; + constexpr boost::uint128_type digits_28 = digits_29 / 10; + constexpr boost::uint128_type digits_27 = digits_28 / 10; + constexpr boost::uint128_type digits_26 = digits_27 / 10; + constexpr boost::uint128_type digits_25 = digits_26 / 10; + constexpr boost::uint128_type digits_24 = digits_25 / 10; + constexpr boost::uint128_type digits_23 = digits_24 / 10; + constexpr boost::uint128_type digits_22 = digits_23 / 10; + constexpr boost::uint128_type digits_21 = digits_22 / 10; return (x > digits_39) ? 39 : (x > digits_38) ? 38 : diff --git a/include/boost/charconv/detail/memcpy.hpp b/include/boost/charconv/detail/memcpy.hpp index 7509142..8bfa50b 100644 --- a/include/boost/charconv/detail/memcpy.hpp +++ b/include/boost/charconv/detail/memcpy.hpp @@ -60,7 +60,7 @@ constexpr char* memcpy(char* dest, const char* src, std::size_t count) #else // Either not C++14 or no way of telling if we are in a constexpr context -#define BOOST_CHARCONV_CONSTEXPR +#define BOOST_CHARCONV_CONSTEXPR inline inline void* memcpy(void* dest, const void* src, std::size_t count) { diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 46b0f75..c51326d 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -68,10 +68,17 @@ constexpr unsigned char digit_from_char(char val) noexcept return uchar_values[static_cast(val)]; } -template -BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept +#ifdef BOOST_MSVC +# pragma warning(push) +# pragma warning(disable: 4146) +#elif defined(__GNUC__) && (__GNUC__ == 5 || __GNUC__ == 6) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Woverflow" +#endif + +template +BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept { - using Unsigned_Integer = typename std::make_unsigned::type; Unsigned_Integer result = 0; Unsigned_Integer overflow_value = 0; Unsigned_Integer max_digit = 0; @@ -83,11 +90,18 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl return {first, EINVAL}; } + Unsigned_Integer unsigned_base = static_cast(base); + // Strip sign if the type is signed // Negative sign will be appended at the end of parsing BOOST_ATTRIBUTE_UNUSED bool is_negative = false; auto next = first; + + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same::value || std::is_signed::value) + #else BOOST_IF_CONSTEXPR (std::is_signed::value) + #endif { if (next != last) { @@ -102,8 +116,18 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl } } - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same::value) + { + overflow_value = BOOST_CHARCONV_INT128_MAX; + max_digit = BOOST_CHARCONV_INT128_MAX; + } + else + #endif + { + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + } if (is_negative) { @@ -125,12 +149,33 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl } } - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same::value) + { + overflow_value = BOOST_CHARCONV_UINT128_MAX; + max_digit = BOOST_CHARCONV_UINT128_MAX; + } + else + #endif + { + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + } } - overflow_value /= static_cast(base); - max_digit %= base; + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same::value) + { + overflow_value /= unsigned_base; + max_digit %= unsigned_base; + overflow_value *= 2; // Overflow value would cause INT128_MIN in non-base10 to fail + } + else + #endif + { + overflow_value /= unsigned_base; + max_digit %= unsigned_base; + } // If the only character was a sign abort now if (next == last) @@ -141,16 +186,16 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl bool overflowed = false; while (next != last) { - auto current_digit = digit_from_char(*next); + const unsigned char current_digit = digit_from_char(*next); - if (current_digit >= base) + if (current_digit >= unsigned_base) { break; } if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) { - result = static_cast(result * base + current_digit); + result = static_cast(result * unsigned_base + current_digit); } else { @@ -169,43 +214,104 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl } value = static_cast(result); + #ifdef BOOST_CHARCONV_HAS_INT128 + BOOST_IF_CONSTEXPR (std::is_same::value || std::is_signed::value) + #else BOOST_IF_CONSTEXPR (std::is_signed::value) + #endif { if (is_negative) { - value = apply_sign(value); + value = -(static_cast(value)); } } return {next, 0}; } -} // Namespace detail - -// GCC 5 does not support constexpr comparison of const char* -#if defined(__GNUC__) && __GNUC__ == 5 -template ::value, bool>::type = true> -inline from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept -{ - return detail::from_chars_integer_impl(first, last, value, base); -} - -template<> -inline from_chars_result from_chars(const char* first, const char* last, bool& value, int base) noexcept = delete; - -#else +#ifdef BOOST_MSVC +# pragma warning(pop) +#elif defined(__GNUC__) && (__GNUC__ == 5 || __GNUC__ == 6) +# pragma GCC diagnostic pop +#endif // Only from_chars for integer types is constexpr (as of C++23) -template ::value, bool>::type = true> -BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept +template +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept { - return detail::from_chars_integer_impl(first, last, value, base); + using Unsigned_Integer = typename std::make_unsigned::type; + return detail::from_chars_integer_impl(first, last, value, base); } -template <> -BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, bool& value, int base) noexcept = delete; +#ifdef BOOST_HAS_INT128 +template +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars128(const char* first, const char* last, Integer& value, int base = 10) noexcept +{ + using Unsigned_Integer = boost::uint128_type; + return detail::from_chars_integer_impl(first, last, value, base); +} +#endif -#endif // GCC5 workarounds +} // Namespace detail + +// integer overloads + +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, bool& value, int base = 10) noexcept = delete; +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, signed char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10) noexcept +{ + return detail::from_chars(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, boost::int128_type& value, int base = 10) noexcept +{ + return detail::from_chars_integer_impl(first, last, value, base); +} +BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, boost::uint128_type& value, int base = 10) noexcept +{ + return detail::from_chars_integer_impl(first, last, value, base); +} +#endif // floating point overloads diff --git a/include/boost/charconv/limits.hpp b/include/boost/charconv/limits.hpp index e1bfe07..b401f28 100644 --- a/include/boost/charconv/limits.hpp +++ b/include/boost/charconv/limits.hpp @@ -57,7 +57,7 @@ template<> struct limits #endif // #if defined(BOOST_HAS_INT128) -#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) +#if defined(BOOST_NO_CXX17_INLINE_VARIABLES) || (defined(__clang__) && __clang_major__ <= 5) // Definitions of in-class constexpr members are allowed but deprecated in C++17 diff --git a/include/boost/charconv/to_chars.hpp b/include/boost/charconv/to_chars.hpp index 76f1ea4..d20f8a1 100644 --- a/include/boost/charconv/to_chars.hpp +++ b/include/boost/charconv/to_chars.hpp @@ -81,7 +81,7 @@ namespace detail { // See: https://jk-jeon.github.io/posts/2022/02/jeaiii-algorithm/ // https://arxiv.org/abs/2101.11408 -BOOST_CHARCONV_CONSTEXPR inline char* decompose32(std::uint32_t value, char* buffer) noexcept +BOOST_CHARCONV_CONSTEXPR char* decompose32(std::uint32_t value, char* buffer) noexcept { constexpr auto mask = (std::uint64_t(1) << 57) - 1; auto y = value * std::uint64_t(1441151881); @@ -98,7 +98,7 @@ BOOST_CHARCONV_CONSTEXPR inline char* decompose32(std::uint32_t value, char* buf #ifdef BOOST_MSVC # pragma warning(push) -# pragma warning(disable: 4127) +# pragma warning(disable: 4127 4146) #endif template @@ -251,12 +251,12 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c } // Strip the sign from the value and apply at the end after parsing if the type is signed - BOOST_IF_CONSTEXPR (std::is_signed::value) + BOOST_IF_CONSTEXPR (std::is_same::value) { if (value < 0) { is_negative = true; - unsigned_value = apply_sign(value); + unsigned_value = -(static_cast(value)); } else { @@ -270,12 +270,6 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c auto converted_value = static_cast(unsigned_value); - // If the value fits into 64 bits use the other method of processing - if (converted_value < (std::numeric_limits::max)()) - { - return to_chars_integer_impl(first, last, value); - } - const int converted_value_digits = num_digits(converted_value); if (converted_value_digits > user_buffer_size) @@ -288,6 +282,12 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c *first++ = '-'; } + // If the value fits into 64 bits use the other method of processing + if (converted_value < (std::numeric_limits::max)()) + { + return to_chars_integer_impl(first, last, static_cast(value)); + } + constexpr std::uint32_t ten_9 = UINT32_C(1000000000); char buffer[5][10] {}; int num_chars[5] {}; @@ -317,19 +317,13 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c } #endif -#ifdef BOOST_MSVC -# pragma warning(pop) -#endif - // All other bases // Use a simple lookup table to put together the Integer in character form -template +template BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char* last, Integer value, int base) noexcept { BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); - using Unsigned_Integer = typename std::make_unsigned::type; - const std::ptrdiff_t output_length = last - first; if (!(first <= last)) @@ -351,7 +345,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char if (value < 0) { *first++ = '-'; - unsigned_value = apply_sign(value); + unsigned_value = -(static_cast(value)); } else { @@ -433,31 +427,94 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char return {first + num_chars, 0}; } -} // Namespace detail +#ifdef BOOST_MSVC +# pragma warning(pop) +#endif -template ::value, bool>::type = true> +template BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, Integer value, int base = 10) noexcept +{ + using Unsigned_Integer = typename std::make_unsigned::type; + if (base == 10) + { + return detail::to_chars_integer_impl(first, last, value); + } + + return detail::to_chars_integer_impl(first, last, value, base); +} + +#ifdef BOOST_CHARCONV_HAS_INT128 +template +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars128(char* first, char* last, Integer value, int base = 10) noexcept { if (base == 10) { - #ifdef BOOST_CHARCONV_HAS_INT128 - BOOST_IF_CONSTEXPR(std::is_same::value || std::is_same::value) - { - return detail::to_chars_128integer_impl(first, last, value); - } - else - #endif - { - return detail::to_chars_integer_impl(first, last, value); - } + return to_chars_128integer_impl(first, last, value); } - return detail::to_chars_integer_impl(first, last, value, base); + return to_chars_integer_impl(first, last, value, base); +} +#endif + +} // Namespace detail + +// integer overloads +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, bool value, int base) noexcept = delete; +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, char value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, signed char value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned char value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, short value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned short value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, int value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned int value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, long value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned long value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, long long value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, unsigned long long value, int base = 10) noexcept +{ + return detail::to_chars(first, last, value, base); } -template <> -BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, bool value, int base) noexcept = delete; - +#ifdef BOOST_CHARCONV_HAS_INT128 +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, boost::int128_type value, int base = 10) noexcept +{ + return detail::to_chars128(first, last, value, base); +} +BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars(char* first, char* last, boost::uint128_type value, int base = 10) noexcept +{ + return detail::to_chars128(first, last, value, base); +} +#endif // floating point overloads BOOST_CHARCONV_DECL to_chars_result to_chars( char* first, char* last, float value ) noexcept; diff --git a/test/quick.cpp b/test/quick.cpp index 919b97e..1271c1d 100644 --- a/test/quick.cpp +++ b/test/quick.cpp @@ -6,7 +6,7 @@ int main() { - char buffer[ 32 ]; + char buffer[ 32 ] {}; auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), 1048576 ); int v = 0; diff --git a/test/roundtrip.cpp b/test/roundtrip.cpp index 9b56538..2eecdb7 100644 --- a/test/roundtrip.cpp +++ b/test/roundtrip.cpp @@ -82,7 +82,15 @@ template void test_roundtrip( T value, int base ) T v2 = 0; auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, base ); - BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value ); + BOOST_TEST_EQ( r2.ec, 0 ); + if (BOOST_TEST_EQ( v2, value )) + { + + } + else + { + std::cerr << "Original Value: " << value << "\nBase:" << base << "\nConverted Value: " << buffer << "\nRoundtriped Value: " << v2 << std::endl; + } } template void test_roundtrip_int8( int base ) @@ -253,7 +261,6 @@ int main() test_roundtrip_int64( base ); test_roundtrip_uint64( base ); - #ifdef BOOST_CHARCONV_HAS_INT128 test_roundtrip_int128( base ); @@ -281,7 +288,6 @@ int main() test_roundtrip_bv( base ); test_roundtrip_bv( base ); - #ifdef BOOST_CHARCONV_HAS_INT128 test_roundtrip_bv( base ); diff --git a/test/to_chars.cpp b/test/to_chars.cpp index bdd9cb5..82df20a 100644 --- a/test/to_chars.cpp +++ b/test/to_chars.cpp @@ -37,7 +37,6 @@ void test_128bit_int() auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3); BOOST_TEST(r3.ec == 0); BOOST_TEST(v3 == test_value); - BOOST_TEST(std::numeric_limits::max() > static_cast(std::numeric_limits::max())); char buffer4[64] {}; auto r4 = boost::charconv::to_chars(buffer4, buffer4 + sizeof(buffer4), v3); @@ -52,6 +51,7 @@ void test_128bit_int() T v5 = 0; auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5); BOOST_TEST(r5.ec == 0); + BOOST_TEST(v5 < 0); char buffer6[64] {}; auto r6 = boost::charconv::to_chars(buffer6, buffer6 + sizeof(buffer6), v5); @@ -63,6 +63,23 @@ void test_128bit_int() auto r7 = boost::charconv::from_chars(buffer6, buffer6 + std::strlen(buffer6), v7); BOOST_TEST(r7.ec == 0); BOOST_TEST(v5 == v7);; + + // Second failing test + const char* buffer10 = "-170141183460469231731687303715884105728"; + T v10 = 0; + auto r10 = boost::charconv::from_chars(buffer10, buffer10 + std::strlen(buffer10), v10); + BOOST_TEST(r10.ec == 0); + BOOST_TEST(v10 < 0); + + char buffer11[64] {}; + auto r11 = boost::charconv::to_chars(buffer11, buffer11 + sizeof(buffer11), v10); + BOOST_TEST_EQ(r11.ec, 0); + BOOST_TEST_CSTR_EQ(buffer10, buffer11); + + T v11 = 0; + auto r12 = boost::charconv::from_chars(buffer11, buffer11 + std::strlen(buffer11), v11); + BOOST_TEST(r12.ec == 0); + BOOST_TEST(v10 == v11); } } #endif