Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add macro to change ERANGE handling. #111

Merged
merged 8 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .drone.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest' },
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', B2_DONT_EMBED_MANIFEST: '1' },
),

windows_pipeline(
Expand Down
11 changes: 11 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ jobs:
os: ubuntu-22.04
install:
- g++-12-multilib
- toolset: gcc-12
cxxstd: "03,11,14,17,20,23"
address_model: 32,64
os: ubuntu-22.04
install:
- g++-12-multilib
define: "BOOST_CHARCONV_STD_ERANGE"
- toolset: gcc-12
cxxstd: "03-gnu,11-gnu,14-gnu,17-gnu,20-gnu,23-gnu"
address_model: 32,64
Expand Down Expand Up @@ -454,6 +461,10 @@ jobs:
then
B2_ARGS+=("address-model=${{matrix.address_model}}")
fi
if [ -n "${{matrix.define}}" ]
then
B2_ARGS+=("define=${{matrix.define}}")
fi
B2_ARGS+=("libs/$LIBRARY/test")
./b2 "${B2_ARGS[@]}"

Expand Down
1 change: 1 addition & 0 deletions doc/charconv/from_chars.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ from_chars_result from_chars(const char* first, const char* last, Real& value, c
=== from_chars for floating point types
* 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.
** If you want the behavior from the standard, compile the library with `BOOST_CHARCONV_STD_ERANGE` defined.
* These functions have been tested to support all built-in floating-point types and those from C++23's `<stdfloat>`
** Long doubles can be 64, 80, or 128-bit, but must be IEEE 754 compliant. An example of a non-compliant, and therefore unsupported, format is `__ibm128`.
** Use of `__float128` or `std::float128_t` requires compiling with `-std=gnu++xx` and linking GCC's `libquadmath`.
Expand Down
40 changes: 40 additions & 0 deletions src/from_chars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,52 @@

boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, float& value, boost::charconv::chars_format fmt) noexcept
{
#ifdef BOOST_CHARCONV_STD_ERANGE

float temp_value;
const auto r = fmt != boost::charconv::chars_format::hex ? boost::charconv::detail::fast_float::from_chars(first, last, temp_value, fmt) :
boost::charconv::detail::from_chars_float_impl(first, last, temp_value, fmt);
if (r)
{
value = temp_value;
}

return r;

#else

if (fmt != boost::charconv::chars_format::hex)
{
return boost::charconv::detail::fast_float::from_chars(first, last, value, fmt);
}
return boost::charconv::detail::from_chars_float_impl(first, last, value, fmt);

#endif
}

boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, double& value, boost::charconv::chars_format fmt) noexcept
{
#ifdef BOOST_CHARCONV_STD_ERANGE

double temp_value;
const auto r = fmt != boost::charconv::chars_format::hex ? boost::charconv::detail::fast_float::from_chars(first, last, temp_value, fmt) :
boost::charconv::detail::from_chars_float_impl(first, last, temp_value, fmt);
if (r)
{
value = temp_value;
}

return r;

#else

if (fmt != boost::charconv::chars_format::hex)
{
return boost::charconv::detail::fast_float::from_chars(first, last, value, fmt);
}
return boost::charconv::detail::from_chars_float_impl(first, last, value, fmt);

#endif
}

#ifdef BOOST_CHARCONV_HAS_FLOAT128
Expand Down Expand Up @@ -79,7 +111,11 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first
auto return_val = boost::charconv::detail::compute_float128(exponent, significand, sign, success);
r.ec = static_cast<std::errc>(success);

#ifdef BOOST_CHARCONV_STD_ERANGE
if (r.ec == std::errc())
#else
if (r.ec == std::errc() || r.ec == std::errc::result_out_of_range)
#endif
{
value = return_val;
}
Expand Down Expand Up @@ -202,7 +238,11 @@ boost::charconv::from_chars_result boost::charconv::from_chars(const char* first
auto return_val = boost::charconv::detail::compute_float80<long double>(exponent, significand, sign, success);
r.ec = success;

#ifdef BOOST_CHARCONV_STD_ERANGE
if (r.ec == std::errc())
#else
if (r.ec == std::errc() || r.ec == std::errc::result_out_of_range)
#endif
{
value = return_val;
}
Expand Down
1 change: 1 addition & 0 deletions test/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,4 @@ run from_chars_float2.cpp ;
run-fail STL_benchmark.cpp : : : [ requires cxx17_hdr_charconv ] [ check-target-builds ../config//has_double_conversion "Google double-coversion support" : <library>"double-conversion" ] ;
run test_float128.cpp : : : [ check-target-builds ../config//has_float128 "GCC libquadmath and __float128 support" : <library>"quadmath" ] ;
run P2497.cpp ;
run github_issue_110.cpp ;
10 changes: 10 additions & 0 deletions test/from_chars_float.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,14 @@ void boost_json_test()
fc("6372891218502368041059e064");
}

// Issue 37 conflicts with handling from 110
#ifdef BOOST_CHARCONV_STD_ERANGE

template <typename T>
void test_issue_37() {}

#else

template <typename T>
void test_issue_37()
{
Expand Down Expand Up @@ -422,6 +430,8 @@ void test_issue_37()
overflow_spot_value("-1.0e-99999", static_cast<T>(-0.0L));
}

#endif

template <typename T>
void test_issue_45(T v, const std::string& full_buffer, const std::ptrdiff_t ptr, boost::charconv::chars_format fmt = boost::charconv::chars_format::general)
{
Expand Down
66 changes: 66 additions & 0 deletions test/github_issue_110.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright 2024 Matt Borland
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/charconv.hpp>
#include <boost/core/lightweight_test.hpp>

#ifdef BOOST_CHARCONV_STD_ERANGE

template <typename T>
void overflow_spot_value(const std::string& buffer, boost::charconv::chars_format fmt = boost::charconv::chars_format::general)
{
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, static_cast<T>(42.L)) && BOOST_TEST(r.ec == std::errc::result_out_of_range)))
{
std::cerr << "Test failure for: " << buffer << " got: " << v << std::endl;
}
}

template <typename T>
void test()
{
const auto format_list = {boost::charconv::chars_format::general, boost::charconv::chars_format::scientific, boost::charconv::chars_format::hex};

for (const auto format : format_list)
{
if (format != boost::charconv::chars_format::hex)
{
overflow_spot_value<T>("1e99999", format);
overflow_spot_value<T>("-1e99999", format);
overflow_spot_value<T>("1e-99999", format);
overflow_spot_value<T>("-1.0e-99999", format);
}
else
{
overflow_spot_value<T>("1p99999", format);
overflow_spot_value<T>("-1p99999", format);
overflow_spot_value<T>("1p-99999", format);
overflow_spot_value<T>("-1.0p-99999", format);
}
}
}

int main()
{
test<float>();
test<double>();
test<long double>();

#ifdef BOOST_CHARCONV_HAS_FLOAT128
test<__float128>();
#endif

return boost::report_errors();
}

#else

int main()
{
return 0;
}

#endif
12 changes: 12 additions & 0 deletions test/test_boost_json_values.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ void test_within_ulp()
}
};

// Directly conflicts with the expected outcomes
#ifdef BOOST_CHARCONV_STD_ERANGE

int main()
{
return 0;
}

#else

int main()
{
issue_599_test();
Expand Down Expand Up @@ -479,3 +489,5 @@ int main()

return boost::report_errors();
}

#endif