Skip to content

Commit

Permalink
Fix handling of leading + with floats
Browse files Browse the repository at this point in the history
  • Loading branch information
eliaskosunen committed Nov 1, 2023
1 parent 38fa1f0 commit a69d578
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

_Released 2023-xx-xx_

## Features

* Parse leading `+` signs in floats (reported in #77)

## Fixes

* Fix `scn::wrap(std::string_view&&)` being ambiguous on gcc (reported in #83)
* Fix compiler error in `scn::basic_string_view<CharT>::substr` (reported in #86)
* Improve error messages given from the float parser

# 1.1.2

Expand Down
18 changes: 17 additions & 1 deletion include/scn/reader/float.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ namespace scn {
auto do_parse_float = [&](span<const char_type> s) -> error {
T tmp = 0;
expected<std::ptrdiff_t> ret{0};
int sign_offset{};
if (SCN_UNLIKELY((format_options & localized_digits) != 0 ||
((common_options & localized) != 0 &&
(format_options & allow_hex) != 0))) {
Expand All @@ -145,16 +146,31 @@ namespace scn {
SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE
}
else {
SCN_EXPECT(!s.empty());
bool has_negative_sign = false;
if (s[0] == char_type{'+'}) {
sign_offset = 1;
}
else if (s[0] == char_type{'-'}) {
has_negative_sign = true;
sign_offset = 1;
}
ret = _read_float(
tmp, s,
tmp, s.subspan(sign_offset),
ctx.locale()
.get((common_options & localized) != 0)
.decimal_point());
if (has_negative_sign) {
SCN_EXPECT(std::isnan(tmp) ||
tmp >= static_cast<T>(0.0));
tmp = -tmp;
}
}

if (!ret) {
return ret.error();
}
ret.value() += sign_offset;
if (ret.value() != s.ssize()) {
auto pb =
putback_n(ctx.range(), s.ssize() - ret.value());
Expand Down
7 changes: 5 additions & 2 deletions include/scn/util/span.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ namespace scn {
using std::input_iterator_tag;
using std::output_iterator_tag;
using std::random_access_iterator_tag;
struct contiguous_iterator_tag : random_access_iterator_tag {
};
struct contiguous_iterator_tag : random_access_iterator_tag {};
} // namespace custom_ranges

/**
Expand Down Expand Up @@ -164,6 +163,10 @@ namespace scn {
{
return m_end - m_ptr;
}
SCN_NODISCARD constexpr bool empty() const noexcept
{
return size() == 0;
}

SCN_CONSTEXPR14 span<T> first(index_type n) const
{
Expand Down
9 changes: 6 additions & 3 deletions src/reader_float.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,8 @@ namespace scn {
SCN_GCC_COMPAT_IGNORE("-Wfloat-equal")
// No conversion
if (f == detail::zero_value<T>::value && chars == 0) {
return error(error::invalid_scanned_value, "strtod");
return error(error::invalid_scanned_value,
"strtod failed to parse float");
}
// Range error
if (err == ERANGE) {
Expand Down Expand Up @@ -295,10 +296,12 @@ namespace scn {
const auto result = ::fast_float::from_chars_advanced(
str, str + len, value, flags);
if (result.ec == std::errc::invalid_argument) {
return error(error::invalid_scanned_value, "fast_float");
return error(error::invalid_scanned_value,
"fast_float failed to parse float");
}
if (result.ec == std::errc::result_out_of_range) {
return error(error::value_out_of_range, "fast_float");
return error(error::value_out_of_range,
"fast_float parsed an out-of-range float");
}
if (std::isinf(value)) {
// fast_float represents very large or small values as inf
Expand Down
18 changes: 18 additions & 0 deletions test/floating.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,24 @@ TEST_CASE_TEMPLATE_DEFINE("floating point", T, floating_test)
CHECK(std::signbit(f));
CHECK(e);
}
{
value_type f{};
auto e = do_scan<char_type>("+42.0", "{}", f);
CHECK(f == doctest::Approx(42.0));
CHECK(e);
}
{
value_type f{};
auto e = do_scan<char_type>(" +42.0", "{}", f);
CHECK(f == doctest::Approx(42.0));
CHECK(e);
}
{
value_type f{};
auto e = do_scan<char_type>("+", "{}", f);
CHECK(!e);
CHECK(e.error() == scn::error::invalid_scanned_value);
}
{
value_type f{1.0};
auto e =
Expand Down

0 comments on commit a69d578

Please sign in to comment.