mirror of
https://github.com/boostorg/charconv.git
synced 2026-02-01 20:32:17 +00:00
Merge pull request #17 from mborland/drop_gnu
Drop GNU requirement for 128-bit integers
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <climits>
|
||||
|
||||
// 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
|
||||
|
||||
@@ -167,30 +167,30 @@ static constexpr std::array<std::uint64_t, 20> 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<unsigned __int128>(UINT64_C(10000000000000000000)) *
|
||||
static_cast<unsigned __int128>(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<boost::uint128_type>(UINT64_C(10000000000000000000)) *
|
||||
static_cast<boost::uint128_type>(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 :
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -68,10 +68,17 @@ constexpr unsigned char digit_from_char(char val) noexcept
|
||||
return uchar_values[static_cast<std::size_t>(val)];
|
||||
}
|
||||
|
||||
template <typename Integer>
|
||||
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 <typename Integer, typename Unsigned_Integer>
|
||||
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<Integer>::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<Unsigned_Integer>(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<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
|
||||
#else
|
||||
BOOST_IF_CONSTEXPR (std::is_signed<Integer>::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<Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Integer>::max)();
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
|
||||
{
|
||||
overflow_value = BOOST_CHARCONV_INT128_MAX;
|
||||
max_digit = BOOST_CHARCONV_INT128_MAX;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
overflow_value = (std::numeric_limits<Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Integer>::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<Unsigned_Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Unsigned_Integer>::max)();
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value)
|
||||
{
|
||||
overflow_value = BOOST_CHARCONV_UINT128_MAX;
|
||||
max_digit = BOOST_CHARCONV_UINT128_MAX;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
overflow_value = (std::numeric_limits<Unsigned_Integer>::max)();
|
||||
max_digit = (std::numeric_limits<Unsigned_Integer>::max)();
|
||||
}
|
||||
}
|
||||
|
||||
overflow_value /= static_cast<Unsigned_Integer>(base);
|
||||
max_digit %= base;
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::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<Unsigned_Integer>(result * base + current_digit);
|
||||
result = static_cast<Unsigned_Integer>(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<Integer>(result);
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
|
||||
#else
|
||||
BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value)
|
||||
#endif
|
||||
{
|
||||
if (is_negative)
|
||||
{
|
||||
value = apply_sign(value);
|
||||
value = -(static_cast<Unsigned_Integer>(value));
|
||||
}
|
||||
}
|
||||
|
||||
return {next, 0};
|
||||
}
|
||||
|
||||
} // Namespace detail
|
||||
|
||||
// GCC 5 does not support constexpr comparison of const char*
|
||||
#if defined(__GNUC__) && __GNUC__ == 5
|
||||
template <typename Integer, typename std::enable_if<std::is_integral<Integer>::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<bool>(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 <typename Integer, typename std::enable_if<std::is_integral<Integer>::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 <typename Integer>
|
||||
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<Integer>::type;
|
||||
return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
|
||||
}
|
||||
|
||||
template <>
|
||||
BOOST_CXX14_CONSTEXPR from_chars_result from_chars<bool>(const char* first, const char* last, bool& value, int base) noexcept = delete;
|
||||
#ifdef BOOST_HAS_INT128
|
||||
template <typename Integer>
|
||||
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<Integer, Unsigned_Integer>(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<boost::int128_type, boost::uint128_type>(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<boost::uint128_type, boost::uint128_type>(first, last, value, base);
|
||||
}
|
||||
#endif
|
||||
|
||||
// floating point overloads
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ template<> struct limits<boost::uint128_type>
|
||||
|
||||
#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
|
||||
|
||||
|
||||
@@ -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 <typename Integer>
|
||||
@@ -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<Integer>::value)
|
||||
BOOST_IF_CONSTEXPR (std::is_same<boost::int128_type, Integer>::value)
|
||||
{
|
||||
if (value < 0)
|
||||
{
|
||||
is_negative = true;
|
||||
unsigned_value = apply_sign(value);
|
||||
unsigned_value = -(static_cast<Unsigned_Integer>(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -270,12 +270,6 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
|
||||
|
||||
auto converted_value = static_cast<boost::uint128_type>(unsigned_value);
|
||||
|
||||
// If the value fits into 64 bits use the other method of processing
|
||||
if (converted_value < (std::numeric_limits<std::uint64_t>::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<std::uint64_t>::max)())
|
||||
{
|
||||
return to_chars_integer_impl(first, last, static_cast<std::uint64_t>(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 <typename Integer>
|
||||
template <typename Integer, typename Unsigned_Integer>
|
||||
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<Integer>::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<Unsigned_Integer>(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 <typename Integer, typename std::enable_if<std::is_integral<Integer>::value, bool>::type = true>
|
||||
template <typename Integer>
|
||||
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<Integer>::type;
|
||||
if (base == 10)
|
||||
{
|
||||
return detail::to_chars_integer_impl(first, last, value);
|
||||
}
|
||||
|
||||
return detail::to_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
|
||||
}
|
||||
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
template <typename Integer>
|
||||
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<Integer, boost::int128_type>::value || std::is_same<Integer, boost::uint128_type>::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<Integer, boost::uint128_type>(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<bool>(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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -82,7 +82,15 @@ template<class T> 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<class T> void test_roundtrip_int8( int base )
|
||||
@@ -253,7 +261,6 @@ int main()
|
||||
|
||||
test_roundtrip_int64<std::int64_t>( base );
|
||||
test_roundtrip_uint64<std::uint64_t>( base );
|
||||
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
|
||||
test_roundtrip_int128<boost::int128_type>( base );
|
||||
@@ -281,7 +288,6 @@ int main()
|
||||
|
||||
test_roundtrip_bv<long long>( base );
|
||||
test_roundtrip_bv<unsigned long long>( base );
|
||||
|
||||
#ifdef BOOST_CHARCONV_HAS_INT128
|
||||
|
||||
test_roundtrip_bv<boost::int128_type>( base );
|
||||
|
||||
@@ -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<T>::max() > static_cast<T>(std::numeric_limits<unsigned long long>::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
|
||||
|
||||
Reference in New Issue
Block a user