Skip to content

Commit edd19b3

Browse files
authored
Merge pull request #61 from eugenegff/main
Parse "nan(n-char-seq-opt)" as required by C++17 20.19.3.7
2 parents 9d76b04 + 76dec80 commit edd19b3

File tree

1 file changed

+23
-28
lines changed

1 file changed

+23
-28
lines changed

include/fast_float/parse_number.h

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,48 +22,43 @@ namespace {
2222
template <typename T>
2323
from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
2424
from_chars_result answer;
25+
answer.ptr = first;
2526
answer.ec = std::errc(); // be optimistic
27+
bool minusSign = false;
28+
if (*first == '-') { // assume first < last, so dereference without checks
29+
minusSign = true;
30+
++first;
31+
} else if( *first == '+' ) { // C++17 20.19.3.7 explicitly forbids '+' here, but anyway
32+
++first;
33+
}
2634
if (last - first >= 3) {
2735
if (fastfloat_strncasecmp(first, "nan", 3)) {
28-
answer.ptr = first + 3;
29-
value = std::numeric_limits<T>::quiet_NaN();
36+
answer.ptr = (first += 3);
37+
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
38+
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
39+
if(first != last && *first == '(') {
40+
for(const char* ptr = first + 1; ptr != last; ++ptr) {
41+
if (*ptr == ')') {
42+
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
43+
break;
44+
}
45+
else if(!(('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z') || ('0' <= *ptr && *ptr <= '9') || *ptr == '_'))
46+
break; // forbidden char, not nan(n-char-seq-opt)
47+
}
48+
}
3049
return answer;
3150
}
3251
if (fastfloat_strncasecmp(first, "inf", 3)) {
33-
if ((last - first >= 8) && fastfloat_strncasecmp(first, "infinity", 8)) {
52+
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, "inity", 5)) {
3453
answer.ptr = first + 8;
3554
} else {
3655
answer.ptr = first + 3;
3756
}
38-
value = std::numeric_limits<T>::infinity();
57+
value = minusSign ? -std::numeric_limits<T>::infinity() : std::numeric_limits<T>::infinity();
3958
return answer;
4059
}
41-
if (last - first >= 4) {
42-
if (fastfloat_strncasecmp(first, "+nan", 4) || fastfloat_strncasecmp(first, "-nan", 4)) {
43-
answer.ptr = first + 4;
44-
value = std::numeric_limits<T>::quiet_NaN();
45-
if (first[0] == '-') {
46-
value = -value;
47-
}
48-
return answer;
49-
}
50-
51-
if (fastfloat_strncasecmp(first, "+inf", 4) || fastfloat_strncasecmp(first, "-inf", 4)) {
52-
if ((last - first >= 9) && fastfloat_strncasecmp(first + 1, "infinity", 8)) {
53-
answer.ptr = first + 9;
54-
} else {
55-
answer.ptr = first + 4;
56-
}
57-
value = std::numeric_limits<T>::infinity();
58-
if (first[0] == '-') {
59-
value = -value;
60-
}
61-
return answer;
62-
}
63-
}
6460
}
6561
answer.ec = std::errc::invalid_argument;
66-
answer.ptr = first;
6762
return answer;
6863
}
6964

0 commit comments

Comments
 (0)