* Added a config macro FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN and FASTFLOAT_DISALLOW_NAN. This both allow to significantly reduce code size and speedup your code when you use fast_float as a part of your parser.

This commit is contained in:
IRainman 2025-03-05 23:21:24 +03:00
parent 3c5b166f6c
commit b0b1954c87
4 changed files with 89 additions and 12 deletions

View File

@ -255,7 +255,9 @@ template <typename UC> struct parsed_number_string_t {
int64_t exponent{0};
uint64_t mantissa{0};
UC const *lastmatch{nullptr};
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
bool negative{false};
#endif
bool valid{false};
bool too_many_digits{false};
// contains the range of the significant digits
@ -290,6 +292,7 @@ parse_number_string(UC const *p, UC const *pend,
answer.valid = false;
answer.too_many_digits = false;
// assume p < pend, so dereference without checks;
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
answer.negative = (*p == UC('-'));
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
if ((*p == UC('-')) ||
@ -314,6 +317,7 @@ parse_number_string(UC const *p, UC const *pend,
}
}
}
#endif
UC const *const start_digits = p;
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
@ -481,6 +485,7 @@ parse_int_string(UC const *p, UC const *pend, T &value,
UC const *const first = p;
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
bool const negative = (*p == UC('-'));
#ifdef FASTFLOAT_VISUAL_STUDIO
#pragma warning(push)
@ -498,6 +503,7 @@ parse_int_string(UC const *p, UC const *pend, T &value,
(uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
++p;
}
#endif
UC const *const start_num = p;
@ -553,12 +559,17 @@ parse_int_string(UC const *p, UC const *pend, T &value,
// check other types overflow
if (!std::is_same<T, uint64_t>::value) {
if (i > uint64_t(std::numeric_limits<T>::max()) + uint64_t(negative)) {
if (i > uint64_t(std::numeric_limits<T>::max())
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
+ uint64_t(negative)
#endif
) {
answer.ec = std::errc::result_out_of_range;
return answer;
}
}
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
if (negative) {
#ifdef FASTFLOAT_VISUAL_STUDIO
#pragma warning(push)
@ -576,8 +587,11 @@ parse_int_string(UC const *p, UC const *pend, T &value,
#pragma warning(pop)
#endif
} else {
#endif
value = T(i);
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
}
#endif
answer.ec = std::errc();
return answer;

View File

@ -381,7 +381,11 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
round<T>(am_b,
[](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); });
T b;
to_float(false, am_b, b);
to_float(
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
false,
#endif
am_b, b);
adjusted_mantissa theor = to_extended_halfway(b);
bigint theor_digits(theor.mantissa);
int32_t theor_exp = theor.power2;

View File

@ -51,8 +51,10 @@ enum class chars_format : uint64_t {
json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific,
fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific,
general = fixed | scientific,
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
allow_leading_plus = 1 << 7,
skip_white_space = 1 << 8,
#endif
};
template <typename UC> struct from_chars_result_t {
@ -606,6 +608,8 @@ template <> inline constexpr int binary_format<float>::infinite_power() {
return 0xFF;
}
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
template <> inline constexpr int binary_format<double>::sign_index() {
return 63;
}
@ -614,6 +618,8 @@ template <> inline constexpr int binary_format<float>::sign_index() {
return 31;
}
#endif
template <>
inline constexpr int binary_format<double>::max_exponent_fast_path() {
return 22;
@ -979,13 +985,19 @@ binary_format<double>::hidden_bit_mask() {
template <typename T>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
to_float(bool negative, adjusted_mantissa am, T &value) {
to_float(
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
bool negative,
#endif
adjusted_mantissa am, T &value) {
using equiv_uint = equiv_uint_t<T>;
equiv_uint word = equiv_uint(am.mantissa);
word = equiv_uint(word | equiv_uint(am.power2)
<< binary_format<T>::mantissa_explicit_bits());
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
word =
equiv_uint(word | equiv_uint(negative) << binary_format<T>::sign_index());
#endif
#if FASTFLOAT_HAS_BIT_CAST
value = std::bit_cast<T>(word);
#else
@ -993,6 +1005,8 @@ to_float(bool negative, adjusted_mantissa am, T &value) {
#endif
}
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
template <typename = void> struct space_lut {
static constexpr bool value[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -1018,6 +1032,8 @@ template <typename UC> constexpr bool is_space(UC c) {
return c < 256 && space_lut<>::value[uint8_t(c)];
}
#endif
template <typename UC> static constexpr uint64_t int_cmp_zeros() {
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4),
"Unsupported character size");
@ -1032,6 +1048,8 @@ template <typename UC> static constexpr int int_cmp_len() {
return sizeof(uint64_t) / sizeof(UC);
}
#ifndef FASTFLOAT_DISALLOW_NAN
template <typename UC> constexpr UC const *str_const_nan();
template <> constexpr char const *str_const_nan<char>() { return "nan"; }
@ -1052,6 +1070,8 @@ template <> constexpr char8_t const *str_const_nan<char8_t>() {
}
#endif
#endif
template <typename UC> constexpr UC const *str_const_inf();
template <> constexpr char const *str_const_inf<char>() { return "infinity"; }
@ -1223,7 +1243,12 @@ operator^=(chars_format &lhs, chars_format rhs) noexcept {
namespace detail {
// adjust for deprecated feature macros
constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
fastfloat_really_inline constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
#if defined(FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN) && \
(defined(FASTFLOAT_ALLOWS_LEADING_PLUS) || \
defined(FASTFLOAT_SKIP_WHITE_SPACE))
#error "FASTFLOAT_ALLOWS_LEADING_PLUS and FASTFLOAT_SKIP_WHITE_SPACE require FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN to be undefined"
#endif
return fmt
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS
| chars_format::allow_leading_plus

View File

@ -22,11 +22,16 @@ namespace detail {
template <typename T, typename UC>
from_chars_result_t<UC>
FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last,
T &value, chars_format fmt) noexcept {
T &value
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
, chars_format fmt
#endif
) noexcept {
from_chars_result_t<UC> answer{};
answer.ptr = first;
answer.ec = std::errc(); // be optimistic
// assume first < last, so dereference without checks;
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
bool const minusSign = (*first == UC('-'));
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
if ((*first == UC('-')) ||
@ -34,11 +39,16 @@ from_chars_result_t<UC>
(*first == UC('+')))) {
++first;
}
#endif
if (last - first >= 3) {
#ifndef FASTFLOAT_DISALLOW_NAN
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
answer.ptr = (first += 3);
value = minusSign ? -std::numeric_limits<T>::quiet_NaN()
: std::numeric_limits<T>::quiet_NaN();
value =
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
minusSign ? -std::numeric_limits<T>::quiet_NaN() :
#endif
std::numeric_limits<T>::quiet_NaN();
// 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).
if (first != last && *first == UC('(')) {
@ -54,6 +64,7 @@ from_chars_result_t<UC>
}
return answer;
}
#endif
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
if ((last - first >= 8) &&
fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
@ -61,8 +72,11 @@ from_chars_result_t<UC>
} else {
answer.ptr = first + 3;
}
value = minusSign ? -std::numeric_limits<T>::infinity()
: std::numeric_limits<T>::infinity();
value =
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
minusSign ? -std::numeric_limits<T>::infinity() :
#endif
std::numeric_limits<T>::infinity();
return answer;
}
}
@ -231,9 +245,11 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
} else {
value = value * binary_format<T>::exact_power_of_ten(pns.exponent);
}
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
if (pns.negative) {
value = -value;
}
#endif
return answer;
}
} else {
@ -246,15 +262,21 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
#if defined(__clang__) || defined(FASTFLOAT_32BIT)
// Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD
if (pns.mantissa == 0) {
value = pns.negative ? T(-0.) : T(0.);
value =
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
pns.negative ? T(-0.) :
#endif
T(0.);
return answer;
}
#endif
value = T(pns.mantissa) *
binary_format<T>::exact_power_of_ten(pns.exponent);
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
if (pns.negative) {
value = -value;
}
#endif
return answer;
}
}
@ -272,7 +294,11 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
if (am.power2 < 0) {
am = digit_comp<T>(pns, am);
}
to_float(pns.negative, am, value);
to_float(
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
pns.negative,
#endif
am, value);
// Test for over/underflow.
if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) ||
am.power2 == binary_format<T>::infinite_power()) {
@ -294,11 +320,13 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value,
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
from_chars_result_t<UC> answer;
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
if (uint64_t(fmt & chars_format::skip_white_space)) {
while ((first != last) && fast_float::is_space(*first)) {
first++;
}
}
#endif
if (first == last) {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
@ -312,7 +340,11 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value,
answer.ptr = first;
return answer;
} else {
return detail::parse_infnan(first, last, value, fmt);
return detail::parse_infnan(first, last, value
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
, fmt
#endif
);
}
}
@ -348,11 +380,13 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value,
int const base = options.base;
from_chars_result_t<UC> answer;
#ifndef FASTFLOAT_DISALLOW_ANY_LEADING_SYMBOLS_INCLUDE_SIGN
if (uint64_t(fmt & chars_format::skip_white_space)) {
while ((first != last) && fast_float::is_space(*first)) {
first++;
}
}
#endif
if (first == last || base < 2 || base > 36) {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;