Compare commits

...

5 Commits

Author SHA1 Message Date
IRainman
497e65b03f * Added separate config macros FASTFLOAT_ISNOT_CHECKED_BOUNDS. 2025-11-09 19:08:11 +03:00
IRainman
c8e4d89fef # unfck lint 2025-11-09 18:15:53 +03:00
IRainman
959c9531ea # cycles (for and while) cleanup in low level for the best compiler optimization and the best runtime. 2025-11-09 18:13:17 +03:00
IRainman
b9d91e7f34 * code cleanup. 2025-11-09 17:22:13 +03:00
IRainman
e109eedd35 * try to fix error on x86 platform step3. 2025-11-09 17:21:52 +03:00
7 changed files with 56 additions and 55 deletions

View File

@ -380,15 +380,17 @@ int main() {
## You also can also use some additional options (currently only configure by macroses): ## You also can also use some additional options (currently only configure by macroses):
There is a really common use case in mathematical and other abstract syntax tree (AST) like parsers, There is a really common use case in mathematical and other abstract syntax tree (AST)-like parsers that already processes
that already process sign and all other symbols before any number by itself. In this case you can the sign and all other symbols before any number by itself. In this case you can use FastFloat to only parse positive numbers
use FastFloat for only parse positive numbers in all supported formats with macros in all supported formats with macros `FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, which significantly reduce the code size
`FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN`, that significantly reduce the code size and improve and improve performance. You also can use macros `FASTFLOAT_ISNOT_CHECKED_BOUNDS` if your code already checks bounds;
performance. Additionally you can use macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you it's very likely because all parsers need to check the first character by itself before parsing. Additionally, you can use
only uneed `FE_TONEAREST` rounding mode in the parsing: this option is also improve performance a bit. macros `FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED` if you only need `FE_TONEAREST` rounding mode in the parsing;
this option also improves performance a bit and reduces code size.
```C++ ```C++
#define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #define FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
#define FASTFLOAT_ISNOT_CHECKED_BOUNDS
#define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED #define FASTFLOAT_ONLY_ROUNDS_TO_NEAREST_SUPPORTED
#include "fast_float/fast_float.h" #include "fast_float/fast_float.h"
#include <iostream> #include <iostream>

View File

@ -49,7 +49,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t
read8_to_u64(UC const *chars) { read8_to_u64(UC const *chars) {
if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) { if (cpp20_and_in_constexpr() || !std::is_same<UC, char>::value) {
uint64_t val = 0; uint64_t val = 0;
for (uint_fast8_t i = 0; i != 8; ++i) { for (uint_fast8_t i = 0; i++ != 8;) {
val |= uint64_t(uint8_t(*chars)) << (i * 8); val |= uint64_t(uint8_t(*chars)) << (i * 8);
++chars; ++chars;
} }
@ -70,7 +70,7 @@ read8_to_u64(UC const *chars) {
#ifdef FASTFLOAT_SSE2 #ifdef FASTFLOAT_SSE2
fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const &data) {
FASTFLOAT_SIMD_DISABLE_WARNINGS FASTFLOAT_SIMD_DISABLE_WARNINGS
// _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8 // _mm_packus_epi16 is SSE2+, converts 8×u16 → 8×u8
__m128i const packed = _mm_packus_epi16(data, data); __m128i const packed = _mm_packus_epi16(data, data);
@ -94,7 +94,7 @@ fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) {
#elif defined(FASTFLOAT_NEON) #elif defined(FASTFLOAT_NEON)
fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const &data) {
FASTFLOAT_SIMD_DISABLE_WARNINGS FASTFLOAT_SIMD_DISABLE_WARNINGS
uint8x8_t utf8_packed = vmovn_u16(data); uint8x8_t utf8_packed = vmovn_u16(data);
return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0);

View File

@ -259,10 +259,9 @@ inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec<size> &vec, limb y,
limb_t start) noexcept { limb_t start) noexcept {
limb carry = y; limb carry = y;
bool overflow; bool overflow;
while (carry != 0 && start < vec.len()) { while (carry != 0 && start++ != vec.len()) {
vec[start] = scalar_add(vec[start], carry, overflow); vec[start] = scalar_add(vec[start], carry, overflow);
carry = limb(overflow); carry = limb(overflow);
++start;
} }
if (carry != 0) { if (carry != 0) {
FASTFLOAT_TRY(vec.try_push(carry)); FASTFLOAT_TRY(vec.try_push(carry));
@ -282,7 +281,7 @@ template <limb_t size>
inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec<size> &vec, inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec<size> &vec,
limb y) noexcept { limb y) noexcept {
limb carry = 0; limb carry = 0;
for (limb_t index = 0; index != vec.len(); ++index) { for (limb_t index = 0; index++ != vec.len();) {
vec[index] = scalar_mul(vec[index], y, carry); vec[index] = scalar_mul(vec[index], y, carry);
} }
if (carry != 0) { if (carry != 0) {
@ -303,7 +302,7 @@ FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec<size> &x, limb_span y,
} }
bool carry = false; bool carry = false;
for (limb_t index = 0; index < y.len(); ++index) { for (limb_t index = 0; index++ != y.len();) {
limb xi = x[index + start]; limb xi = x[index + start];
limb yi = y[index]; limb yi = y[index];
bool c1 = false; bool c1 = false;
@ -488,7 +487,7 @@ struct bigint : pow5_tables<> {
} else if (vec.len() < other.vec.len()) { } else if (vec.len() < other.vec.len()) {
return -1; return -1;
} else { } else {
for (limb_t index = vec.len(); index != 0; --index) { for (limb_t index = vec.len(); index-- != 0;) {
limb xi = vec[index - 1]; limb xi = vec[index - 1];
limb yi = other.vec[index - 1]; limb yi = other.vec[index - 1];
if (xi > yi) { if (xi > yi) {
@ -515,7 +514,7 @@ struct bigint : pow5_tables<> {
bigint_bits_t const shl = n; bigint_bits_t const shl = n;
bigint_bits_t const shr = limb_bits - shl; bigint_bits_t const shr = limb_bits - shl;
limb prev = 0; limb prev = 0;
for (limb_t index = 0; index != vec.len(); ++index) { for (limb_t index = 0; index++ != vec.len();) {
limb xi = vec[index]; limb xi = vec[index];
vec[index] = (xi << shl) | (prev >> shr); vec[index] = (xi << shl) | (prev >> shr);
prev = xi; prev = xi;
@ -535,19 +534,17 @@ struct bigint : pow5_tables<> {
// we can't shift more than the capacity of the vector. // we can't shift more than the capacity of the vector.
return false; return false;
} }
if (vec.is_empty()) { if (!vec.is_empty()) {
// nothing to do // move limbs
return true; limb *dst = vec.data + n;
limb const *src = vec.data;
std::copy_backward(src, src + vec.len(), dst + vec.len());
// fill in empty limbs
limb *first = vec.data;
limb *last = first + n;
::std::fill(first, last, 0);
vec.set_len(limb_t(n + vec.len()));
} }
// move limbs
limb *dst = vec.data + n;
limb const *src = vec.data;
std::copy_backward(src, src + vec.len(), dst + vec.len());
// fill in empty limbs
limb *first = vec.data;
limb *last = first + n;
::std::fill(first, last, 0);
vec.set_len(limb_t(n + vec.len()));
return true; return true;
} }
@ -590,12 +587,14 @@ struct bigint : pow5_tables<> {
FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); }
// multiply as if by 2 raised to a power. // multiply as if by 2 raised to a power.
FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t exp) noexcept { FASTFLOAT_CONSTEXPR20 bool pow2(am_pow_t const exp) noexcept {
FASTFLOAT_ASSERT(exp >= 0);
return shl(static_cast<fast_float::bigint_bits_t>(exp)); return shl(static_cast<fast_float::bigint_bits_t>(exp));
} }
// multiply as if by 5 raised to a power. // multiply as if by 5 raised to a power.
FASTFLOAT_CONSTEXPR20 bool pow5(am_pow_t exp) noexcept { FASTFLOAT_CONSTEXPR20 bool pow5(am_pow_t exp) noexcept {
FASTFLOAT_ASSERT(exp >= 0);
// multiply by a power of 5 // multiply by a power of 5
limb_t const large_length = sizeof(large_power_of_5) / sizeof(limb); limb_t const large_length = sizeof(large_power_of_5) / sizeof(limb);
limb_span const large = limb_span(large_power_of_5, large_length); limb_span const large = limb_span(large_power_of_5, large_length);
@ -627,6 +626,7 @@ struct bigint : pow5_tables<> {
// multiply as if by 10 raised to a power. // multiply as if by 10 raised to a power.
FASTFLOAT_CONSTEXPR20 bool pow10(am_pow_t exp) noexcept { FASTFLOAT_CONSTEXPR20 bool pow10(am_pow_t exp) noexcept {
FASTFLOAT_ASSERT(exp >= 0);
FASTFLOAT_TRY(pow5(exp)); FASTFLOAT_TRY(pow5(exp));
return pow2(exp); return pow2(exp);
} }

View File

@ -373,11 +373,9 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa positive_digit_comp(
// we then need to scale by `2^(f- e)`, and then the two significant digits // we then need to scale by `2^(f- e)`, and then the two significant digits
// are of the same magnitude. // are of the same magnitude.
template <typename T> template <typename T>
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
bigint &bigmant, adjusted_mantissa am, am_pow_t const exponent) noexcept { negative_digit_comp(bigint &real_digits, adjusted_mantissa am,
bigint &real_digits = bigmant; am_pow_t const real_exp) noexcept {
am_pow_t const &real_exp = exponent;
// get the value of `b`, rounded down, and get a bigint representation of // get the value of `b`, rounded down, and get a bigint representation of
// b+h // b+h
adjusted_mantissa am_b = am; adjusted_mantissa am_b = am;
@ -391,12 +389,12 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
false, false,
#endif #endif
am_b, b); am_b, b);
adjusted_mantissa theor = to_extended_halfway(b); adjusted_mantissa const theor = to_extended_halfway(b);
bigint theor_digits(theor.mantissa); bigint theor_digits(theor.mantissa);
am_pow_t theor_exp = theor.power2; am_pow_t const theor_exp = theor.power2;
// scale real digits and theor digits to be same power. // scale real digits and theor digits to be same power.
am_pow_t pow2_exp = theor_exp - real_exp; am_pow_t const pow2_exp = theor_exp - real_exp;
am_pow_t pow5_exp = -real_exp; am_pow_t pow5_exp = -real_exp;
if (pow5_exp != 0) { if (pow5_exp != 0) {
FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp));
@ -408,7 +406,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
} }
// compare digits, and use it to direct rounding // compare digits, and use it to direct rounding
int ord = real_digits.compare(theor_digits); int const ord = real_digits.compare(theor_digits);
round<T>(am, [ord](adjusted_mantissa &a, am_pow_t shift) { round<T>(am, [ord](adjusted_mantissa &a, am_pow_t shift) {
round_nearest_tie_even( round_nearest_tie_even(
a, shift, [ord](bool is_odd, bool _, bool __) -> bool { a, shift, [ord](bool is_odd, bool _, bool __) -> bool {

View File

@ -179,8 +179,7 @@ using parse_options = parse_options_t<char>;
#if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ #if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \
(defined(_M_AMD64) || defined(_M_X64) || \ (defined(_M_AMD64) || defined(_M_X64) || \
(defined(_M_IX86_FP) && _M_IX86_FP == 2))) (defined(_M_IX86_FP) && _M_IX86_FP == 2)))
// try to fix error on x86 platform: disable SSE2 code #define FASTFLOAT_SSE2 1
// #define FASTFLOAT_SSE2 1
#endif #endif
#if defined(__aarch64__) || defined(_M_ARM64) #if defined(__aarch64__) || defined(_M_ARM64)
@ -289,7 +288,7 @@ template <typename UC>
inline FASTFLOAT_CONSTEXPR14 bool inline FASTFLOAT_CONSTEXPR14 bool
fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
uint8_t const length) noexcept { uint8_t const length) noexcept {
for (uint8_t i = 0; i != length; ++i) { for (uint8_t i = 0; i++ != length;) {
UC const actual = actual_mixedcase[i]; UC const actual = actual_mixedcase[i];
if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
return false; return false;

View File

@ -336,14 +336,16 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value,
++first; ++first;
} }
} }
#endif
#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS
// We are in parser code with external loop that checks bounds.
FASTFLOAT_ASSUME(first < last);
#else
if (first == last) { if (first == last) {
answer.ec = std::errc::invalid_argument; answer.ec = std::errc::invalid_argument;
answer.ptr = first; answer.ptr = first;
return answer; return answer;
} }
#else
// We are in parser code with external loop that checks bounds.
FASTFLOAT_ASSUME(first < last);
#endif #endif
parsed_number_string_t<UC> const pns = parsed_number_string_t<UC> const pns =
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
@ -498,19 +500,19 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value,
static_assert(is_supported_char_type<UC>::value, static_assert(is_supported_char_type<UC>::value,
"only char, wchar_t, char16_t and char32_t are supported"); "only char, wchar_t, char16_t and char32_t are supported");
#ifdef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN
// We are in parser code with external loop that checks bounds.
FASTFLOAT_ASSUME(first < last);
// base is already checked in the parse_options_t constructor.
#else
if (chars_format_t(options.format & chars_format::skip_white_space)) { if (chars_format_t(options.format & chars_format::skip_white_space)) {
while ((first != last) && fast_float::is_space(*first)) { while ((first != last) && fast_float::is_space(*first)) {
++first; ++first;
} }
} }
#endif
#ifdef FASTFLOAT_ISNOT_CHECKED_BOUNDS
// We are in parser code with external loop that checks bounds.
FASTFLOAT_ASSUME(first < last);
#endif #endif
if ( if (
#ifndef FASTFLOAT_ONLY_POSITIVE_C_NUMBER_WO_INF_NAN #ifndef FASTFLOAT_ISNOT_CHECKED_BOUNDS
first == last || first == last ||
#endif #endif
options.base < 2 || options.base > 36) { options.base < 2 || options.base > 36) {

View File

@ -618,7 +618,7 @@ TEST_CASE("issue8") {
"752384674818467669405132000568127145263560827785771342757789609173637178" "752384674818467669405132000568127145263560827785771342757789609173637178"
"721468440901224953430146549585371050792279689258923542019956112129021960" "721468440901224953430146549585371050792279689258923542019956112129021960"
"864034418159813629774771309960518707211349999998372978"; "864034418159813629774771309960518707211349999998372978";
for (int i = 0; i < 16; i++) { for (int i = 0; i != 16; ++i) {
// Parse all but the last i chars. We should still get 3.141ish. // Parse all but the last i chars. We should still get 3.141ish.
double d = 0.0; double d = 0.0;
auto answer = fast_float::from_chars(s, s + strlen(s) - i, d); auto answer = fast_float::from_chars(s, s + strlen(s) - i, d);
@ -919,9 +919,9 @@ uint16_t get_mantissa(std::bfloat16_t f) {
} }
#endif #endif
std::string append_zeros(std::string str, size_t number_of_zeros) { std::string append_zeros(std::string_view str, size_t const number_of_zeros) {
std::string answer(str); std::string answer(str);
for (size_t i = 0; i < number_of_zeros; i++) { for (size_t i = 0; i++ != number_of_zeros;) {
answer += "0"; answer += "0";
} }
return answer; return answer;
@ -947,7 +947,7 @@ constexpr void check_basic_test_result(stringtype str, result_type result,
#define FASTFLOAT_CHECK_EQ(...) \ #define FASTFLOAT_CHECK_EQ(...) \
if constexpr (diag == Diag::runtime) { \ if constexpr (diag == Diag::runtime) { \
char narrow[global_string_capacity]{}; \ char narrow[global_string_capacity]{}; \
for (size_t i = 0; i < str.size(); i++) { \ for (size_t i = 0; i++ != str.size();) { \
narrow[i] = char(str[i]); \ narrow[i] = char(str[i]); \
} \ } \
INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \ INFO("str(char" << 8 * sizeof(typename stringtype::value_type) \
@ -1006,7 +1006,7 @@ constexpr void basic_test(std::string_view str, T expected,
// We give plenty of memory: 2048 characters. // We give plenty of memory: 2048 characters.
char16_t u16[global_string_capacity]{}; char16_t u16[global_string_capacity]{};
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i++ != str.size();) {
u16[i] = char16_t(str[i]); u16[i] = char16_t(str[i]);
} }
@ -1015,7 +1015,7 @@ constexpr void basic_test(std::string_view str, T expected,
actual, expected, expected_ec); actual, expected, expected_ec);
char32_t u32[global_string_capacity]{}; char32_t u32[global_string_capacity]{};
for (size_t i = 0; i < str.size(); i++) { for (size_t i = 0; i++ != str.size();) {
u32[i] = char32_t(str[i]); u32[i] = char32_t(str[i]);
} }