mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 16:56:57 +08:00
* 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:
parent
3c5b166f6c
commit
b0b1954c87
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user