Merge pull request #42 from mborland/system_error

Use `std::errc` as the error code instead of errno values
This commit is contained in:
Matt Borland
2023-05-18 13:30:33 +02:00
committed by GitHub
21 changed files with 307 additions and 263 deletions

View File

@@ -13,7 +13,7 @@ https://www.boost.org/LICENSE_1_0.txt
struct from_chars_result
{
const char* ptr;
int ec;
std::errc 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
@@ -30,10 +30,10 @@ from_chars_result from_chars(const char* first, const char* last, Real& value, c
== 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)
* ec - the error code. Valid values for are:
** std::errc() - successful parsing
** std::errc::invalid_argument - invalid argument (e.g. parsing a negative number into an unsigned type)
** std::errc::result_out_of_range - 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
@@ -50,7 +50,7 @@ from_chars_result from_chars(const char* first, const char* last, Real& value, c
** One known exception is GCC 5 which does not support constexpr comparison of `const char*`.
=== from_chars for floating point types
* On ERANGE we return ±0 for small values (e.g. 1.0e-99999) or ±HUGE_VAL for large values (e.g. 1.0e+99999) to match the handling of `std::strtod`.
* On std::errc::result_out_of_range we return ±0 for small values (e.g. 1.0e-99999) or ±HUGE_VAL for large values (e.g. 1.0e+99999) to match the handling of `std::strtod`.
This is a divergence from the standard which states we should return the `value` argument unmodified.
== Examples
@@ -62,7 +62,7 @@ This is a divergence from the standard which states we should return the `value`
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(r.ec == std::errc());
assert(v == 42);
----
==== Floating Point
@@ -71,7 +71,7 @@ assert(v == 42);
const char* buffer = "1.2345"
double v = 0;
auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
assert(r.ec == 0);
assert(r.ec == std::errc());
assert(v == 1.2345);
----
@@ -82,7 +82,7 @@ assert(v == 1.2345);
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(r.ec == std::errc());
assert(v == 42);
----
==== Floating Point
@@ -91,34 +91,34 @@ assert(v == 42);
const char* buffer = "1.3a2bp-10";
double v = 0;
auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, boost::charconv::chars_format::hex);
assert(r.ec == 0);
assert(r.ec == std::errc());
assert(v == 8.0427e-18);
----
=== EINVAL
=== std::errc::invalid_argument
[source, c++]
----
const char* buffer = "-123";
unsigned v = 0;
auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
assert(r.ec == EINVAL);
assert(r.ec == std::errc::invalid_argument);
----
[source, c++]
----
const char* buffer = "-1.573e-3";
double v = 0;
auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v, boost::charconv::chars_format::fixed);
assert(r.ec == EINVAL);
assert(r.ec == std::errc::invalid_argument);
----
In the event of EINVAL v is not set by `from_chars`
Note: In the event of std::errc::invalid_argument v is not modified by `from_chars`
=== ERANGE
=== std::errc::result_out_of_range
[source, c++]
----
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(r.ec == std::errc::result_out_of_range);
assert(v == 0)
----
In the event of ERANGE v is not set by `from_chars`
Note: In the event of std::errc::result_out_of_range v is not modified by `from_chars`

View File

@@ -22,11 +22,13 @@ This library requires a minimum of C++11.
const char* buffer = "42";
int v = 0;
auto r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), v);
assert(r == 42);
assert(r.ec == std::errc());
assert(v == 42);
char buffer[64];
int v = 123456;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == std::errc());
assert(!strncmp(buffer, "123456", 6)); // Strncmp returns 0 on match
----

View File

@@ -38,15 +38,15 @@ from_chars_result from_chars(const char* first, const char* last, Real& value, c
struct from_chars_result
{
char const* ptr;
int ec;
std::errc ec;
};
----
`from_chars_result` is the return type of the `from_chars` family of
overloaded functions.
The `ec` member is zero when the conversion was successful, `EINVAL`
when no prefix of the passed characters form a valid value, or `ERANGE`
The `ec` member is `std::errc()` when the conversion was successful, `std::errc::invalid_argument`
when no prefix of the passed characters form a valid value, or `std::errc::result_out_of_range`
when the characters form a value that would be out of range for the type.
The `ptr` member points to the first character not part of the matched
@@ -66,8 +66,8 @@ Effects:;; Attempts to interpret the characters in `[first, last)` as a numeric
consisting of an optional minus sign (only if the type is signed), and a sequence of digits. For
bases above 10, the digit characters are `Aa` to `Zz`, as appropriate for `base`.
Returns:;; The `ec` member of the return value is `0` on success, `EINVAL` if
`[first, last)` can't be interpreted as an integer of base `base`, and `ERANGE`
Returns:;; The `ec` member of the return value is `std::errc()` on success, `std::errc::invalid_argument` if
`[first, last)` can't be interpreted as an integer of base `base`, and `std::errc::result_out_of_range`
if `[first, last)` when interpreted as an integer of base `base` can't be represented
as a value of type `Integral`. The `ptr` member of the return value points to the first
character in `[first, last)` that is not part of the matched value, or is `last` when
@@ -84,8 +84,8 @@ Requires:;; `fmt` has the value of one of the enumerators of chars_format
Effects:;; value is converted to a string in the style of printf in the "C" locale with the given precision. If a precision is not provided the shortest representation will be given.
Returns:;; The `ec` member of the return value is `0` on success.
`EINVAL` is returned if the value can't be interpreted with the given format `fmt`.
`ERANGE` is returned when the value can't be represented in the target floating point type.
`std::errc::invalid_argument` is returned if the value can't be interpreted with the given format `fmt`.
`std::errc::result_out_of_range` is returned when the value can't be represented in the target floating point type.
The `ptr` member of the return value points to the first character in `[first, last)` that is not part of the matched value, or is `last` when all characters are matched.
== <boost/charconv/to_chars.hpp>
@@ -117,18 +117,18 @@ to_chars_result to_chars(char* first, char* last, Real value, chars_format fmt =
struct to_chars_result
{
char const* ptr;
int ec;
std::errc ec;
};
----
`to_chars_result` is the return type of the `to_chars` family of
overloaded functions.
The `ec` member is zero when the conversion was successful, or `EOVERFLOW`
The `ec` member is `std::errc()` when the conversion was successful, or `std::errc::result_out_of_range`
when the value cannot fit into the provided buffer.
The `ptr` member points to the first character after the characters written,
or `last` when `ec` is `EOVERFLOW`.
or `last` when `ec` is `std::errc::result_out_of_range`.
=== to_chars
@@ -145,10 +145,10 @@ Effects:;; The value of `value` is converted to a string of digits in the given
Digits in the range 10..35 (inclusive) are represented as lowercase characters
`a`..`z`. If value is less than zero, the representation starts with a minus sign.
Returns:;; The `ec` member of the return value is `0` on success, and `EOVERFLOW` if
Returns:;; The `ec` member of the return value is `std::errc()` on success, and `std::errc::result_out_of_range` if
`[first, last)` does not contain enough space to hold the string representation of
`value`. The `ptr` member of the return value points to the character in `[first, last]`
that is one past the storted characters, or is `last` when `ec` is `EOVERFLOW`.
that is one past the parsed characters, or is `last` when `ec` is `std::errc::result_out_of_range`.
[source, c++]
----
@@ -161,10 +161,10 @@ Requires:;; fmt has the value of one of the enumerators of chars_format
Effects:;; value is converted to a string in the style of printf in the "C" locale with the given precision.
If no precision is provided the value character string will be the shortest representation of `value`
Returns:;; The `ec` member of the return value is `0` on success, and `EOVERFLOW` if
Returns:;; The `ec` member of the return value is `std::errc()` on success, and `std::errc::result_out_of_range` if
`[first, last)` does not contain enough space to hold the string representation of
`value`. The `ptr` member of the return value points to the character in `[first, last]`
that is one past the storted characters, or is `last` when `ec` is `EOVERFLOW`.
that is one past the parsed characters, or is `last` when `ec` is `std::errc::result_out_of_range`.
== <boost/charconv/limits.hpp>

View File

@@ -13,7 +13,7 @@ https://www.boost.org/LICENSE_1_0.txt
struct to_chars_result
{
char* ptr;
int ec;
std::errc ec;
friend constexpr bool operator==(const to_chars_result& lhs, const to_chars_result& rhs) noexcept;
friend constexpr bool operator!=(const to_chars_result& lhs, const to_chars_result& rhs) noexcept;
@@ -31,16 +31,16 @@ to_chars_result(char* first, char* last, Real value, chars_format fmt = chars_fo
== to_chars_result
* ptr - points to the first character
* ec - the error code. Valid values from <cerrno> are:
* ec - the error code. Valid values from are:
** 0 - successful parsing
** EINVAL - invalid argument
** ERANGE - result out of range (e.g. overflow)
** std::errc::invalid_argument - invalid argument
** std::errc::result_out_of_range - result out of range (e.g. overflow)
* operator== - compares the value of ptr and ec for equality
* operator!= - compares the value of ptr and ec for inequality
== to_chars
* first, last - pointers to the character buffer
* value - the value to be paresed into the buffer
* value - the value to be parsed into the buffer
* base (integer only) - the integer base to use. Must be between 2 and 36 inclusive
* fmt (float only) - the floating point format to use.
See xref:chars_format.adoc[chars_format overview] for description.
@@ -67,7 +67,7 @@ See xref:chars_format.adoc[chars_format overview] for description.
char buffer[64] {};
int v = 42;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == 0);
assert(r.ec == std::errc());
assert(!strcmp(buffer, "42")); // strcmp returns 0 on match
----
==== Floating Point
@@ -76,7 +76,7 @@ assert(!strcmp(buffer, "42")); // strcmp returns 0 on match
char buffer[64] {};
double v = 1e300;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ex == 0);
assert(r.ec == std::errc());
assert(!strcmp(buffer, "1e+300"));
----
@@ -87,7 +87,7 @@ assert(!strcmp(buffer, "1e+300"));
char buffer[64] {};
int v = 42;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v, 16);
assert(r.ec == 0);
assert(r.ec == std::errc());
assert(!strcmp(buffer, "2a")); // strcmp returns 0 on match
----
==== Floating Point
@@ -96,18 +96,18 @@ assert(!strcmp(buffer, "2a")); // strcmp returns 0 on match
char buffer[64] {};
double v = -1.08260383390082946e+307;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v, boost::charconv::chars_format::hex);
assert(r.ex == 0);
assert(r.ec == std::errc());
assert(!strcmp(buffer, "-1.ed5658af91a0fp+1019"));
----
=== ERANGE
=== std::errc::result_out_of_range
==== Integral
[source, c++]
----
char buffer[3] {};
int v = -1234;
to_chars_result r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v, 16);
assert(r.ec == ERANGE);
assert(r.ec == std::errc::result_out_of_range);
----
==== Floating Point
[source, c++]
@@ -115,7 +115,7 @@ assert(r.ec == ERANGE);
char buffer[3] {};
double v = 1.2345;
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, v);
assert(r.ec == ERANGE);
assert(r.ec == std::errc::result_out_of_range);
----
In the event of ERANGE to_chars_result.ptr is first
In the event of std::errc::result_out_of_range to_chars_result.ptr is equal to first

View File

@@ -10,6 +10,7 @@
#include <boost/charconv/detail/from_chars_result.hpp>
#include <boost/charconv/config.hpp>
#include <boost/config.hpp>
#include <system_error>
#include <type_traits>
#include <limits>
#include <cstdlib>
@@ -58,6 +59,10 @@ constexpr unsigned char digit_from_char(char val) noexcept
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Woverflow"
#elif defined(__GNUC__) && (__GNUC__ >= 9)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template <typename Integer, typename Unsigned_Integer>
@@ -70,7 +75,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
// Check pre-conditions
if (!((first <= last) && (base >= 2 && base <= 36)))
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
Unsigned_Integer unsigned_base = static_cast<Unsigned_Integer>(base);
@@ -95,7 +100,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
}
else if (*next == '+')
{
return {next, EINVAL};
return {next, std::errc::invalid_argument};
}
}
@@ -122,7 +127,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
{
if (next != last && (*next == '-' || *next == '+'))
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
#ifdef BOOST_CHARCONV_HAS_INT128
@@ -156,7 +161,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
// If the only character was a sign abort now
if (next == last)
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
bool overflowed = false;
@@ -186,7 +191,7 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
// If we have overflowed then we do not return the result
if (overflowed)
{
return {next, ERANGE};
return {next, std::errc::result_out_of_range};
}
value = static_cast<Integer>(result);
@@ -202,14 +207,14 @@ BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* firs
}
}
return {next, 0};
return {next, std::errc()};
}
#ifdef BOOST_MSVC
# pragma warning(pop)
#elif defined(__clang__) && defined(__APPLE__)
# pragma clang diagnostic pop
#elif defined(__GNUC__) && (__GNUC__ < 7)
#elif defined(__GNUC__) && (__GNUC__ < 7 || __GNUC__ >= 9)
# pragma GCC diagnostic pop
#endif

View File

@@ -5,6 +5,8 @@
#ifndef BOOST_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP
#define BOOST_CHARCONV_DETAIL_FROM_CHARS_RESULT_HPP
#include <system_error>
namespace boost { namespace charconv {
// 22.13.3, Primitive numerical input conversion
@@ -17,7 +19,7 @@ struct from_chars_result
// 0 = no error
// EINVAL = invalid_argument
// ERANGE = result_out_of_range
int ec;
std::errc ec;
friend constexpr bool operator==(const from_chars_result& lhs, const from_chars_result& rhs) noexcept
{

View File

@@ -11,6 +11,7 @@
#include <boost/charconv/detail/integer_search_trees.hpp>
#include <boost/charconv/limits.hpp>
#include <boost/charconv/chars_format.hpp>
#include <system_error>
#include <type_traits>
#include <limits>
#include <cerrno>
@@ -29,7 +30,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
if (first > last)
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
auto next = first;
@@ -43,7 +44,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
}
else if (*next == '+')
{
return {next, EINVAL};
return {next, std::errc::invalid_argument};
}
else
{
@@ -74,7 +75,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
significand = 0;
exponent = 0;
return {next, 0};
return {next, std::errc()};
}
// Next we get the significand
@@ -99,7 +100,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
// if fmt is chars_format::scientific the e is required
if (fmt == chars_format::scientific)
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
exponent = 0;
@@ -116,12 +117,12 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
}
switch (r.ec)
{
case EINVAL:
return {first, EINVAL};
case ERANGE:
return {next, ERANGE};
case std::errc::invalid_argument:
return {first, std::errc::invalid_argument};
case std::errc::result_out_of_range:
return {next, std::errc::result_out_of_range};
default:
return {next, 0};
return {next, std::errc()};
}
}
else if (*next == '.')
@@ -148,7 +149,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
if (next == last)
{
return {last, 0};
return {last, std::errc()};
}
}
@@ -183,7 +184,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
if (fmt == chars_format::scientific)
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
if (dot_position != 0 || fractional)
{
@@ -206,12 +207,12 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
}
switch (r.ec)
{
case EINVAL:
return {first, EINVAL};
case ERANGE:
return {next, ERANGE};
case std::errc::invalid_argument:
return {first, std::errc::invalid_argument};
case std::errc::result_out_of_range:
return {next, std::errc::result_out_of_range};
default:
return {next, 0};
return {next, std::errc()};
}
}
else if (*next == exp_char || *next == capital_exp_char)
@@ -219,13 +220,13 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
// Would be a number without a significand e.g. e+03
if (next == first)
{
return {next, EINVAL};
return {next, std::errc::invalid_argument};
}
++next;
if (fmt == chars_format::fixed)
{
return {first, EINVAL};
return {first, std::errc::invalid_argument};
}
exponent = i - 1;
@@ -249,7 +250,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
from_chars_result r {};
// If the significand is 0 from chars will return EINVAL because there is nothing in the buffer,
// If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer,
// but it is a valid value. We need to continue parsing to get the correct value of ptr even
// though we know we could bail now.
//
@@ -263,12 +264,15 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
r = from_chars(significand_buffer, significand_buffer + offset, significand);
}
switch (r.ec)
{
case EINVAL:
return {first, EINVAL};
case ERANGE:
return {next, ERANGE};
case std::errc::invalid_argument:
return {first, std::errc::invalid_argument};
case std::errc::result_out_of_range:
return {next, std::errc::result_out_of_range};
default:
break;
}
if (round)
@@ -313,7 +317,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
// If the exponent can't fit in the buffer the number is not representable
if (next != last && i == exponent_buffer_size)
{
return {next, ERANGE};
return {next, std::errc::result_out_of_range};
}
// If the exponent was e+00 or e-00
@@ -328,7 +332,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
exponent = extra_zeros;
}
return {next, 0};
return {next, std::errc()};
}
const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent);
@@ -337,10 +341,10 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
switch (r.ec)
{
case EINVAL:
return {first, EINVAL};
case ERANGE:
return {next, ERANGE};
case std::errc::invalid_argument:
return {first, std::errc::invalid_argument};
case std::errc::result_out_of_range:
return {next, std::errc::result_out_of_range};
default:
if (fractional)
{
@@ -360,7 +364,7 @@ inline from_chars_result parser(const char* first, const char* last, bool& sign,
{
exponent += extra_zeros;
}
return {next, 0};
return {next, std::errc()};
}
}

View File

@@ -15,6 +15,7 @@
#include <boost/charconv/detail/bit_layouts.hpp>
#include <boost/charconv/config.hpp>
#include <boost/charconv/chars_format.hpp>
#include <system_error>
#include <cmath>
namespace boost { namespace charconv {
@@ -108,7 +109,7 @@ from_chars_result from_chars_strtod(const char* first, const char* last, T& valu
return_value = std::strtof(first, &str_end);
if (return_value == HUGE_VALF)
{
return {last, ERANGE};
return {last, std::errc::result_out_of_range};
}
}
else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value)
@@ -116,7 +117,7 @@ from_chars_result from_chars_strtod(const char* first, const char* last, T& valu
return_value = std::strtod(first, &str_end);
if (return_value == HUGE_VAL)
{
return {last, ERANGE};
return {last, std::errc::result_out_of_range};
}
}
else
@@ -124,18 +125,18 @@ from_chars_result from_chars_strtod(const char* first, const char* last, T& valu
return_value = std::strtold(first, &str_end);
if (return_value == HUGE_VALL)
{
return {last, ERANGE};
return {last, std::errc::result_out_of_range};
}
}
// Since this is a fallback routine we are safe to check for 0
if (return_value == 0 && str_end == last)
{
return {first, EINVAL};
return {first, std::errc::result_out_of_range};
}
value = return_value;
return {str_end, 0};
return {str_end, std::errc()};
}
template <typename T>
@@ -146,7 +147,7 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
std::int64_t exponent {};
auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt);
if (r.ec != 0)
if (r.ec != std::errc())
{
return r;
}
@@ -173,7 +174,7 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
{
value = 1;
r.ptr = last;
r.ec = 0;
r.ec = std::errc();
}
else
{
@@ -182,12 +183,12 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
if (return_val == HUGE_VALF || return_val == -HUGE_VALF)
{
value = return_val;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else if (exponent < -46)
{
value = sign ? -0.0F : 0.0;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else
{
@@ -199,12 +200,12 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
if (return_val == HUGE_VAL || return_val == -HUGE_VAL)
{
value = return_val;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else if (exponent < -325)
{
value = sign ? -0.0 : 0.0;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else
{
@@ -216,7 +217,7 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
if (return_val == HUGE_VALL || return_val == -HUGE_VALL)
{
value = return_val;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
#if BOOST_CHARCONV_LDBL_BITS == 64
else if (exponent < -325)
@@ -225,7 +226,7 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
#endif
{
value = sign ? -0.0L : 0.0L;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else
@@ -243,6 +244,8 @@ from_chars_result from_chars_float_impl(const char* first, const char* last, T&
return r;
}
std::errc errno_to_errc(int errno_value) noexcept;
} // Namespace detail
#ifdef BOOST_MSVC

View File

@@ -16,6 +16,7 @@
#include <boost/charconv/detail/dragonbox.hpp>
#include <boost/charconv/config.hpp>
#include <boost/charconv/chars_format.hpp>
#include <system_error>
#include <type_traits>
#include <array>
#include <limits>
@@ -34,12 +35,7 @@ namespace boost { namespace charconv {
struct to_chars_result
{
char* ptr;
// Values:
// 0 = no error
// EINVAL = invalid_argument
// ERANGE = result_out_of_range
int ec;
std::errc ec;
constexpr friend bool operator==(const to_chars_result& lhs, const to_chars_result& rhs) noexcept
{
@@ -119,7 +115,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
if (first > last)
{
return {last, EINVAL};
return {last, std::errc::invalid_argument};
}
// Strip the sign from the value and apply at the end after parsing if the type is signed
@@ -155,7 +151,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
if (converted_value_digits > user_buffer_size)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
decompose32(converted_value, buffer);
@@ -175,7 +171,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
if (converted_value_digits > user_buffer_size)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
if (is_negative)
@@ -228,7 +224,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
}
}
return {first + converted_value_digits, 0};
return {first + converted_value_digits, std::errc()};
}
#ifdef BOOST_CHARCONV_HAS_INT128
@@ -248,7 +244,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
if (first > last)
{
return {last, EINVAL};
return {last, std::errc::invalid_argument};
}
// Strip the sign from the value and apply at the end after parsing if the type is signed
@@ -275,7 +271,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
if (converted_value_digits > user_buffer_size)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
if (is_negative)
@@ -314,7 +310,7 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_128integer_impl(char* first, c
offset += 9;
}
return {first + converted_value_digits, 0};
return {first + converted_value_digits, std::errc()};
}
#endif
@@ -327,13 +323,13 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
if (!((first <= last) && (base >= 2 && base <= 36)))
{
return {last, EINVAL};
return {last, std::errc::invalid_argument};
}
if (value == 0)
{
*first++ = '0';
return {first, 0};
return {first, std::errc()};
}
Unsigned_Integer unsigned_value {};
@@ -418,12 +414,12 @@ BOOST_CHARCONV_CONSTEXPR to_chars_result to_chars_integer_impl(char* first, char
if (num_chars > output_length)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
boost::charconv::detail::memcpy(first, buffer + (buffer_size - num_chars), num_chars);
return {first + num_chars, 0};
return {first + num_chars, std::errc()};
}
#ifdef BOOST_MSVC
@@ -469,7 +465,7 @@ to_chars_result to_chars_hex(char* first, char* last, Real value, int precision)
const std::ptrdiff_t buffer_size = last - first;
if (buffer_size < real_precision || first > last)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
// Handle edge cases first
@@ -481,14 +477,14 @@ to_chars_result to_chars_hex(char* first, char* last, Real value, int precision)
case FP_NAN:
// The dragonbox impl will return the correct type of NaN
ptr = boost::charconv::detail::to_chars(value, first, chars_format::general);
return { ptr, 0 };
return { ptr, std::errc() };
case FP_ZERO:
if (std::signbit(value))
{
*first++ = '-';
}
std::memcpy(first, "0p+0", 4);
return {first + 4, 0};
return {first + 4, std::errc()};
}
// Extract the significand and the exponent
@@ -552,7 +548,7 @@ to_chars_result to_chars_hex(char* first, char* last, Real value, int precision)
const std::ptrdiff_t total_length = (value < 0) + 2 + real_precision + 2 + num_digits(abs_unbiased_exponent);
if (total_length > buffer_size)
{
return {last, EOVERFLOW};
return {last, std::errc::result_out_of_range};
}
// Round if required
@@ -660,7 +656,7 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
}
auto r = to_chars_integer_impl(first, last, value_struct.significand);
if (r.ec != 0)
if (r.ec != std::errc())
{
return r;
}
@@ -679,7 +675,7 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
abs_value /= 10;
}
return { r.ptr, 0 };
return { r.ptr, std::errc() };
}
else if (abs_value >= max_fractional_value && abs_value < max_value)
{
@@ -692,13 +688,13 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
else
{
auto* ptr = boost::charconv::detail::to_chars(value, first, fmt);
return { ptr, 0 };
return { ptr, std::errc() };
}
}
else if (fmt == boost::charconv::chars_format::scientific)
{
auto* ptr = boost::charconv::detail::to_chars(value, first, fmt);
return { ptr, 0 };
return { ptr, std::errc() };
}
}
else
@@ -706,7 +702,7 @@ to_chars_result to_chars_float_impl(char* first, char* last, Real value, chars_f
if (fmt != boost::charconv::chars_format::hex)
{
auto* ptr = boost::charconv::detail::floff<boost::charconv::detail::main_cache_full, boost::charconv::detail::extended_cache_long>(value, precision, first, fmt);
return { ptr, 0 };
return { ptr, std::errc() };
}
}

View File

@@ -5,6 +5,7 @@
#include <boost/charconv/from_chars.hpp>
#include <boost/charconv/detail/bit_layouts.hpp>
#include <system_error>
#include <string>
#include <cstdlib>
@@ -12,6 +13,19 @@
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
std::errc boost::charconv::detail::errno_to_errc(int errno_value) noexcept
{
switch (errno_value)
{
case EINVAL:
return std::errc::invalid_argument;
case ERANGE:
return std::errc::result_out_of_range;
default:
return std::errc();
}
}
boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, float& value, boost::charconv::chars_format fmt) noexcept
{
return boost::charconv::detail::from_chars_float_impl(first, last, value, fmt);
@@ -43,7 +57,7 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first
std::int64_t exponent {};
auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt);
if (r.ec != 0)
if (r.ec != std::errc())
{
value = 0.0L;
return r;
@@ -54,7 +68,7 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first
if (!success)
{
value = 0.0L;
r.ec = ERANGE;
r.ec = std::errc::result_out_of_range;
}
else
{
@@ -107,7 +121,7 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first
value = std::strtold( tmp.c_str(), &ptr );
r.ptr = ptr;
r.ec = errno;
r.ec = detail::errno_to_errc(errno);
return r;
}

View File

@@ -578,6 +578,6 @@ boost::charconv::to_chars_result boost::charconv::to_chars(char* first, char* la
boost::charconv::to_chars_result boost::charconv::to_chars( char* first, char* last, long double value ) noexcept
{
std::snprintf( first, last - first, "%.*Lg", std::numeric_limits<long double>::max_digits10, value );
return { first + std::strlen(first), 0 };
return { first + std::strlen(first), std::errc() };
}
#endif

View File

@@ -5,6 +5,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <type_traits>
#include <limits>
#include <cstring>
@@ -21,7 +22,7 @@ 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_TEST(r1.ec == 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST(v1 == test_value);
BOOST_TEST(std::numeric_limits<T>::max() > static_cast<T>(std::numeric_limits<unsigned long long>::max()));
}
@@ -42,7 +43,7 @@ template <typename T>
constexpr void constexpr_test()
{
constexpr auto results = constexpr_test_helper<T>();
static_assert(results.second.ec == 0, "No error");
static_assert(results.second.ec == std::errc(), "No error");
static_assert(results.first == 42, "Value is 42");
}
@@ -55,7 +56,7 @@ void base2_test()
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(r1.ec == std::errc());
BOOST_TEST_EQ(v1, 42);
}
@@ -66,13 +67,13 @@ void base16_test()
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);
BOOST_TEST(r1.ec == std::errc());
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(r2.ec == std::errc());
BOOST_TEST_EQ(v2, 0);
}
@@ -85,18 +86,18 @@ void overflow_test()
BOOST_IF_CONSTEXPR((std::numeric_limits<T>::max)() < 1234)
{
BOOST_TEST_EQ(r1.ec, ERANGE);
BOOST_TEST(r1.ec == std::errc::result_out_of_range);
}
else
{
BOOST_TEST_EQ(r1.ec, 0) && BOOST_TEST_EQ(v1, 1234);
BOOST_TEST(r1.ec == std::errc()) && 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);
BOOST_TEST(r2.ec == std::errc::result_out_of_range) && BOOST_TEST_EQ(v2, 0);
}
template <typename T>
@@ -105,38 +106,38 @@ 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);
BOOST_TEST(r1.ec == std::errc::invalid_argument);
const char* buffer2 = "-";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, EINVAL);
BOOST_TEST(r2.ec == std::errc::invalid_argument);
const char* buffer3 = "+";
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST_EQ(r3.ec, EINVAL);
BOOST_TEST(r3.ec == std::errc::invalid_argument);
BOOST_IF_CONSTEXPR(std::is_unsigned<T>::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);
BOOST_TEST(r4.ec == std::errc::invalid_argument);
}
// Bases outside 2-36 inclusive return EINVAL
// Bases outside 2-36 inclusive return std::errc::invalid_argument
const char* buffer5 = "23";
T v5 = 0;
auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5, 1);
BOOST_TEST_EQ(r5.ec, EINVAL);
BOOST_TEST(r5.ec == std::errc::invalid_argument);
auto r6 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5, 50);
BOOST_TEST_EQ(r6.ec, EINVAL);
BOOST_TEST(r6.ec == std::errc::invalid_argument);
const char* buffer7 = "+12345";
T v7 = 3;
auto r7 = boost::charconv::from_chars(buffer7, buffer7 + std::strlen(buffer7), v7);
BOOST_TEST_EQ(r7.ec, EINVAL);
BOOST_TEST(r7.ec == std::errc::invalid_argument);
BOOST_TEST_EQ(v7, 3);
}
@@ -149,17 +150,17 @@ void simple_test()
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, 34);
BOOST_TEST( r.ec == std::errc() ) && BOOST_TEST_EQ(v, 34);
BOOST_TEST(r == r);
boost::charconv::from_chars_result r2 {r.ptr, 0};
boost::charconv::from_chars_result r2 {r.ptr, std::errc()};
BOOST_TEST(r == r2);
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);
BOOST_TEST(r3.ec == std::errc()) && BOOST_TEST_EQ(v2, 12);
}
int main()

View File

@@ -4,6 +4,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <iostream>
#include <iomanip>
#include <string>
@@ -17,7 +18,7 @@ void spot_value(const std::string& buffer, T expected_value, boost::charconv::ch
{
T v = 0;
auto r = boost::charconv::from_chars(buffer.c_str(), buffer.c_str() + std::strlen(buffer.c_str()), v, fmt);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
if (!BOOST_TEST_EQ(v, expected_value))
{
std::cerr << "Test failure for: " << buffer << " got: " << v << std::endl;
@@ -30,7 +31,7 @@ void overflow_spot_value(const std::string& buffer, T expected_value, boost::cha
auto v = static_cast<T>(42.L);
auto r = boost::charconv::from_chars(buffer.c_str(), buffer.c_str() + std::strlen(buffer.c_str()), v, fmt);
if (!(BOOST_TEST_EQ(v, expected_value) && BOOST_TEST_EQ(r.ec, ERANGE)))
if (!(BOOST_TEST_EQ(v, expected_value) && BOOST_TEST(r.ec == std::errc::result_out_of_range)))
{
std::cerr << "Test failure for: " << buffer << " got: " << v << std::endl;
}
@@ -55,13 +56,13 @@ void simple_integer_test()
const char* buffer1 = "12";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(12));
const char* buffer2 = "1200";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(1200));
}
@@ -71,7 +72,7 @@ void simple_hex_integer_test()
const char* buffer1 = "-2a";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(-42));
}
@@ -81,31 +82,31 @@ void simple_scientific_test()
const char* buffer1 = "1e1";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(1e1L));
const char* buffer2 = "123456789e10";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(123456789e10L));
const char* buffer3 = "1.23456789e+10";
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_EQ(v3, static_cast<T>(1.23456789e+10L));
const char* buffer4 = "1234.56789e+10";
T v4 = 0;
auto r4 = boost::charconv::from_chars(buffer4, buffer4 + std::strlen(buffer4), v4);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(v4, static_cast<T>(1234.56789e+10L));
const char* buffer5 = "+1234.56789e+10";
auto v5 = static_cast<T>(3.0L);
auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5);
BOOST_TEST_EQ(r5.ec, EINVAL);
BOOST_TEST(r5.ec == std::errc::invalid_argument);
BOOST_TEST_EQ(v5, static_cast<T>(3.0L));
}
@@ -115,13 +116,13 @@ void simple_hex_scientific_test()
const char* buffer1 = "1.3a2bp-10";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(80427e-14L));
const char* buffer2 = "1.234p-10";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(4660e-13L));
}
@@ -131,25 +132,25 @@ void dot_position_test()
const char* buffer1 = "11.11111111";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(11.11111111L));
const char* buffer2 = "1111.111111";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(1111.111111L));
const char* buffer3 = "111111.1111";
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_EQ(v3, static_cast<T>(111111.1111L));
const char* buffer4 = "1111111111.";
T v4 = 0;
auto r4 = boost::charconv::from_chars(buffer4, buffer4 + std::strlen(buffer4), v4);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(v4, static_cast<T>(1111111111.L));
}
@@ -159,37 +160,37 @@ void odd_strings_test()
const char* buffer1 = "00000000000000000000000000000000000000000005";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(5));
const char* buffer2 = "123456789123456789123456789";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(1.23456789123456789123456789e26L));
const char* buffer3 = "100000000000000000000000e5";
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_EQ(v3, static_cast<T>(100000000000000000000000e5L));
const char* buffer4 = "1.23456789123456789123456789123456789123456789e-5";
T v4 = 0;
auto r4 = boost::charconv::from_chars(buffer4, buffer4 + std::strlen(buffer4), v4);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(v4, static_cast<T>(1.23456789123456789123456789123456789123456789e-5L));
const char* buffer5 = "1.23456789123456789123456789123456789123456789e-00000000000000000005";
T v5 = 0;
auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5);
BOOST_TEST_EQ(r5.ec, 0);
BOOST_TEST(r5.ec == std::errc());
BOOST_TEST_EQ(v5, static_cast<T>(1.23456789123456789123456789123456789123456789e-5L));
const char* buffer6 = "E01";
T v6 = 0;
auto r6 = boost::charconv::from_chars(buffer6, buffer6 + std::strlen(buffer6), v6);
BOOST_TEST_EQ(r6.ec, EINVAL);
BOOST_TEST(r6.ec == std::errc::invalid_argument);
}
template <typename T>
@@ -198,42 +199,42 @@ void zero_test()
const char* buffer1 = "0e0";
T v1 = 0;
auto r1 = boost::charconv::from_chars(buffer1, buffer1 + std::strlen(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(v1, static_cast<T>(0));
BOOST_TEST(!std::signbit(v1));
const char* buffer2 = "-0e0";
T v2 = 0;
auto r2 = boost::charconv::from_chars(buffer2, buffer2 + std::strlen(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(v2, static_cast<T>(-0));
BOOST_TEST(std::signbit(v2));
const char* buffer3 = "0.0";
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_EQ(v3, static_cast<T>(0.0));
BOOST_TEST(!std::signbit(v3));
const char* buffer4 = "-0.0";
T v4 = 0;
auto r4 = boost::charconv::from_chars(buffer4, buffer4 + std::strlen(buffer4), v4);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(v4, static_cast<T>(-0));
BOOST_TEST(std::signbit(v4));
const char* buffer5 = "0";
T v5 = 0;
auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5);
BOOST_TEST_EQ(r5.ec, 0);
BOOST_TEST(r5.ec == std::errc());
BOOST_TEST_EQ(v5, static_cast<T>(0));
BOOST_TEST(!std::signbit(v5));
const char* buffer6 = "-0";
T v6 = 0;
auto r6 = boost::charconv::from_chars(buffer6, buffer6 + std::strlen(buffer6), v6);
BOOST_TEST_EQ(r6.ec, 0);
BOOST_TEST(r6.ec == std::errc());
BOOST_TEST_EQ(v6, static_cast<T>(-0));
BOOST_TEST(std::signbit(v6));
}

View File

@@ -61,6 +61,7 @@ std::ostream& operator<<( std::ostream& os, boost::int128_type v )
#include <boost/charconv/to_chars.hpp>
#include <boost/charconv/from_chars.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <limits>
void test_odr_use( int const* );
@@ -71,24 +72,24 @@ template<typename T> void test_integral( T value )
{
char buffer[ boost::charconv::limits<T>::max_chars10 ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST(r.ec == std::errc());
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 );
BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value );
BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value );
}
// base 10
{
char buffer[ boost::charconv::limits<T>::max_chars10 ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, 10 );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST(r.ec == std::errc());
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, 10 );
BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value );
BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value );
}
// any base
@@ -96,12 +97,12 @@ template<typename T> void test_integral( T value )
{
char buffer[ boost::charconv::limits<T>::max_chars ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, base );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST(r.ec == std::errc());
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, base );
BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value );
BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value );
}
}
@@ -123,24 +124,24 @@ template<typename T> void test_floating_point( T value )
{
char buffer[ boost::charconv::limits<T>::max_chars10 ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST(r.ec == std::errc());
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 );
BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value );
BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value );
}
// no base, max_chars
{
char buffer[ boost::charconv::limits<T>::max_chars ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST(r.ec == std::errc());
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 );
BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value );
BOOST_TEST(r2.ec == std::errc()) && BOOST_TEST_EQ( v2, value );
}
}

View File

@@ -59,6 +59,7 @@ std::ostream& operator<<( std::ostream& os, boost::int128_type v )
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <system_error>
#include <iostream>
#include <iomanip>
#include <limits>
@@ -72,18 +73,23 @@ static boost::detail::splitmix64 rng;
// integral types, random values
#if defined(__GNUC__) && (__GNUC__ == 12)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
template<class T> void test_roundtrip( T value, int base )
{
char buffer[ 256 ];
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, base );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST( r.ec == std::errc() );
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2, base );
if( BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value ) )
if( BOOST_TEST( r2.ec == std::errc() ) && BOOST_TEST_EQ( v2, value ) )
{
}
else
@@ -92,6 +98,10 @@ template<class T> void test_roundtrip( T value, int base )
}
}
#if defined(__GNUC__) && (__GNUC__ == 12)
# pragma GCC diagnostic pop
#endif
template<class T> void test_roundtrip_int8( int base )
{
for( int i = -256; i <= 255; ++i )
@@ -217,12 +227,12 @@ template<class T> void test_roundtrip( T value )
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST( r.ec == std::errc() );
T v2 = 0;
auto r2 = boost::charconv::from_chars( buffer, r.ptr, v2 );
if( BOOST_TEST_EQ( r2.ec, 0 ) && BOOST_TEST_EQ( v2, value ) )
if( BOOST_TEST( r2.ec == std::errc() ) && BOOST_TEST_EQ( v2, value ) )
{
}
else

View File

@@ -9,6 +9,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <vector>
#include <iostream>
#include <iomanip>
@@ -25,7 +26,7 @@ void grind(const std::string& str, const T expected_value)
// From string to expected value
T v {};
auto from_r = boost::charconv::from_chars(str.c_str(), str.c_str() + std::strlen(str.c_str()), v);
if (!(BOOST_TEST_EQ(v, expected_value) && BOOST_TEST_EQ(from_r.ec, 0)))
if (!(BOOST_TEST_EQ(v, expected_value) && BOOST_TEST(from_r.ec == std::errc())))
{
std::cerr << "Expected value: " << expected_value << "\nFrom chars value: " << v << std::endl;
return;
@@ -35,10 +36,10 @@ void grind(const std::string& str, const T expected_value)
T roundtrip_v {};
char buffer[256] {};
auto to_r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), expected_value);
BOOST_TEST_EQ(to_r.ec, 0);
BOOST_TEST(to_r.ec == std::errc());
auto roundtrip_r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), roundtrip_v);
if (!(BOOST_TEST_EQ(roundtrip_v, expected_value) && BOOST_TEST_EQ(roundtrip_r.ec, 0)))
if (!(BOOST_TEST_EQ(roundtrip_v, expected_value) && BOOST_TEST(roundtrip_r.ec == std::errc())))
{
std::cerr << "Expected value: " << expected_value << "\nRoundtrip value: " << roundtrip_v << std::endl;
return;
@@ -65,7 +66,7 @@ void spot_value(const std::string& buffer, T expected_value)
{
T v = 0;
auto r = boost::charconv::from_chars(buffer.c_str(), buffer.c_str() + std::strlen(buffer.c_str()), v);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
if (!BOOST_TEST_EQ(v, expected_value))
{
std::cerr << "Test failure for: " << buffer << " got: " << v << std::endl;
@@ -130,11 +131,11 @@ void issue_599_test()
{
char buffer[256] {};
const auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), current_ref_val);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
double return_val {};
const auto return_r = boost::charconv::from_chars(buffer, buffer + std::strlen(buffer), return_val);
BOOST_TEST_EQ(return_r.ec, 0);
BOOST_TEST(return_r.ec == std::errc());
if (!BOOST_TEST_EQ(current_ref_val, return_val))
{
#ifdef BOOST_CHARCONV_DEBUG

View File

@@ -5,6 +5,7 @@
#include <boost/charconv/detail/parser.hpp>
#include <boost/charconv/chars_format.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <type_traits>
#include <cstdint>
#include <cstring>
@@ -19,7 +20,7 @@ void test_integer()
const char* val1 = "12";
auto r1 = boost::charconv::detail::parser(val1, val1 + std::strlen(val1), sign, significand, exponent);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(significand, 12);
BOOST_TEST_EQ(exponent, 0);
@@ -30,13 +31,13 @@ void test_integer()
const char* val2 = "123456789";
auto r2 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 0);
BOOST_TEST_EQ(significand, 123456789);
auto r3 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent, boost::charconv::chars_format::scientific);
BOOST_TEST_EQ(r3.ec, EINVAL);
BOOST_TEST(r3.ec == std::errc::invalid_argument);
}
template <typename T>
@@ -48,7 +49,7 @@ void test_scientifc()
const char* val1 = "-1e1";
auto r1 = boost::charconv::detail::parser(val1, val1 + std::strlen(val1), sign, significand, exponent);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(sign, true);
BOOST_TEST_EQ(significand, 1);
BOOST_TEST_EQ(exponent, 1);
@@ -59,7 +60,7 @@ void test_scientifc()
const char* val2 = "123456789e10";
auto r2 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 10);
BOOST_TEST_EQ(significand, 123456789);
@@ -70,31 +71,31 @@ void test_scientifc()
const char* val3 = "1.23456789e+10";
auto r3 = boost::charconv::detail::parser(val3, val3 + std::strlen(val3), sign, significand, exponent);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 2);
BOOST_TEST_EQ(significand, 123456789);
const char* val4 = "1.23456789e-10";
auto r4 = boost::charconv::detail::parser(val4, val4 + std::strlen(val4), sign, significand, exponent);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, -18);
BOOST_TEST_EQ(significand, 123456789);
auto r5 = boost::charconv::detail::parser(val4, val4 + std::strlen(val4), sign, significand, exponent, boost::charconv::chars_format::fixed);
BOOST_TEST_EQ(r5.ec, EINVAL);
BOOST_TEST(r5.ec == std::errc::invalid_argument);
const char* val6 = "987654321e10";
auto r6 = boost::charconv::detail::parser(val6, val6 + std::strlen(val6), sign, significand, exponent);
BOOST_TEST_EQ(r6.ec, 0);
BOOST_TEST(r6.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 10);
BOOST_TEST_EQ(significand, 987654321);
const char* val7 = "1.23456789E+10";
auto r7 = boost::charconv::detail::parser(val7, val7 + std::strlen(val7), sign, significand, exponent);
BOOST_TEST_EQ(r7.ec, 0);
BOOST_TEST(r7.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(exponent, 2);
BOOST_TEST_EQ(significand, 123456789);
@@ -110,7 +111,7 @@ void test_hex_integer()
const char* val1 = "2a";
auto r1 = boost::charconv::detail::parser(val1, val1 + std::strlen(val1), sign, significand, exponent, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(significand, 42);
BOOST_TEST_EQ(exponent, 0);
@@ -121,13 +122,13 @@ void test_hex_integer()
const char* val2 = "-1a3b5c7d9";
auto r2 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(sign, true);
BOOST_TEST_EQ(exponent, 0);
BOOST_TEST_EQ(significand, 7041566681);
auto r3 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent, boost::charconv::chars_format::scientific);
BOOST_TEST_EQ(r3.ec, EINVAL);
BOOST_TEST(r3.ec == std::errc::invalid_argument);
}
template <typename T>
@@ -139,7 +140,7 @@ void test_hex_scientific()
const char* val1 = "2ap+5";
auto r1 = boost::charconv::detail::parser(val1, val1 + std::strlen(val1), sign, significand, exponent, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_EQ(sign, false);
BOOST_TEST_EQ(significand, 42);
BOOST_TEST_EQ(exponent, 5);
@@ -150,23 +151,23 @@ void test_hex_scientific()
const char* val2 = "-1.3a2bp-10";
auto r2 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_EQ(sign, true);
BOOST_TEST_EQ(exponent, -14);
BOOST_TEST_EQ(significand, 80427);
auto r3 = boost::charconv::detail::parser(val2, val2 + std::strlen(val2), sign, significand, exponent, boost::charconv::chars_format::scientific);
BOOST_TEST_EQ(r3.ec, EINVAL);
BOOST_TEST(r3.ec == std::errc::invalid_argument);
const char* val4 = "-1.3A2BP-10";
auto r4 = boost::charconv::detail::parser(val4, val4 + std::strlen(val4), sign, significand, exponent, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_EQ(sign, true);
BOOST_TEST_EQ(exponent, -14);
BOOST_TEST_EQ(significand, 80427);
}
int main(void)
int main()
{
test_integer<float>();
test_integer<double>();

View File

@@ -5,6 +5,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <type_traits>
#include <limits>
#include <string>
@@ -19,14 +20,14 @@ void test_128bit_int()
char buffer1[64] {};
T v1 = static_cast<T>(1234);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "1234");
// Use 64-bit path
char buffer2[64] {};
T v2 = static_cast<T>(1234123412341234LL);
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "1234123412341234");
// Use 128-bit path
@@ -35,12 +36,12 @@ void test_128bit_int()
test_value = test_value << 126;
T v3 = 0;
auto r3 = boost::charconv::from_chars(buffer3, buffer3 + std::strlen(buffer3), v3);
BOOST_TEST(r3.ec == 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST(v3 == test_value);
char buffer4[64] {};
auto r4 = boost::charconv::to_chars(buffer4, buffer4 + sizeof(buffer4), v3);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer3, buffer4);
// Failing from roundtrip test
@@ -50,35 +51,35 @@ void test_128bit_int()
const char* buffer5 = "-103527168272318384816037687533325012784";
T v5 = 0;
auto r5 = boost::charconv::from_chars(buffer5, buffer5 + std::strlen(buffer5), v5);
BOOST_TEST(r5.ec == 0);
BOOST_TEST(r5.ec == std::errc());
BOOST_TEST(v5 < 0);
char buffer6[64] {};
auto r6 = boost::charconv::to_chars(buffer6, buffer6 + sizeof(buffer6), v5);
BOOST_TEST_EQ(r6.ec, 0);
BOOST_TEST(r6.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer5, buffer6);
// And back again
T v7 = 0;
auto r7 = boost::charconv::from_chars(buffer6, buffer6 + std::strlen(buffer6), v7);
BOOST_TEST(r7.ec == 0);
BOOST_TEST(r7.ec == std::errc());
BOOST_TEST(v5 == v7);;
// Second failing test
const char* buffer10 = "-170141183460469231731687303715884105728";
T v10 = 0;
auto r10 = boost::charconv::from_chars(buffer10, buffer10 + std::strlen(buffer10), v10);
BOOST_TEST(r10.ec == 0);
BOOST_TEST(r10.ec == std::errc());
BOOST_TEST(v10 < 0);
char buffer11[64] {};
auto r11 = boost::charconv::to_chars(buffer11, buffer11 + sizeof(buffer11), v10);
BOOST_TEST_EQ(r11.ec, 0);
BOOST_TEST(r11.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer10, buffer11);
T v11 = 0;
auto r12 = boost::charconv::from_chars(buffer11, buffer11 + std::strlen(buffer11), v11);
BOOST_TEST(r12.ec == 0);
BOOST_TEST(r12.ec == std::errc());
BOOST_TEST(v10 == v11);
}
}
@@ -89,7 +90,7 @@ void specific_value_tests(T value)
{
char buffer[64] {};
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, value);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
std::string value_string = std::to_string(value);
BOOST_TEST_CSTR_EQ(buffer, value_string.c_str());
}
@@ -98,7 +99,7 @@ void off_by_one_tests(int value)
{
char buffer[64] {};
auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer) - 1, value);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
std::string value_string = std::to_string(value);
BOOST_TEST_CSTR_EQ(buffer, value_string.c_str());
}
@@ -109,7 +110,7 @@ void base_thirtytwo_tests()
char buffer1[64] {};
T v1 = static_cast<T>(42);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 32);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "1a");
}
@@ -119,7 +120,7 @@ void base_sixteen_tests()
char buffer1[64] {};
T v1 = static_cast<T>(42);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 16);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "2a");
}
@@ -129,7 +130,7 @@ void base_eight_tests()
char buffer1[64] {};
T v1 = static_cast<T>(42);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 8);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "52");
}
@@ -139,7 +140,7 @@ void base_four_tests()
char buffer1[64] {};
T v1 = static_cast<T>(42);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 4);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "222");
}
@@ -150,13 +151,13 @@ void base_30_tests()
char buffer1[64] {};
T v1 = static_cast<T>(1234);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 30);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "1b4");
char buffer2[64] {};
T v2 = static_cast<T>(-4321);
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2, 30);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "-4o1");
}
@@ -166,12 +167,12 @@ void overflow_tests()
char buffer1[2] {};
T v1 = static_cast<T>(250);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1);
BOOST_TEST_EQ(r1.ec, EOVERFLOW);
BOOST_TEST(r1.ec == std::errc::result_out_of_range);
char buffer2[3] {};
T v2 = static_cast<T>(12341234);
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2);
BOOST_TEST_EQ(r2.ec, EOVERFLOW);
BOOST_TEST(r2.ec == std::errc::result_out_of_range);
}
template <typename T>
@@ -180,7 +181,7 @@ void base_two_tests()
char buffer1[64] {};
T v1 = static_cast<T>(42);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1, 2);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "101010");
}
@@ -190,13 +191,13 @@ void sixty_four_bit_tests()
char buffer1[64] {};
T v1 = static_cast<T>(-1234);
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "-1234");
char buffer2[64] {};
T v2 = static_cast<T>(1234123412341234LL);
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "1234123412341234");
}
@@ -206,21 +207,21 @@ void sixty_four_bit_tests<std::uint64_t>()
char buffer1[64] {};
std::uint64_t v1 = (std::numeric_limits<std::uint64_t>::max)();
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "18446744073709551615");
// Cutting this value in half would overflow a 32 bit unsigned for the back 10 digits
char buffer2[64] {};
std::uint64_t v2 = UINT64_C(9999999999999999999);
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "9999999999999999999");
// Account for zeros in the back half of the split
char buffer3[64] {};
std::uint64_t v3 = UINT64_C(10000000000000000000);
auto r3 = boost::charconv::to_chars(buffer3, buffer3 + sizeof(buffer3) - 1, v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer3, "10000000000000000000");
}
@@ -230,7 +231,7 @@ void negative_vals_test()
char buffer1[10] {};
T v = -4321;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "-4321");
}
@@ -240,7 +241,7 @@ void simple_test()
char buffer1[64] {};
T v = 34;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1) - 1, v);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "34");
boost::charconv::to_chars_result r {r1.ptr, r1.ec};
@@ -250,16 +251,16 @@ void simple_test()
T v2 = 12;
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2) - 1, v2);
BOOST_TEST(r1 != r2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "12");
// If the base is not 2-36 inclusive return invalid value
char buffer3[64] {};
T v3 = 12;
auto r3 = boost::charconv::to_chars(buffer3, buffer3 + sizeof(buffer3) - 1, v3, -2);
BOOST_TEST_EQ(r3.ec, EINVAL);
BOOST_TEST(r3.ec == std::errc::invalid_argument);
auto r4 = boost::charconv::to_chars(buffer3, buffer3 + sizeof(buffer3) - 1, v3, 90);
BOOST_TEST_EQ(r4.ec, EINVAL);
BOOST_TEST(r4.ec == std::errc::invalid_argument);
}
int main()

View File

@@ -5,6 +5,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <system_error>
#include <type_traits>
#include <limits>
#include <cstring>
@@ -21,19 +22,19 @@ void printf_divergence()
char buffer1[256] {};
T v1 = 3.4;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "3.4");
char buffer2[256] {};
T v2 = 3000.40;
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2), v2);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "3000.4");
char buffer3[256] {};
T v3 = -3000000300000000.5;
auto r3 = boost::charconv::to_chars(buffer3, buffer3 + sizeof(buffer3), v3);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer3, "-3000000300000000.5");
}
@@ -43,11 +44,11 @@ void integer_general_format()
char buffer1[256] {};
T v1 = 1217.2772861138403;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "1217.2772861138403");
T return_v1;
auto r1_return = boost::charconv::from_chars(buffer1, buffer1 + strlen(buffer1), return_v1);
BOOST_TEST_EQ(r1_return.ec, 0);
BOOST_TEST(r1_return.ec == std::errc());
BOOST_TEST_EQ(return_v1, v1);
}
@@ -57,37 +58,37 @@ void non_finite_values(boost::charconv::chars_format fmt = boost::charconv::char
char buffer1[256] {};
T v1 = std::numeric_limits<T>::infinity();
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1), v1, fmt, precision);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "inf");
char buffer2[256] {};
T v2 = -std::numeric_limits<T>::infinity();
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2), v2, fmt, precision);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "-inf");
char buffer3[256] {};
T v3 = std::numeric_limits<T>::quiet_NaN();
auto r3 = boost::charconv::to_chars(buffer3, buffer3 + sizeof(buffer3), v3, fmt, precision);
BOOST_TEST_EQ(r3.ec, 0);
BOOST_TEST(r3.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer3, "nan");
char buffer4[256] {};
T v4 = -std::numeric_limits<T>::quiet_NaN();
auto r4 = boost::charconv::to_chars(buffer4, buffer4 + sizeof(buffer4), v4, fmt, precision);
BOOST_TEST_EQ(r4.ec, 0);
BOOST_TEST(r4.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer4, "-nan(ind)");
char buffer5[256] {};
T v5 = std::numeric_limits<T>::signaling_NaN();
auto r5 = boost::charconv::to_chars(buffer5, buffer5 + sizeof(buffer5), v5, fmt, precision);
BOOST_TEST_EQ(r5.ec, 0);
BOOST_TEST(r5.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer5, "nan(snan)");
char buffer6[256] {};
T v6 = -std::numeric_limits<T>::signaling_NaN();
auto r6 = boost::charconv::to_chars(buffer6, buffer6 + sizeof(buffer6), v6, fmt, precision);
BOOST_TEST_EQ(r6.ec, 0);
BOOST_TEST(r6.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer6, "-nan(snan)");
}
@@ -97,7 +98,7 @@ void fixed_values()
char buffer1[256] {};
T v1 = 61851632;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1), v1);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "61851632");
}
@@ -107,13 +108,13 @@ void failing_ci_values()
char buffer1[256] {};
T v1 = -1.08260383390082946e+307;
auto r1 = boost::charconv::to_chars(buffer1, buffer1 + sizeof(buffer1), v1, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r1.ec, 0);
BOOST_TEST(r1.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer1, "-1.ed5658af91a0fp+1019");
char buffer2[256] {};
T v2 = -9.52743282403084637e+306;
auto r2 = boost::charconv::to_chars(buffer2, buffer2 + sizeof(buffer2), v2, boost::charconv::chars_format::hex);
BOOST_TEST_EQ(r2.ec, 0);
BOOST_TEST(r2.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer2, "-1.b22914956c56fp+1019");
}
@@ -122,7 +123,7 @@ void spot_check(T v, const std::string& str, boost::charconv::chars_format fmt =
{
char buffer[256] {};
const auto r = boost::charconv::to_chars(buffer, buffer + sizeof(buffer), v, fmt);
BOOST_TEST_EQ(r.ec, 0);
BOOST_TEST(r.ec == std::errc());
BOOST_TEST_CSTR_EQ(buffer, str.c_str());
}

View File

@@ -63,7 +63,7 @@ void test_spot(T val, boost::charconv::chars_format fmt = boost::charconv::chars
r_stl = std::to_chars(buffer_stl, buffer_stl + sizeof(buffer_stl), val, stl_fmt, precision);
}
BOOST_TEST_EQ(r_boost.ec, 0);
BOOST_TEST(r_boost.ec == std::errc());
if (r_stl.ec != std::errc())
{
// STL failed
@@ -114,16 +114,16 @@ void non_finite_test(boost::charconv::chars_format fmt = boost::charconv::chars_
test_spot(-std::numeric_limits<T>::infinity(), fmt, i);
test_spot(std::numeric_limits<T>::quiet_NaN(), fmt, i);
#if (defined(__clang__) && __clang_major__ >= 16) || defined(_MSC_VER)
#if (defined(__clang__) && __clang_major__ >= 16 && defined(__APPLE__)) || defined(_MSC_VER)
//
// Newer clang and MSVC both give the following:
// Newer apple clang and MSVC both give the following:
//
// -qNaN = -nan(ind)
//
test_spot(-std::numeric_limits<T>::quiet_NaN(), fmt, i);
#endif
#if (defined(__clang__) && __clang_major__ >= 16)
#if (defined(__clang__) && __clang_major__ >= 16 && defined(__APPLE__))
//
// Newer clang also gives the following:
//

View File

@@ -6,6 +6,7 @@
#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <system_error>
#include <string>
#include <sstream>
#include <iomanip>
@@ -104,7 +105,7 @@ template<class T> void test_sprintf( T value )
auto r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value );
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST( r.ec == std::errc() );
char buffer2[ 256 ];
std::snprintf( buffer2, sizeof( buffer2 ), fmt_from_type( value ), value );
@@ -133,7 +134,7 @@ template<class T> void test_sprintf_float( T value, boost::charconv::chars_forma
r = boost::charconv::to_chars( buffer, buffer + sizeof( buffer ), value, fmt, std::numeric_limits<T>::max_digits10);
}
BOOST_TEST_EQ( r.ec, 0 );
BOOST_TEST( r.ec == std::errc() );
char buffer2[ 256 ];