From 9e3c7948dda3ea6a7e202b701447d485dff8f36f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 09:45:20 -0800 Subject: [PATCH 01/31] Add integer framework [ci skip] --- include/boost/charconv/from_chars.hpp | 22 ++++++++++ src/from_chars.cpp | 62 ++++++++++++++++++++++++++- 2 files changed, 82 insertions(+), 2 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index ecd3d08..610bc84 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -7,6 +7,7 @@ #define BOOST_CHARCONV_FROM_CHARS_HPP_INCLUDED #include +#include namespace boost { namespace charconv { @@ -15,6 +16,11 @@ namespace boost { namespace charconv { struct from_chars_result { const char* ptr; + + // Values: + // 0 = no error + // 1 = invalid_argument + // 2 = result_out_of_range int ec; friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) @@ -28,7 +34,23 @@ struct from_chars_result } }; +namespace detail { + +template ::value, bool>::type = true> +boost::charconv::from_chars_result from_chars(const char* first, const char* last, Integer& value, int base); + +} // Namespace detail + +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10); BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10); } // namespace charconv } // namespace boost diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 97f93de..a02c7f8 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -4,10 +4,68 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include +#include #include +template ::value, bool>::type> +boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) +{ + BOOST_IF_CONSTEXPR(std::is_same::value) + { + value = static_cast(std::strtol(first, const_cast(&last), base)); + return { last, 0 }; + } + + return {last, 0}; +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, short& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned short& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, int& value, int base) { - value = static_cast(std::strtol(first, const_cast(&last), base)); - return { last, 0 }; + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned int& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long long& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); +} + +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long long& value, int base) +{ + return boost::charconv::detail::from_chars(first, last, value, base); } From 9ae5f9e02a17fd9b37db64444a54282aa27d6fd0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 09:55:11 -0800 Subject: [PATCH 02/31] Define assert with message and check pre-conditions [ci skip] --- include/boost/charconv/config.hpp | 4 ++++ src/from_chars.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/include/boost/charconv/config.hpp b/include/boost/charconv/config.hpp index ffcccf2..0a472e9 100644 --- a/include/boost/charconv/config.hpp +++ b/include/boost/charconv/config.hpp @@ -6,6 +6,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 @@ -34,4 +35,7 @@ #endif +#define BOOST_CHARCONV_ASSERT(expr) assert(expr) +#define BOOST_CHARCONV_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) + #endif // BOOST_CHARCONV_CONFIG_HPP_INCLUDED diff --git a/src/from_chars.cpp b/src/from_chars.cpp index a02c7f8..d58ba53 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -4,6 +4,7 @@ // https://www.boost.org/LICENSE_1_0.txt #include +#include #include #include #include @@ -11,6 +12,9 @@ template ::value, bool>::type> boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) { + // Check pre-conditions + BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); + BOOST_IF_CONSTEXPR(std::is_same::value) { value = static_cast(std::strtol(first, const_cast(&last), base)); From ab20292a9351f7e89ebfa5a60827f993a42d4497 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 10:25:02 -0800 Subject: [PATCH 03/31] Add character lookup table [ci skip] --- include/boost/charconv/from_chars.hpp | 28 ++++++++++++++++++++++++++- src/from_chars.cpp | 2 +- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 610bc84..8f29663 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -8,6 +8,8 @@ #include #include +#include +#include namespace boost { namespace charconv { @@ -22,7 +24,7 @@ struct from_chars_result // 1 = invalid_argument // 2 = result_out_of_range int ec; - + friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) { return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec; @@ -36,6 +38,30 @@ struct from_chars_result namespace detail { +static constexpr std::array uchar_values = + {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + +// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 +unsigned char digit_from_char(char val) +{ + return uchar_values[static_cast(val)]; +} + template ::value, bool>::type = true> boost::charconv::from_chars_result from_chars(const char* first, const char* last, Integer& value, int base); diff --git a/src/from_chars.cpp b/src/from_chars.cpp index d58ba53..9440515 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -14,7 +14,7 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha { // Check pre-conditions BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); - + BOOST_IF_CONSTEXPR(std::is_same::value) { value = static_cast(std::strtol(first, const_cast(&last), base)); From 2d90c85de63429fc5803d6c8b60bd700495f573b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 10:27:53 -0800 Subject: [PATCH 04/31] Use cerrno values for ec [ci skip] --- include/boost/charconv/from_chars.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 8f29663..5a9b3f9 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace boost { namespace charconv { @@ -21,8 +22,8 @@ struct from_chars_result // Values: // 0 = no error - // 1 = invalid_argument - // 2 = result_out_of_range + // EINVAL = invalid_argument + // ERANGE = result_out_of_range int ec; friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) From 884b06641ae33d0769262fe56f7858ea85d4bc0a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 11:12:17 -0800 Subject: [PATCH 05/31] Change exception specification [ci skip] --- include/boost/charconv/from_chars.hpp | 28 +++++++++++++-------------- src/from_chars.cpp | 22 ++++++++++----------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 5a9b3f9..c9bb871 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -26,12 +26,12 @@ struct from_chars_result // ERANGE = result_out_of_range int ec; - friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) + friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept { return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec; } - friend bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) + friend bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept { return !(lhs == rhs); } @@ -58,26 +58,26 @@ static constexpr std::array uchar_values = 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 -unsigned char digit_from_char(char val) +unsigned char digit_from_char(char val) noexcept { return uchar_values[static_cast(val)]; } template ::value, bool>::type = true> -boost::charconv::from_chars_result from_chars(const char* first, const char* last, Integer& value, int base); +boost::charconv::from_chars_result from_chars(const char* first, const char* last, Integer& value, int base) noexcept; } // Namespace detail -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10); -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10); +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10) noexcept; } // namespace charconv } // namespace boost diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 9440515..8e2cb6b 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -10,7 +10,7 @@ #include template ::value, bool>::type> -boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) +boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) noexcept { // Check pre-conditions BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); @@ -24,52 +24,52 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha return {last, 0}; } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, short& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, short& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned short& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned short& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, int& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, int& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned int& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned int& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long long& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long long& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long long& value, int base) +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long long& value, int base) noexcept { return boost::charconv::detail::from_chars(first, last, value, base); } From aae6dd4f4c1f7bca094a82231bd2dd107ba9dea8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 12:01:16 -0800 Subject: [PATCH 06/31] Implement integer parser [ci skip] --- src/from_chars.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 8e2cb6b..a9133ca 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -7,21 +7,109 @@ #include #include #include +#include #include +#include +#include template ::value, bool>::type> boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) noexcept { + using Unsinged_Integer = typename std::make_unsigned::type; + Unsinged_Integer result = 0; + Unsinged_Integer overflow_value = 0; + Unsinged_Integer max_digit = 0; + // Check pre-conditions BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); - - BOOST_IF_CONSTEXPR(std::is_same::value) + if (!(first <= last)) { - value = static_cast(std::strtol(first, const_cast(&last), base)); - return { last, 0 }; + return {first, EINVAL}; } - return {last, 0}; + // Strip sign if the type is signed + // Negative sign will be appended at the end of parsing + bool is_negative = false; + auto next = first; + BOOST_IF_CONSTEXPR (std::is_signed::value) + { + if (next != last) + { + if (*next == '-') + { + is_negative = true; + ++next; + } + else if (*next == '+') + { + ++next; + } + } + + if (is_negative) + { + overflow_value = (static_cast((std::numeric_limits::max)()) + 1); + max_digit = (static_cast((std::numeric_limits::max)()) + 1); + } + else + { + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + } + } + else + { + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + } + + overflow_value /= base; + max_digit %= base; + + // If the only character was a sign abort now + if (next == last) + { + return {first, EINVAL}; + } + + bool overflowed = false; + while (next != last) + { + auto current_digit = digit_from_char(*next++); + + if (current_digit >= base) + { + break; + } + + if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) + { + result = static_cast(result * base + current_digit); + } + else + { + // Required to keep updating the value of next, but the result is garbage + overflowed = true; + } + } + + // Return the parsed value, adding the sign back if applicable + // If we have overflowed then we do not return the result + if (overflowed) + { + return {next, ERANGE}; + } + + value = static_cast(result); + BOOST_IF_CONSTEXPR (std::is_signed::value) + { + if (is_negative) + { + value *= -1; + } + } + + return {next, 0}; } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) noexcept From a0132d7dc2a25a421590c8dd029faa701ddeced9 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Tue, 10 Jan 2023 12:04:44 -0800 Subject: [PATCH 07/31] Fix spelling of Unsigned_Integer [ci skip] --- src/from_chars.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index a9133ca..1c8572c 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -15,10 +15,10 @@ template ::value, bool>::type> boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) noexcept { - using Unsinged_Integer = typename std::make_unsigned::type; - Unsinged_Integer result = 0; - Unsinged_Integer overflow_value = 0; - Unsinged_Integer max_digit = 0; + using Unsigned_Integer = typename std::make_unsigned::type; + Unsigned_Integer result = 0; + Unsigned_Integer overflow_value = 0; + Unsigned_Integer max_digit = 0; // Check pre-conditions BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); @@ -48,8 +48,8 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha if (is_negative) { - overflow_value = (static_cast((std::numeric_limits::max)()) + 1); - max_digit = (static_cast((std::numeric_limits::max)()) + 1); + overflow_value = (static_cast((std::numeric_limits::max)()) + 1); + max_digit = (static_cast((std::numeric_limits::max)()) + 1); } else { @@ -59,8 +59,8 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha } else { - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); } overflow_value /= base; @@ -84,7 +84,7 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) { - result = static_cast(result * base + current_digit); + result = static_cast(result * base + current_digit); } else { From e4c12ebb702f38e66bbc87422ae10cbb13b0ca25 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 07:31:48 -0800 Subject: [PATCH 08/31] Refactor simple test --- test/from_chars.cpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 7b79989..596343f 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -6,24 +6,44 @@ #include #include #include +#include -int main() +// No overflows, negative numbers, locales, etc. +template +void simple_test() { - const char* buffer = "1048576"; + const char* buffer = "34"; - int v = 0; + T v = 0; auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); - BOOST_TEST_EQ( r.ec, 0 ) && BOOST_TEST_EQ( v, 1048576 ); + BOOST_TEST_EQ( r.ec, 0 ) && BOOST_TEST_EQ(v, 34); BOOST_TEST(r == r); boost::charconv::from_chars_result r2 {r.ptr, 0}; BOOST_TEST(r == r2); - const char* buffer2 = "1234567"; - int v2 = 0; + const char* buffer2 = "12"; + T v2 = 0; auto r3 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer), v2); BOOST_TEST(r != r3); + BOOST_TEST_EQ(r3.ec, 0) && BOOST_TEST_EQ(v2, 12); +} +int main() +{ + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + simple_test(); + return boost::report_errors(); } From 70de0faa6ef650c22986249bd955a2b9c1bd4216 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 07:50:56 -0800 Subject: [PATCH 09/31] Add double curly braces for old clangs https://bugs.llvm.org/show_bug.cgi?id=21629 --- include/boost/charconv/from_chars.hpp | 32 +++++++++++++-------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index c9bb871..4579e6c 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -40,22 +40,22 @@ struct from_chars_result namespace detail { static constexpr std::array uchar_values = - {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + {{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 unsigned char digit_from_char(char val) noexcept From 462cf533c2a62a54e695254ef9eeac36b31a381a Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 07:52:04 -0800 Subject: [PATCH 10/31] Add unused attribute in case of early return --- src/from_chars.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 1c8572c..e60ef51 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -29,7 +29,7 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha // Strip sign if the type is signed // Negative sign will be appended at the end of parsing - bool is_negative = false; + BOOST_ATTRIBUTE_UNUSED bool is_negative = false; auto next = first; BOOST_IF_CONSTEXPR (std::is_signed::value) { From 7c00e61d150d7ff2c470bcf8c5a95dc2098c74f3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 07:58:24 -0800 Subject: [PATCH 11/31] Inline function for ODR violation --- include/boost/charconv/from_chars.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 4579e6c..781ae1d 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -58,7 +58,7 @@ static constexpr std::array uchar_values = 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 -unsigned char digit_from_char(char val) noexcept +inline unsigned char digit_from_char(char val) noexcept { return uchar_values[static_cast(val)]; } From 2fc5c898995ed36bfefc6f72615e0ce409427422 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 08:45:02 -0800 Subject: [PATCH 12/31] Fixes for MSVC warnings --- src/from_chars.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index e60ef51..9e6795b 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -12,6 +12,22 @@ #include #include +namespace boost { namespace charconv { namespace detail { + +template ::value, bool>::type = true> +inline Integer apply_sign(Integer val) noexcept +{ + return -val; +} + +template ::value, bool>::type = true> +inline Integer apply_sign(Integer val) noexcept +{ + return val; +} + +}}} // Namespaces + template ::value, bool>::type> boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) noexcept { @@ -63,7 +79,7 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha max_digit = (std::numeric_limits::max)(); } - overflow_value /= base; + overflow_value /= static_cast(base); max_digit %= base; // If the only character was a sign abort now @@ -105,7 +121,7 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha { if (is_negative) { - value *= -1; + value = apply_sign(value); } } From cad83d2ae8ff8584745759a8923935d360e933a0 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 11:04:00 -0800 Subject: [PATCH 13/31] Fix -Woverflow on old GCC https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80745 --- src/from_chars.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 9e6795b..e23bea8 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -62,15 +62,13 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha } } + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + if (is_negative) { - overflow_value = (static_cast((std::numeric_limits::max)()) + 1); - max_digit = (static_cast((std::numeric_limits::max)()) + 1); - } - else - { - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); + ++overflow_value; + ++max_digit; } } else From 672bd3b8728ea256989b65d905eebf44e5fa21da Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 11:26:06 -0800 Subject: [PATCH 14/31] Refactor detail namespace --- include/boost/charconv/from_chars.hpp | 31 ---------------- src/from_chars.cpp | 52 +++++++++++++++++++-------- 2 files changed, 38 insertions(+), 45 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 781ae1d..1d68a8f 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -37,37 +37,6 @@ struct from_chars_result } }; -namespace detail { - -static constexpr std::array uchar_values = - {{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; - -// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 -inline unsigned char digit_from_char(char val) noexcept -{ - return uchar_values[static_cast(val)]; -} - -template ::value, bool>::type = true> -boost::charconv::from_chars_result from_chars(const char* first, const char* last, Integer& value, int base) noexcept; - -} // Namespace detail - BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept; diff --git a/src/from_chars.cpp b/src/from_chars.cpp index e23bea8..9649e20 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -14,6 +14,30 @@ namespace boost { namespace charconv { namespace detail { +static constexpr std::array uchar_values = + {{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; + +// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 +inline unsigned char digit_from_char(char val) noexcept +{ + return uchar_values[static_cast(val)]; +} + template ::value, bool>::type = true> inline Integer apply_sign(Integer val) noexcept { @@ -26,10 +50,8 @@ inline Integer apply_sign(Integer val) noexcept return val; } -}}} // Namespaces - -template ::value, bool>::type> -boost::charconv::from_chars_result boost::charconv::detail::from_chars(const char* first, const char* last, Integer& value, int base) noexcept +template ::value, bool>::type = true> +boost::charconv::from_chars_result from_chars_impl(const char* first, const char* last, Integer& value, int base) noexcept { using Unsigned_Integer = typename std::make_unsigned::type; Unsigned_Integer result = 0; @@ -126,52 +148,54 @@ boost::charconv::from_chars_result boost::charconv::detail::from_chars(const cha return {next, 0}; } +}}} // Namespace boost::charconv::detail + boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, short& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned short& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, int& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned int& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long long& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long long& value, int base) noexcept { - return boost::charconv::detail::from_chars(first, last, value, base); + return boost::charconv::detail::from_chars_impl(first, last, value, base); } From 99d45ca9417b2c430719296be06130f046098fb3 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 11 Jan 2023 13:30:18 -0800 Subject: [PATCH 15/31] Add test for invalid arguments --- src/from_chars.cpp | 12 ++++++++++++ test/from_chars.cpp | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 9649e20..109c265 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -95,6 +95,18 @@ boost::charconv::from_chars_result from_chars_impl(const char* first, const char } else { + if (next != last) + { + if (*next == '-') + { + return {first, EINVAL}; + } + else if (*next == '+') + { + ++next; + } + } + overflow_value = (std::numeric_limits::max)(); max_digit = (std::numeric_limits::max)(); } diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 596343f..18297dd 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -7,6 +7,26 @@ #include #include #include +#include + +template +void invalid_argument_test() +{ + const char* buffer1 = ""; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1); + BOOST_TEST_EQ(r1.ec, EINVAL); + + const char* buffer2 = "-"; + T v2 = 0; + auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2); + BOOST_TEST_EQ(r2.ec, EINVAL); + + const char* buffer3 = "+"; + T v3 = 0; + auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3); + BOOST_TEST_EQ(r3.ec, EINVAL); +} // No overflows, negative numbers, locales, etc. template @@ -45,5 +65,8 @@ int main() simple_test(); simple_test(); + invalid_argument_test(); + invalid_argument_test(); + return boost::report_errors(); } From 19fc30cc122f405eaea03cd0df8b4c4236bbf4fa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 09:16:18 -0800 Subject: [PATCH 16/31] Add test for parsing a negative number into an unsigned int --- test/from_chars.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 18297dd..f6c4c64 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -26,6 +26,14 @@ void invalid_argument_test() T v3 = 0; auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3); BOOST_TEST_EQ(r3.ec, EINVAL); + + BOOST_IF_CONSTEXPR(std::is_unsigned::value) + { + const char* buffer4 = "-123"; + T v4 = 0; + auto r4 = boost::charconv::from_chars(buffer4, buffer4 + std::strlen(buffer4), v4); + BOOST_TEST_EQ(r4.ec, EINVAL); + } } // No overflows, negative numbers, locales, etc. From d824d46b693601f0fcd501bf2e539b87242940aa Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 09:33:20 -0800 Subject: [PATCH 17/31] Add overflow test --- test/from_chars.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/from_chars.cpp b/test/from_chars.cpp index f6c4c64..cf17910 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -5,10 +5,35 @@ #include #include +#include +#include #include #include #include +template +void overflow_test() +{ + const char* buffer1 = "1234"; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1); + + BOOST_IF_CONSTEXPR((std::numeric_limits::max)() < 1234) + { + BOOST_TEST_EQ(r1.ec, ERANGE); + } + else + { + BOOST_TEST_EQ(r1.ec, 0) && BOOST_TEST_EQ(v1, 1234); + } + + const char* buffer2 = "123456789123456789123456789"; + T v2 = 0; + auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2); + // In the event of overflow v2 is to be returned unmodified + BOOST_TEST_EQ(r2.ec, ERANGE) && BOOST_TEST_EQ(v2, 0); +} + template void invalid_argument_test() { @@ -76,5 +101,8 @@ int main() invalid_argument_test(); invalid_argument_test(); + overflow_test(); + overflow_test(); + return boost::report_errors(); } From 47689f9ebbb7e3849030705564cedae6399f32f1 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 10:02:23 -0800 Subject: [PATCH 18/31] Fixes and testing for hexadecimal --- src/from_chars.cpp | 17 +++++++++++++++++ test/from_chars.cpp | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 109c265..e03ea17 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -120,6 +120,23 @@ boost::charconv::from_chars_result from_chars_impl(const char* first, const char return {first, EINVAL}; } + // In base16 we need to strip 0x and 0X prefixes + if (base == 16) + { + if (next != last && *next == '0') + { + ++next; + } + if (next != last && (*next == 'x' || *next == 'X')) + { + ++next; + } + else // move back in the event there is a leading 0 and not the appropriate prefix + { + --next; + } + } + bool overflowed = false; while (next != last) { diff --git a/test/from_chars.cpp b/test/from_chars.cpp index cf17910..1811933 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -11,6 +11,23 @@ #include #include +template +void base16_test() +{ + // In base 16 0x and 0X prefixes are ignored + const char* buffer1 = "0x2a"; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1, 16); + BOOST_TEST_EQ(r1.ec, 0); + BOOST_TEST_EQ(v1, 42); + + const char* buffer2 = "0"; + T v2 = 1; + auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2, 16); + BOOST_TEST_EQ(r2.ec, 0); + BOOST_TEST_EQ(v2, 0); +} + template void overflow_test() { @@ -104,5 +121,8 @@ int main() overflow_test(); overflow_test(); + base16_test(); + base16_test(); + return boost::report_errors(); } From eec32d14e7dcf1defd9d2bec4c61a6b8dc1f28e8 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 10:10:05 -0800 Subject: [PATCH 19/31] Add binary test --- test/from_chars.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 1811933..9fdeac3 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -11,6 +11,17 @@ #include #include +template +void base2_test() +{ + // Includes leading 0 which should be ignored + const char* buffer1 = "0101010"; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1, 2); + BOOST_TEST_EQ(r1.ec, 0); + BOOST_TEST_EQ(v1, 42); +} + template void base16_test() { @@ -124,5 +135,8 @@ int main() base16_test(); base16_test(); + base2_test(); + base2_test(); + return boost::report_errors(); } From b5baf88e355b0b4d31e8027385ca808dc64fba44 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 10:18:52 -0800 Subject: [PATCH 20/31] Add overload for signed char http://eel.is/c++draft/basic#fundamental --- include/boost/charconv/from_chars.hpp | 1 + src/from_chars.cpp | 5 +++++ test/from_chars.cpp | 1 + 3 files changed, 7 insertions(+) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 1d68a8f..7005409 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -38,6 +38,7 @@ struct from_chars_result }; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept; +BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, signed char& value, int base = 10) noexcept; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept; BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10) noexcept; diff --git a/src/from_chars.cpp b/src/from_chars.cpp index e03ea17..6a0388c 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -184,6 +184,11 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first return boost::charconv::detail::from_chars_impl(first, last, value, base); } +boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, signed char& value, int base) noexcept +{ + return boost::charconv::detail::from_chars_impl(first, last, value, base); +} + boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) noexcept { return boost::charconv::detail::from_chars_impl(first, last, value, base); diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 9fdeac3..3d4f7e7 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -114,6 +114,7 @@ void simple_test() int main() { simple_test(); + simple_test(); simple_test(); simple_test(); simple_test(); From 1a2a1ad66ade424956389333be0af340ed33b98f Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 11:36:53 -0800 Subject: [PATCH 21/31] Make integer from_chars constexpr --- include/boost/charconv/from_chars.hpp | 192 ++++++++++++++++++++-- src/from_chars.cpp | 222 -------------------------- test/from_chars.cpp | 26 +++ 3 files changed, 205 insertions(+), 235 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 7005409..3e45775 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -7,9 +7,13 @@ #define BOOST_CHARCONV_FROM_CHARS_HPP_INCLUDED #include +#include #include +#include #include +#include #include +#include #include namespace boost { namespace charconv { @@ -26,28 +30,190 @@ struct from_chars_result // ERANGE = result_out_of_range int ec; - friend bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept + friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept { return lhs.ptr == rhs.ptr && lhs.ec == rhs.ec; } - friend bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept + friend constexpr bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept { return !(lhs == rhs); } }; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, char& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, signed char& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned char& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, short& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned short& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, int& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned int& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, long long& value, int base = 10) noexcept; -BOOST_CHARCONV_DECL from_chars_result from_chars(const char* first, const char* last, unsigned long long& value, int base = 10) noexcept; +namespace detail { + +static constexpr std::array uchar_values = + {{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; + +// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 +constexpr unsigned char digit_from_char(char val) noexcept +{ + return uchar_values[static_cast(val)]; +} + +template ::value, bool>::type = true> +constexpr Integer apply_sign(Integer val) noexcept +{ + return -val; +} + +template ::value, bool>::type = true> +constexpr Integer apply_sign(Integer val) noexcept +{ + return 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 +{ + using Unsigned_Integer = typename std::make_unsigned::type; + Unsigned_Integer result = 0; + Unsigned_Integer overflow_value = 0; + Unsigned_Integer max_digit = 0; + + // Check pre-conditions + BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); + if (!(first <= last)) + { + return {first, EINVAL}; + } + + // 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; + BOOST_IF_CONSTEXPR (std::is_signed::value) + { + if (next != last) + { + if (*next == '-') + { + is_negative = true; + ++next; + } + else if (*next == '+') + { + ++next; + } + } + + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + + if (is_negative) + { + ++overflow_value; + ++max_digit; + } + } + else + { + if (next != last) + { + if (*next == '-') + { + return {first, EINVAL}; + } + else if (*next == '+') + { + ++next; + } + } + + overflow_value = (std::numeric_limits::max)(); + max_digit = (std::numeric_limits::max)(); + } + + overflow_value /= static_cast(base); + max_digit %= base; + + // If the only character was a sign abort now + if (next == last) + { + return {first, EINVAL}; + } + + // In base16 we need to strip 0x and 0X prefixes + if (base == 16) + { + if (next != last && *next == '0') + { + ++next; + } + if (next != last && (*next == 'x' || *next == 'X')) + { + ++next; + } + else // move back in the event there is a leading 0 and not the appropriate prefix + { + --next; + } + } + + bool overflowed = false; + while (next != last) + { + auto current_digit = digit_from_char(*next++); + + if (current_digit >= base) + { + break; + } + + if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) + { + result = static_cast(result * base + current_digit); + } + else + { + // Required to keep updating the value of next, but the result is garbage + overflowed = true; + } + } + + // Return the parsed value, adding the sign back if applicable + // If we have overflowed then we do not return the result + if (overflowed) + { + return {next, ERANGE}; + } + + value = static_cast(result); + BOOST_IF_CONSTEXPR (std::is_signed::value) + { + if (is_negative) + { + value = apply_sign(value); + } + } + + return {next, 0}; +} + +} // Namespace detail + +// 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 +{ + return detail::from_chars_integer_impl(first, last, value, base); +} } // namespace charconv } // namespace boost diff --git a/src/from_chars.cpp b/src/from_chars.cpp index 6a0388c..9c94412 100644 --- a/src/from_chars.cpp +++ b/src/from_chars.cpp @@ -11,225 +11,3 @@ #include #include #include - -namespace boost { namespace charconv { namespace detail { - -static constexpr std::array uchar_values = - {{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}}; - -// Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 -inline unsigned char digit_from_char(char val) noexcept -{ - return uchar_values[static_cast(val)]; -} - -template ::value, bool>::type = true> -inline Integer apply_sign(Integer val) noexcept -{ - return -val; -} - -template ::value, bool>::type = true> -inline Integer apply_sign(Integer val) noexcept -{ - return val; -} - -template ::value, bool>::type = true> -boost::charconv::from_chars_result from_chars_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; - - // Check pre-conditions - BOOST_CHARCONV_ASSERT_MSG(base >= 2 && base <= 36, "Base must be between 2 and 36 (inclusive)"); - if (!(first <= last)) - { - return {first, EINVAL}; - } - - // 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; - BOOST_IF_CONSTEXPR (std::is_signed::value) - { - if (next != last) - { - if (*next == '-') - { - is_negative = true; - ++next; - } - else if (*next == '+') - { - ++next; - } - } - - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); - - if (is_negative) - { - ++overflow_value; - ++max_digit; - } - } - else - { - if (next != last) - { - if (*next == '-') - { - return {first, EINVAL}; - } - else if (*next == '+') - { - ++next; - } - } - - overflow_value = (std::numeric_limits::max)(); - max_digit = (std::numeric_limits::max)(); - } - - overflow_value /= static_cast(base); - max_digit %= base; - - // If the only character was a sign abort now - if (next == last) - { - return {first, EINVAL}; - } - - // In base16 we need to strip 0x and 0X prefixes - if (base == 16) - { - if (next != last && *next == '0') - { - ++next; - } - if (next != last && (*next == 'x' || *next == 'X')) - { - ++next; - } - else // move back in the event there is a leading 0 and not the appropriate prefix - { - --next; - } - } - - bool overflowed = false; - while (next != last) - { - auto current_digit = digit_from_char(*next++); - - if (current_digit >= base) - { - break; - } - - if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) - { - result = static_cast(result * base + current_digit); - } - else - { - // Required to keep updating the value of next, but the result is garbage - overflowed = true; - } - } - - // Return the parsed value, adding the sign back if applicable - // If we have overflowed then we do not return the result - if (overflowed) - { - return {next, ERANGE}; - } - - value = static_cast(result); - BOOST_IF_CONSTEXPR (std::is_signed::value) - { - if (is_negative) - { - value = apply_sign(value); - } - } - - return {next, 0}; -} - -}}} // Namespace boost::charconv::detail - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, char& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, signed char& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned char& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, short& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned short& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, int& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned int& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long long& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} - -boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, unsigned long long& value, int base) noexcept -{ - return boost::charconv::detail::from_chars_impl(first, last, value, base); -} diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 3d4f7e7..124163a 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -10,6 +10,28 @@ #include #include #include +#include + +#ifndef BOOST_NO_CXX14_CONSTEXPR +template +constexpr std::pair constexpr_test_helper() +{ + const char* buffer1 = "42"; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + 2, v1); + + return std::make_pair(v1, r1); +} + +template +constexpr void constexpr_test() +{ + constexpr auto results = constexpr_test_helper(); + static_assert(results.second.ec == 0, "No error"); + static_assert(results.first == 42, "Value is 42"); +} + +#endif template void base2_test() @@ -139,5 +161,9 @@ int main() base2_test(); base2_test(); + #ifndef BOOST_NO_CXX14_CONSTEXPR + constexpr_test(); + #endif + return boost::report_errors(); } From 51e3eef6ee25801278987a01db86ad093af5e78b Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Thu, 12 Jan 2023 12:53:17 -0800 Subject: [PATCH 22/31] Workaround for GCC 5 C++14 constexpr support --- include/boost/charconv/from_chars.hpp | 9 +++++++++ test/from_chars.cpp | 10 ++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 3e45775..3c00bda 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -208,12 +208,21 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl } // 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); +} +#else // 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 { return detail::from_chars_integer_impl(first, last, value, base); } +#endif } // namespace charconv } // namespace boost diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 124163a..142e81c 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -161,8 +161,14 @@ int main() base2_test(); base2_test(); - #ifndef BOOST_NO_CXX14_CONSTEXPR - constexpr_test(); + #ifndef __GNUC__ + # ifndef BOOST_NO_CXX14_CONSTEXPR + constexpr_test(); + # endif + #else + # if __GNUC__ > 5 && !defined(BOOST_NO_CXX14_CONSTEXPR) + constexpr_test(); + # endif #endif return boost::report_errors(); From 06d17d8827b71969644ce8b29abbedfd901fb069 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 13 Jan 2023 09:39:52 -0800 Subject: [PATCH 23/31] Fix GCC5 workaround --- include/boost/charconv/from_chars.hpp | 2 +- test/from_chars.cpp | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 3c00bda..456e0a2 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -209,7 +209,7 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl } // Namespace detail // GCC 5 does not support constexpr comparison of const char* -#if defined(__GNUC__) && __GNUC__ <= 5 +#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 { diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 142e81c..e74d9f0 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -161,14 +161,10 @@ int main() base2_test(); base2_test(); - #ifndef __GNUC__ + #if !(defined(__GNUC__) && __GNUC__ == 5) # ifndef BOOST_NO_CXX14_CONSTEXPR constexpr_test(); # endif - #else - # if __GNUC__ > 5 && !defined(BOOST_NO_CXX14_CONSTEXPR) - constexpr_test(); - # endif #endif return boost::report_errors(); From 2114d03bc41487a4435262b6e3afe696cc1200c4 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 13 Jan 2023 10:25:45 -0800 Subject: [PATCH 24/31] Delete bool overloads --- include/boost/charconv/from_chars.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index 456e0a2..f4a79ff 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -215,14 +215,23 @@ inline from_chars_result from_chars(const char* first, const char* last, Integer { 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 + // 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 { return detail::from_chars_integer_impl(first, last, value, base); } -#endif + +template <> +BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, bool& value, int base) noexcept = delete; + +#endif // GCC5 workarounds } // namespace charconv } // namespace boost From 1f592c1d4b3c32de961f82ae0cbfdb9250fdb648 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 13 Jan 2023 11:33:18 -0800 Subject: [PATCH 25/31] Add STL comp test and adjust hexadecimal parsing to match --- include/boost/charconv/from_chars.hpp | 21 ++--------- test/Jamfile | 1 + test/from_chars.cpp | 4 +-- test/from_chars_STL_comp.cpp | 52 +++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 20 deletions(-) create mode 100644 test/from_chars_STL_comp.cpp diff --git a/include/boost/charconv/from_chars.hpp b/include/boost/charconv/from_chars.hpp index f4a79ff..9e5fcc6 100644 --- a/include/boost/charconv/from_chars.hpp +++ b/include/boost/charconv/from_chars.hpp @@ -149,27 +149,10 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl return {first, EINVAL}; } - // In base16 we need to strip 0x and 0X prefixes - if (base == 16) - { - if (next != last && *next == '0') - { - ++next; - } - if (next != last && (*next == 'x' || *next == 'X')) - { - ++next; - } - else // move back in the event there is a leading 0 and not the appropriate prefix - { - --next; - } - } - bool overflowed = false; while (next != last) { - auto current_digit = digit_from_char(*next++); + auto current_digit = digit_from_char(*next); if (current_digit >= base) { @@ -185,6 +168,8 @@ BOOST_CXX14_CONSTEXPR boost::charconv::from_chars_result from_chars_integer_impl // Required to keep updating the value of next, but the result is garbage overflowed = true; } + + ++next; } // Return the parsed value, adding the sign back if applicable diff --git a/test/Jamfile b/test/Jamfile index 680ffaf..5bdc53b 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -20,3 +20,4 @@ run quick.cpp ; run from_chars.cpp ; run to_chars.cpp ; run roundtrip.cpp ; +run from_chars_STL_comp.cpp : : : [ requires cxx17_std_apply ] ; diff --git a/test/from_chars.cpp b/test/from_chars.cpp index e74d9f0..4f66b7a 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -47,8 +47,8 @@ void base2_test() template void base16_test() { - // In base 16 0x and 0X prefixes are ignored - const char* buffer1 = "0x2a"; + // In base 16 0x and 0X prefixes are not allowed + const char* buffer1 = "2a"; T v1 = 0; auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1, 16); BOOST_TEST_EQ(r1.ec, 0); diff --git a/test/from_chars_STL_comp.cpp b/test/from_chars_STL_comp.cpp new file mode 100644 index 0000000..c31c2e5 --- /dev/null +++ b/test/from_chars_STL_comp.cpp @@ -0,0 +1,52 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +void test() +{ + // Base 2 + const char* base2 = "0101010"; + T base2_v_boost = 0; + T base2_v_stl = 0; + auto r1_boost = boost::charconv::from_chars(base2, base2 + std::strlen(base2), base2_v_boost, 2); + auto r1_stl = std::from_chars(base2, base2 + std::strlen(base2), base2_v_stl, 2); + BOOST_TEST_EQ(r1_boost.ptr, r1_stl.ptr); + BOOST_TEST_EQ(base2_v_boost, base2_v_stl); + + // Hexadecimal + const char* base16 = "0x2a"; + T base16_v_boost = 0; + T base16_v_stl = 0; + auto r2_boost = boost::charconv::from_chars(base16, base16 + std::strlen(base16), base16_v_boost, 16); + auto r2_stl = std::from_chars(base16, base16 + std::strlen(base16), base16_v_stl, 16); + BOOST_TEST_EQ(r2_boost.ptr, r2_stl.ptr); + BOOST_TEST_EQ(base16_v_boost, base16_v_stl); +} + +int main() +{ + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + test(); + + return boost::report_errors(); +} From 2c33b21dc22e61d67a001b7148a0e34746d61027 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 13 Jan 2023 11:43:06 -0800 Subject: [PATCH 26/31] Add more edge cases to comparison test --- test/from_chars_STL_comp.cpp | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/test/from_chars_STL_comp.cpp b/test/from_chars_STL_comp.cpp index c31c2e5..0a2e5b1 100644 --- a/test/from_chars_STL_comp.cpp +++ b/test/from_chars_STL_comp.cpp @@ -15,7 +15,7 @@ template void test() { - // Base 2 + // Binary const char* base2 = "0101010"; T base2_v_boost = 0; T base2_v_stl = 0; @@ -32,6 +32,39 @@ void test() auto r2_stl = std::from_chars(base16, base16 + std::strlen(base16), base16_v_stl, 16); BOOST_TEST_EQ(r2_boost.ptr, r2_stl.ptr); BOOST_TEST_EQ(base16_v_boost, base16_v_stl); + + base16 = "2a"; + r2_boost = boost::charconv::from_chars(base16, base16 + std::strlen(base16), base16_v_boost, 16); + r2_stl = std::from_chars(base16, base16 + std::strlen(base16), base16_v_stl, 16); + BOOST_TEST_EQ(r2_boost.ptr, r2_stl.ptr); + BOOST_TEST_EQ(base16_v_boost, base16_v_stl); + + // Decimal + const char* base10 = "42"; + T base10_v_boost = 0; + T base10_v_stl = 0; + auto r3_boost = boost::charconv::from_chars(base10, base10 + std::strlen(base10), base10_v_boost); + auto r3_stl = std::from_chars(base10, base10 + std::strlen(base10), base10_v_stl); + BOOST_TEST_EQ(r3_boost.ptr, r3_stl.ptr); + BOOST_TEST_EQ(base10_v_boost, base10_v_stl); + + // Negative number + const char* neg = "-100"; + T negative_v_boost = 0; + T negative_v_stl = 0; + auto r4_boost = boost::charconv::from_chars(neg, neg + std::strlen(neg), negative_v_boost); + auto r4_stl = std::from_chars(neg, neg + std::strlen(neg), negative_v_stl); + BOOST_TEST_EQ(r4_boost.ptr, r4_stl.ptr); + BOOST_TEST_EQ(negative_v_boost, negative_v_stl); + + // Digit seperator + const char* sep = "1'000"; + T sep_v_boost = 0; + T sep_v_stl = 0; + auto r5_boost = boost::charconv::from_chars(sep, sep + std::strlen(sep), sep_v_boost); + auto r5_stl = std::from_chars(sep, sep + std::strlen(sep), sep_v_stl); + BOOST_TEST_EQ(r5_boost.ptr, r5_stl.ptr); + BOOST_TEST_EQ(sep_v_boost, sep_v_stl); } int main() From 880c4d206834304d3199ab9171b5f4d4ca6d98ae Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Fri, 13 Jan 2023 12:47:55 -0800 Subject: [PATCH 27/31] Workaround for non-compliant compilers --- test/from_chars_STL_comp.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/from_chars_STL_comp.cpp b/test/from_chars_STL_comp.cpp index 0a2e5b1..7823a34 100644 --- a/test/from_chars_STL_comp.cpp +++ b/test/from_chars_STL_comp.cpp @@ -2,6 +2,10 @@ // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt +#include + +#if !defined(BOOST_NO_CXX17_HDR_CHARCONV) && (!defined(__clang_major__) || (defined(__clang_major__) && __clang_major__ > 7)) + #include #include #include @@ -83,3 +87,12 @@ int main() return boost::report_errors(); } + +#else + +int main() +{ + return 0; +} + +#endif From 8a7f593bcd61c9d9f21cdf16e18954c83b77abc6 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Sat, 14 Jan 2023 17:11:45 -0800 Subject: [PATCH 28/31] Add 128bit int tests --- test/from_chars.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 4f66b7a..355e2df 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -12,6 +12,23 @@ #include #include +#ifdef __GLIBCXX_TYPE_INT_N_0 +// __int128 is incompatible with BOOST_TEST because there is not a defined overload +// for operator<< for I/O +template +void test_128bit_int() +{ + const char* buffer1 = "85070591730234615865843651857942052864"; // 2^126 + T test_value = 1; + test_value = test_value << 126; + T v1 = 0; + auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1); + BOOST_CHARCONV_ASSERT(r1.ec == 0); + BOOST_CHARCONV_ASSERT(v1 == test_value); + BOOST_CHARCONV_ASSERT(std::numeric_limits::max() > static_cast(std::numeric_limits::max())); +} +#endif // 128-bit testing + #ifndef BOOST_NO_CXX14_CONSTEXPR template constexpr std::pair constexpr_test_helper() @@ -167,5 +184,11 @@ int main() # endif #endif + // Only compiles using cxxstd-dialect=gnu or equivalent + #ifdef __GLIBCXX_TYPE_INT_N_0 + test_128bit_int<__int128>(); + test_128bit_int(); + #endif + return boost::report_errors(); } From 1591042d70e9d429de5b439eb4a880b2de212f46 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 16 Jan 2023 08:01:58 -0800 Subject: [PATCH 29/31] Add documentation --- doc/charconv.adoc | 5 +- doc/charconv.html | 981 ++++++++++++++++++++++++ doc/charconv/copyright.adoc | 2 +- doc/charconv/from_chars.adoc | 86 +++ doc/charconv/overview.adoc | 22 +- doc/charconv/reference.adoc | 16 +- reporting/performance/charcov_benchmark | Bin 0 -> 327902 bytes 7 files changed, 1093 insertions(+), 19 deletions(-) create mode 100644 doc/charconv.html create mode 100644 doc/charconv/from_chars.adoc create mode 100755 reporting/performance/charcov_benchmark diff --git a/doc/charconv.adoc b/doc/charconv.adoc index b3bd8c4..022fd17 100644 --- a/doc/charconv.adoc +++ b/doc/charconv.adoc @@ -4,8 +4,8 @@ Distributed under the Boost Software License, Version 1.0. https://www.boost.org/LICENSE_1_0.txt //// -# CharConv: An Implementation of in {cpp}11 -Peter Dimov += CharConv: An Implementation of in {cpp}11 +Peter Dimov and Matt Borland :toc: left :toclevels: 4 :idprefix: @@ -17,6 +17,7 @@ Peter Dimov :leveloffset: +1 include::charconv/overview.adoc[] +include::charconv/from_chars.adoc[] include::charconv/reference.adoc[] include::charconv/copyright.adoc[] diff --git a/doc/charconv.html b/doc/charconv.html new file mode 100644 index 0000000..5fc9ee3 --- /dev/null +++ b/doc/charconv.html @@ -0,0 +1,981 @@ + + + + + + + + +CharConv: An Implementation of <charconv> in C++11 + + + + + + +
+
+

Overview

+
+
+

Description

+
+

Charconv is a collection of parsing functions that are locale-independent, non-allocating, and non-throwing.

+
+
+
+

Usage Examples

+
+
+
#include <boost/charconv.hpp>
+
+const char* buffer = "42";
+int v = 0;
+auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
+assert(r == 42);
+
+
+
+
+

Supported Compilers

+
+
    +
  • +

    GCC 5 or later with -std=c++11 or above

    +
  • +
  • +

    Clang 3.9 or later with -std=c++11 or above

    +
  • +
  • +

    Visual Studio 2015, 2017, 2019

    +
  • +
+
+
+

Tested on Github Actions.

+
+
+
+
+
+

from_chars

+
+
+

from_chars overview

+
+
+
struct from_chars_result
+{
+    const char* ptr;
+    int ec;
+
+    friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept
+    friend constexpr bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept
+}
+
+template <typename Integral>
+BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept;
+
+BOOST_CXX14_CONSTEXPR from_chars_result from_chars<bool>(const char* first, const char* last, bool& value, int base) = delete;
+
+
+
+
+

from_chars_result

+
+
    +
  • +

    ptr - points to the first character not matching the pattern, or has the value of last if all characters are successfully parsed.

    +
  • +
  • +

    ec - the error code. Valid values for <cerrno> are:

    +
    +
      +
    • +

      0 - successful parsing

      +
    • +
    • +

      EINVAL - invalid argument (e.g. parsing a negative number into an unsigned type)

      +
    • +
    • +

      ERANGE - result out of range (e.g. overflow)

      +
    • +
    +
    +
  • +
  • +

    operator== - compares the values of ptr and ec for equality

    +
  • +
  • +

    operator!- - compares the value of ptr and ec for inequality

    +
  • +
+
+
+
+

from_chars

+
+
    +
  • +

    first, last - valid range to parse

    +
  • +
  • +

    value - where the output is stored upon successful parsing

    +
  • +
  • +

    base - the integer base to use. Must be between 2 and 36 inclusive

    +
  • +
  • +

    from_chars for integral types is constexpr when compiled using -std=c++14 or newer

    +
    +
      +
    • +

      One known exception is GCC 5 which does not support constexpr comparison of const char*.

      +
    • +
    +
    +
  • +
+
+
+
+

from_chars for integral types

+
+
    +
  • +

    All built-in integral types are allowed except bool which is deleted

    +
  • +
  • +

    These function have been tested to support int128 and unsigned int128 when compiling with -std=gnu++11 or newer

    +
  • +
+
+
+
+

Examples

+
+

Basic usage

+
+
+
const char* buffer = "42";
+int v = 0;
+from_chars_result r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
+assert(r.ec == 0);
+assert(v == 42);
+
+
+
+
+

Hexadecimal

+
+
+
const char* buffer = "2a";
+unsigned v = 0;
+auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, 16);
+assert(r.ec == 0);
+assert(v == 42);
+
+
+
+
+

EINVAL

+
+
+
const char* buffer = "-123";
+unsigned v = 0;
+auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
+assert(r.ec, EINVAL);
+assert(v == 0);
+
+
+
+

In the event of EINVAL v is not set by from_chars

+
+
+
+

ERANGE

+
+
+
const char* buffer = "1234";
+unsigned char v = 0;
+auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
+assert(r.ec == ERANGE);
+assert(v == 0)
+
+
+
+

In the event of ERANGE v is not set by from_chars

+
+
+
+
+
+
+

Reference

+
+
+

<boost/charconv/from_chars.hpp>

+
+

Synopsis

+
+
+
namespace boost {
+namespace charconv {
+
+struct from_chars_result;
+
+template <typename Integral>
+BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept;
+
+// ...
+
+} // namespace charconv
+} // namespace boost
+
+
+
+
+
+

<boost/charconv/to_chars.hpp>

+
+

Synopsis

+
+
+
namespace boost {
+namespace charconv {
+
+struct to_chars_result;
+
+template<class Integral>
+to_chars_result to_chars( char* first, char* last, Integral value, int base = 10 );
+
+// ...
+
+} // namespace charconv
+} // namespace boost
+
+
+
+
+
+

<boost/charconv.hpp>

+
+

This convenience header includes all headers previously +mentioned.

+
+
+
+
+
+ +
+
+

This documentation is copyright 2022-2023 Peter Dimov and Matt Borland and is distributed under +the Boost Software License, Version 1.0.

+
+
+
+
+ + + + \ No newline at end of file diff --git a/doc/charconv/copyright.adoc b/doc/charconv/copyright.adoc index 2defdc8..5e4a1c4 100644 --- a/doc/charconv/copyright.adoc +++ b/doc/charconv/copyright.adoc @@ -8,5 +8,5 @@ https://www.boost.org/LICENSE_1_0.txt # Copyright and License :idprefix: -This documentation is copyright 2022 Peter Dimov and is distributed under +This documentation is copyright 2022-2023 Peter Dimov and Matt Borland and is distributed under the http://www.boost.org/LICENSE_1_0.txt[Boost Software License, Version 1.0]. diff --git a/doc/charconv/from_chars.adoc b/doc/charconv/from_chars.adoc new file mode 100644 index 0000000..704702b --- /dev/null +++ b/doc/charconv/from_chars.adoc @@ -0,0 +1,86 @@ +//// +Copyright 2023 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + += from_chars +:idprefix: from_chars_ + +== from_chars overview +``` +struct from_chars_result +{ + const char* ptr; + int ec; + + friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept + friend constexpr bool operator!=(const from_chars_result& lhs, const from_chars_result& rhs) noexcept +} + +template +BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept; + +BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, bool& value, int base) = delete; +``` + +== from_chars_result +* ptr - points to the first character not matching the pattern, or has the value of last if all characters are successfully parsed. +* ec - the error code. Valid values for are: +** 0 - successful parsing +** EINVAL - invalid argument (e.g. parsing a negative number into an unsigned type) +** ERANGE - result out of range (e.g. overflow) +* operator== - compares the values of ptr and ec for equality +* operator!- - compares the value of ptr and ec for inequality + +== from_chars +* first, last - valid range to parse +* value - where the output is stored upon successful parsing +* base - the integer base to use. Must be between 2 and 36 inclusive +* from_chars for integral types is constexpr when compiled using `-std=c++14` or newer +** One known exception is GCC 5 which does not support constexpr comparison of const char*. + +== from_chars for integral types +* All built-in integral types are allowed except bool which is deleted +* These function have been tested to support `__int128` and `unsigned __int128` when compiling with `-std=gnu++11` or newer + +== Examples + +=== Basic usage +``` +const char* buffer = "42"; +int v = 0; +from_chars_result r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r.ec == 0); +assert(v == 42); +``` + +=== Hexadecimal +``` +const char* buffer = "2a"; +unsigned v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, 16); +assert(r.ec == 0); +assert(v == 42); +``` + +=== EINVAL +``` +const char* buffer = "-123"; +unsigned v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r.ec, EINVAL); +assert(v == 0); +``` +In the event of EINVAL v is not set by `from_chars` + + +=== ERANGE +``` +const char* buffer = "1234"; +unsigned char v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r.ec == ERANGE); +assert(v == 0) +``` +In the event of ERANGE v is not set by `from_chars` diff --git a/doc/charconv/overview.adoc b/doc/charconv/overview.adoc index 9b3da93..7c14230 100644 --- a/doc/charconv/overview.adoc +++ b/doc/charconv/overview.adoc @@ -5,22 +5,28 @@ https://www.boost.org/LICENSE_1_0.txt //// [#overview] -# Overview += Overview :idprefix: overview_ -## Description +== Description -... +Charconv is a collection of parsing functions that are locale-independent, non-allocating, and non-throwing. -## Usage Examples +== Usage Examples -... +``` +#include -## Supported Compilers +const char* buffer = "42"; +int v = 0; +auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v); +assert(r == 42); +``` + +== Supported Compilers * GCC 5 or later with `-std=c++11` or above * Clang 3.9 or later with `-std=c++11` or above * Visual Studio 2015, 2017, 2019 -Tested on https://github.com/cppalliance/charconv/actions[Github Actions] and -https://ci.appveyor.com/project/cppalliance/charconv[Appveyor]. +Tested on https://github.com/cppalliance/charconv/actions[Github Actions]. diff --git a/doc/charconv/reference.adoc b/doc/charconv/reference.adoc index b9c8266..1e7c89b 100644 --- a/doc/charconv/reference.adoc +++ b/doc/charconv/reference.adoc @@ -5,12 +5,12 @@ https://www.boost.org/LICENSE_1_0.txt //// [#reference] -# Reference += Reference :idprefix: ref_ -## +== -### Synopsis +=== Synopsis ``` namespace boost { @@ -18,8 +18,8 @@ namespace charconv { struct from_chars_result; -template -from_chars_result from_chars( const char* first, const char* last, Integral& value, int base = 10 ); +template +BOOST_CXX14_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integral& value, int base = 10) noexcept; // ... @@ -27,9 +27,9 @@ from_chars_result from_chars( const char* first, const char* last, Integral& val } // namespace boost ``` -## +== -### Synopsis +=== Synopsis ``` namespace boost { @@ -46,7 +46,7 @@ to_chars_result to_chars( char* first, char* last, Integral value, int base = 10 } // namespace boost ``` -## +== This convenience header includes all headers previously mentioned. diff --git a/reporting/performance/charcov_benchmark b/reporting/performance/charcov_benchmark new file mode 100755 index 0000000000000000000000000000000000000000..326eb549cd30ec05e7627fa42da0e234c08a949d GIT binary patch literal 327902 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 JE8|S@xd6T3cEkVx literal 0 HcmV?d00001 From 231840d36da93e673ec90e087ddf7cfa2f429703 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 16 Jan 2023 08:45:03 -0800 Subject: [PATCH 30/31] Replace cassert with boost.assert --- include/boost/charconv/config.hpp | 12 +++++++++--- test/from_chars.cpp | 8 +++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/boost/charconv/config.hpp b/include/boost/charconv/config.hpp index 0a472e9..bbafb51 100644 --- a/include/boost/charconv/config.hpp +++ b/include/boost/charconv/config.hpp @@ -6,7 +6,6 @@ // 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 @@ -35,7 +34,14 @@ #endif -#define BOOST_CHARCONV_ASSERT(expr) assert(expr) -#define BOOST_CHARCONV_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) +#ifndef BOOST_CHARCONV_STANDALONE +# include +# define BOOST_CHARCONV_ASSERT(expr) BOOST_ASSERT(expr) +# define BOOST_CHARCONV_ASSERT_MSG(expr, msg) BOOST_ASSERT_MSG(expr, msg) +#else // Use plain asserts +# include +# define BOOST_CHARCONV_ASSERT(expr) assert(expr) +# define BOOST_CHARCONV_ASSERT_MSG(expr, msg) assert((expr)&&(msg)) +#endif #endif // BOOST_CHARCONV_CONFIG_HPP_INCLUDED diff --git a/test/from_chars.cpp b/test/from_chars.cpp index 355e2df..23ac5ad 100644 --- a/test/from_chars.cpp +++ b/test/from_chars.cpp @@ -13,8 +13,6 @@ #include #ifdef __GLIBCXX_TYPE_INT_N_0 -// __int128 is incompatible with BOOST_TEST because there is not a defined overload -// for operator<< for I/O template void test_128bit_int() { @@ -23,9 +21,9 @@ void test_128bit_int() test_value = test_value << 126; T v1 = 0; auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1); - BOOST_CHARCONV_ASSERT(r1.ec == 0); - BOOST_CHARCONV_ASSERT(v1 == test_value); - BOOST_CHARCONV_ASSERT(std::numeric_limits::max() > static_cast(std::numeric_limits::max())); + BOOST_TEST(r1.ec == 0); + BOOST_TEST(v1 == test_value); + BOOST_TEST(std::numeric_limits::max() > static_cast(std::numeric_limits::max())); } #endif // 128-bit testing From 9c438e59d32e0a165ccd39d005bf4f10ac546944 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Mon, 16 Jan 2023 09:27:23 -0800 Subject: [PATCH 31/31] Add boost.assert to cmake --- CMakeLists.txt | 1 + test/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d299f57..36335f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ target_include_directories(boost_charconv PUBLIC include) target_link_libraries(boost_charconv PUBLIC Boost::config + Boost::assert ) target_compile_features(boost_charconv PUBLIC cxx_std_11) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b8cee3d..6e2c396 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,6 +6,6 @@ include(BoostTestJamfile OPTIONAL RESULT_VARIABLE HAVE_BOOST_TEST) if(HAVE_BOOST_TEST) -boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::charconv Boost::core) +boost_test_jamfile(FILE Jamfile LINK_LIBRARIES Boost::charconv Boost::core Boost::assert) endif()