mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-09-14 14:42:26 +08:00
improve error messages when type is unsupported.
cleanup of functions naming. logical improvements of the FASTFLOAT_ISNOT_CHECKED_BOUNDS when FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN isn't enabled.
This commit is contained in:
parent
bfbe4c4869
commit
4a71c111f2
@ -83,7 +83,7 @@ read_chars_to_unsigned(UC const *chars) noexcept {
|
||||
|
||||
#if FASTFLOAT_X86_SIMD
|
||||
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
|
||||
fastfloat_really_inline uint64_t simd_read8(__m128i const data) {
|
||||
// _mm_packus_epi16 is SSE2, converts 8×u16 → 8×u8
|
||||
__m128i const packed = _mm_packus_epi16(data, data);
|
||||
|
||||
@ -102,25 +102,23 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) {
|
||||
#endif
|
||||
}
|
||||
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
|
||||
fastfloat_really_inline uint64_t simd_read8(char16_t const *chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
// unaligned SIMD instruction -> all fine.
|
||||
return simd_read8_to_u64(
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); //-V1032
|
||||
return simd_read8(_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
#elif defined(FASTFLOAT_ARM_NEON)
|
||||
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) {
|
||||
fastfloat_really_inline uint64_t simd_read8(uint16x8_t const &data) {
|
||||
uint8x8_t utf8_packed = vmovn_u16(data);
|
||||
return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0);
|
||||
}
|
||||
|
||||
fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
|
||||
fastfloat_really_inline uint64_t simd_read8(char16_t const *chars) {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
return simd_read8_to_u64(
|
||||
vld1q_u16(reinterpret_cast<uint16_t const *>(chars)));
|
||||
return simd_read8(vld1q_u16(reinterpret_cast<uint16_t const *>(chars)));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
}
|
||||
|
||||
@ -135,13 +133,13 @@ template <typename UC>
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
|
||||
#endif
|
||||
// dummy for compile
|
||||
uint64_t simd_read8_to_u64(UC const *) {
|
||||
uint64_t simd_read8(UC const *) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// credit @aqrit
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
|
||||
parse_eight_digits_unrolled(uint64_t val) noexcept {
|
||||
parse_8_digits(uint64_t val) noexcept {
|
||||
uint64_t const mask = 0x000000FF000000FF;
|
||||
uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
||||
uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
||||
@ -154,28 +152,28 @@ parse_eight_digits_unrolled(uint64_t val) noexcept {
|
||||
// Call this if chars are definitely 8 digits.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t
|
||||
parse_eight_digits_unrolled(UC const *chars) noexcept {
|
||||
parse_8_digits(UC const *chars) noexcept {
|
||||
if (is_constant_evaluated() || !has_simd_opt<UC>()) {
|
||||
return parse_eight_digits_unrolled(
|
||||
return parse_8_digits(
|
||||
read_chars_to_unsigned<uint64_t>(chars)); // truncation okay
|
||||
}
|
||||
return parse_eight_digits_unrolled(simd_read8_to_u64(chars));
|
||||
return parse_8_digits(simd_read8(chars));
|
||||
}
|
||||
|
||||
// credit @aqrit
|
||||
fastfloat_really_inline constexpr bool
|
||||
is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||
is_made_of_8_digits(uint64_t val) noexcept {
|
||||
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
|
||||
0x8080808080808080));
|
||||
}
|
||||
|
||||
fastfloat_really_inline constexpr bool
|
||||
is_made_of_four_digits_fast(uint32_t val) noexcept {
|
||||
is_made_of_4_digits(uint32_t val) noexcept {
|
||||
return !((((val + 0x46464646) | (val - 0x30303030)) & 0x80808080));
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t
|
||||
parse_four_digits_unrolled(uint32_t val) noexcept {
|
||||
parse_4_digits(uint32_t val) noexcept {
|
||||
val -= 0x30303030;
|
||||
val = (val * 10) + (val >> 8);
|
||||
return (((val & 0x00FF00FF) * 0x00640001) >> 16) & 0xFFFF;
|
||||
@ -187,7 +185,7 @@ parse_four_digits_unrolled(uint32_t val) noexcept {
|
||||
|
||||
#if FASTFLOAT_X86_SIMD >= 31
|
||||
// credit @hedgehoginthecpp
|
||||
fastfloat_really_inline __m128i x86_parse_4x4_digits(__m128i data) noexcept {
|
||||
fastfloat_really_inline __m128i parse_4x4_digits(__m128i data) noexcept {
|
||||
// 1. convert from ASCII '0' .. '9' to numbers 0 .. 9
|
||||
const __m128i ascii0 = _mm_set1_epi8('0');
|
||||
const __m128i t0 = _mm_subs_epu8(data, ascii0);
|
||||
@ -205,7 +203,7 @@ fastfloat_really_inline __m128i x86_parse_4x4_digits(__m128i data) noexcept {
|
||||
|
||||
// credit @hedgehoginthecpp
|
||||
fastfloat_really_inline uint64_t
|
||||
convert_4x4_to_16digits(__m128i data) noexcept {
|
||||
convert_4x4_to_16_digits(__m128i data) noexcept {
|
||||
// 4. convert to 16-digit number
|
||||
// v[0] * 10^12 + v[1] * 10^8 + v[2] * 10^4 + v[3]
|
||||
const uint64_t lo = static_cast<uint32_t>(_mm_cvtsi128_si32(data));
|
||||
@ -222,8 +220,8 @@ convert_4x4_to_16digits(__m128i data) noexcept {
|
||||
|
||||
#if FASTFLOAT_X86_SIMD >= 42
|
||||
// credit @hedgehoginthecpp
|
||||
fastfloat_really_inline bool x86_parse_if_16_digits(char const *chars,
|
||||
uint64_t &value) noexcept {
|
||||
fastfloat_really_inline bool parse_if_16_digits(char const *chars,
|
||||
uint64_t &value) noexcept {
|
||||
FASTFLOAT_SIMD_DISABLE_WARNINGS
|
||||
const __m128i data =
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars));
|
||||
@ -254,7 +252,7 @@ fastfloat_really_inline bool x86_parse_if_16_digits(char const *chars,
|
||||
return false;
|
||||
|
||||
value = value * 10000000000000000ULL +
|
||||
convert_4x4_to_16digits(x86_parse_4x4_digits(data));
|
||||
convert_4x4_to_16_digits(parse_4x4_digits(data));
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -262,9 +260,9 @@ fastfloat_really_inline bool x86_parse_if_16_digits(char const *chars,
|
||||
|
||||
#if FASTFLOAT_X86_SIMD >= 31
|
||||
// credit @hedgehoginthecpp
|
||||
fastfloat_really_inline uint64_t x86_parse_16_digits(char const *p) noexcept {
|
||||
fastfloat_really_inline uint64_t parse_16_digits(char const *p) noexcept {
|
||||
const __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
|
||||
return convert_4x4_to_16digits(x86_parse_4x4_digits(data));
|
||||
return convert_4x4_to_16_digits(parse_4x4_digits(data));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -278,7 +276,7 @@ parse_digits_until_19(char const *&p, char const *pend, am_mant_t &mantissa) {
|
||||
* 16-digit block cannot exceed 10^18 - 1.
|
||||
*/
|
||||
while (std::distance(p, pend) >= 16 && mantissa < 100) {
|
||||
auto const value = x86_parse_16_digits(p);
|
||||
auto const value = parse_16_digits(p);
|
||||
mantissa = mantissa * 10000000000000000ULL + value;
|
||||
p += 16;
|
||||
}
|
||||
@ -287,13 +285,14 @@ parse_digits_until_19(char const *&p, char const *pend, am_mant_t &mantissa) {
|
||||
// An 8-digit block is safe while: mantissa < 10^10 because the result is
|
||||
// guaranteed < 10^18.
|
||||
while (std::distance(p, pend) >= 8 && mantissa < 10000000000ULL) {
|
||||
auto const value = parse_eight_digits_unrolled(p);
|
||||
auto const value = parse_8_digits(p);
|
||||
mantissa = mantissa * 100000000ULL + value;
|
||||
p += 8;
|
||||
}
|
||||
// ?????
|
||||
while (std::distance(p, pend) >= 4 && mantissa < 10000000000ULL) {
|
||||
auto const value = read_chars_to_unsigned<uint32_t>(p);
|
||||
mantissa = mantissa * 10000 + parse_four_digits_unrolled(value);
|
||||
mantissa = mantissa * 10000 + parse_4_digits(value);
|
||||
p += 4;
|
||||
}
|
||||
// Finalizer
|
||||
@ -323,11 +322,10 @@ parse_digits_until_19(UC const *&p, UC const *pend,
|
||||
#endif
|
||||
|
||||
// Call this if chars might not be 8 digits.
|
||||
// Using this style (instead of is_made_of_eight_digits_fast() then
|
||||
// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice.
|
||||
// Using this style (instead of is_made_of_8_digits() then
|
||||
// parse_8_digits()) ensures we don't load SIMD registers twice.
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
|
||||
simd_parse_if_eight_digits_unrolled(char16_t const *chars,
|
||||
uint64_t &i) noexcept {
|
||||
simd_parse_if_8_digits(char16_t const *chars, uint64_t &i) noexcept {
|
||||
if (is_constant_evaluated()) {
|
||||
return false;
|
||||
}
|
||||
@ -336,7 +334,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars,
|
||||
// Load 8 UTF-16 characters (16 bytes)
|
||||
// unaligned SIMD instruction -> all fine.
|
||||
__m128i const data =
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); //-V1032
|
||||
_mm_loadu_si128(reinterpret_cast<__m128i const *>(chars));
|
||||
FASTFLOAT_SIMD_RESTORE_WARNINGS
|
||||
|
||||
// Branchless "are all digits?" trick from Lemire:
|
||||
@ -348,7 +346,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars,
|
||||
|
||||
// If mask == 0 → all digits valid.
|
||||
if (_mm_movemask_epi8(mask) == 0) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
|
||||
i = i * 100000000 + parse_8_digits(simd_read8(data));
|
||||
return true;
|
||||
}
|
||||
#elif FASTFLOAT_ARM_NEON
|
||||
@ -362,7 +360,7 @@ simd_parse_if_eight_digits_unrolled(char16_t const *chars,
|
||||
uint16x8_t const mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1));
|
||||
|
||||
if (vminvq_u16(mask) == 0xFFFF) {
|
||||
i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data));
|
||||
i = i * 100000000 + parse_8_digits(simd_read8(data));
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
@ -388,9 +386,9 @@ template <typename UC>
|
||||
#else
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
|
||||
#endif
|
||||
// dummy for compile
|
||||
bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) {
|
||||
return 0;
|
||||
// dummy for compiler
|
||||
bool simd_parse_if_8_digits_unrolled(UC const *, uint64_t &) {
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!std::is_same<UC, char>::value) = 0>
|
||||
@ -398,10 +396,9 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
loop_parse_if_digits(UC const *&p, UC const *const pend, uint64_t &i) noexcept {
|
||||
if (!is_constant_evaluated()) {
|
||||
if FASTFLOAT_CONSTEXPR17 (has_simd_opt<UC>()) {
|
||||
while (std::distance(p, pend) >= 8 /*sizeof(uint64_t)*/ &&
|
||||
simd_parse_if_eight_digits_unrolled(
|
||||
p, i)) { // may overflow, that's ok
|
||||
p += 8 /*sizeof(uint64_t)*/;
|
||||
while (std::distance(p, pend) >= 8 &&
|
||||
simd_parse_if_8_digits_unrolled(p, i)) { // may overflow, that's ok
|
||||
p += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -423,7 +420,7 @@ loop_parse_if_digits(char const *&p, char const *const pend,
|
||||
* This is only used when a complete 16-byte block exists,
|
||||
* so the load is always inside [p, pend).
|
||||
*/
|
||||
while (std::distance(p, pend) >= 16 && x86_parse_if_16_digits(p, i)) {
|
||||
while (std::distance(p, pend) >= 16 && parse_if_16_digits(p, i)) {
|
||||
p += 16;
|
||||
}
|
||||
}
|
||||
@ -431,9 +428,8 @@ loop_parse_if_digits(char const *&p, char const *const pend,
|
||||
// optimizes better than parse_if_eight_digits_unrolled() for UC = char.
|
||||
while (std::distance(p, pend) >= 8 /*sizeof(uint64_t)*/) {
|
||||
auto const val = read_chars_to_unsigned<uint64_t>(p);
|
||||
if (is_made_of_eight_digits_fast(val)) {
|
||||
i = i * 100000000 /*10 ^ sizeof(uint64_t)*/ +
|
||||
parse_eight_digits_unrolled(val); // may overflow, that's ok
|
||||
if (is_made_of_8_digits(val)) {
|
||||
i = i * 100000000 + parse_8_digits(val); // may overflow, that's ok
|
||||
p += sizeof(uint64_t);
|
||||
} else {
|
||||
break;
|
||||
@ -446,9 +442,8 @@ loop_parse_if_digits(char const *&p, char const *const pend,
|
||||
// with the leaner hot path the 4-digit step now wins on gcc as well.
|
||||
if (std::distance(p, pend) >= 4 /*sizeof(uint32_t)*/) {
|
||||
auto const val = read_chars_to_unsigned<uint32_t>(p);
|
||||
if (is_made_of_four_digits_fast(val)) {
|
||||
i = i * 10000 /*10 ^ sizeof(uint32_t)*/ +
|
||||
parse_four_digits_unrolled(val); // may overflow, that's ok
|
||||
if (is_made_of_4_digits(val)) {
|
||||
i = i * 10000 + parse_4_digits(val); // may overflow, that's ok
|
||||
p += sizeof(uint32_t);
|
||||
}
|
||||
}
|
||||
@ -911,8 +906,8 @@ parse_int_string(UC const *p, UC const *pend, T &value,
|
||||
sizeof(UC) == 1) {
|
||||
if (len >= sizeof(uint32_t)) {
|
||||
auto const digits = read_chars_to_unsigned<uint32_t>(p);
|
||||
if (is_made_of_four_digits_fast(digits)) {
|
||||
auto v = parse_four_digits_unrolled(digits);
|
||||
if (is_made_of_4_digits(digits)) {
|
||||
auto v = parse_4_digits(digits);
|
||||
if (len >= 5 && is_integer(p[4])) {
|
||||
v = v * 10 + static_cast<uint32_t>(p[4] - '0');
|
||||
if (len >= 6 && is_integer(p[5])) {
|
||||
|
||||
@ -222,7 +222,7 @@ template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
parse_eight_digits(UC const *&p, limb &value, am_digits &counter,
|
||||
am_digits &count) noexcept {
|
||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||
value = value * 100000000 + parse_8_digits(p);
|
||||
p += 8;
|
||||
counter += 8;
|
||||
count += 8;
|
||||
|
||||
@ -61,6 +61,7 @@ from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||
FASTFLOAT_CONSTEXPR20 inline double
|
||||
integer_times_pow10(uint64_t const mantissa,
|
||||
int const decimal_exponent) noexcept;
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 inline double
|
||||
integer_times_pow10(int64_t const mantissa,
|
||||
int const decimal_exponent) noexcept;
|
||||
@ -75,6 +76,7 @@ FASTFLOAT_CONSTEXPR20
|
||||
typename std::enable_if<is_supported_float_type<T>::value, T>::type
|
||||
integer_times_pow10(uint64_t const mantissa,
|
||||
int const decimal_exponent) noexcept;
|
||||
|
||||
template <typename T>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
typename std::enable_if<is_supported_float_type<T>::value, T>::type
|
||||
|
||||
@ -47,10 +47,9 @@ typedef uint_fast8_t limb_t;
|
||||
// Size of bits in the mantissa and path and rounding shifts
|
||||
typedef int_fast8_t am_bits_t;
|
||||
|
||||
// 16 bit signed integer is used for power to cover all double exponents.
|
||||
// 16 bit signed integer is used for power to cover all exponents up to double.
|
||||
typedef int_fast16_t am_pow_t;
|
||||
// Power bias is signed for handling a denormal float
|
||||
// or an invalid mantissa.
|
||||
// Power bias is signed for handling a denormal float or an invalid mantissa.
|
||||
// Bias so we can get the real exponent with an invalid adjusted_mantissa.
|
||||
constexpr static am_pow_t invalid_am_bias =
|
||||
std::numeric_limits<int16_t>::min() + 1;
|
||||
@ -269,6 +268,7 @@ static_assert(FASTFLOAT_X86_SIMD == 20 || FASTFLOAT_X86_SIMD == 42 ||
|
||||
#define fastfloat_unlikely(x) (x)
|
||||
#endif
|
||||
|
||||
// clang-format off
|
||||
#ifndef FASTFLOAT_ASSERT
|
||||
#define FASTFLOAT_ASSERT(x) \
|
||||
{ ((void)(x)); }
|
||||
@ -278,6 +278,7 @@ static_assert(FASTFLOAT_X86_SIMD == 20 || FASTFLOAT_X86_SIMD == 42 ||
|
||||
#define FASTFLOAT_DEBUG_ASSERT(x) \
|
||||
{ ((void)(x)); }
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// rust style `try!()` macro, or `?` operator
|
||||
#define FASTFLOAT_TRY(x) \
|
||||
|
||||
@ -278,7 +278,7 @@ template <typename T, typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(parsed_number_string_t<UC> const &pns, T &value) noexcept {
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
"this type of floating-point type isn't supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
@ -349,7 +349,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_float_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> const options) noexcept {
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
"this type of floating-point type isn't supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
@ -590,6 +590,10 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS
|
||||
// We are in parser code with external loop that checks bounds.
|
||||
FASTFLOAT_ASSUME(first < last);
|
||||
#endif
|
||||
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
|
||||
if (chars_format_t(options.format & chars_format::skip_white_space)) {
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
@ -597,10 +601,6 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||
}
|
||||
}
|
||||
#else
|
||||
#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS
|
||||
// We are in parser code with external loop that checks bounds.
|
||||
FASTFLOAT_ASSUME(first < last);
|
||||
#endif
|
||||
#endif
|
||||
if (
|
||||
#ifndef FASTFLOAT_ISNOT_CHECKED_BOUNDS
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user