mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 16:56:57 +08:00
Minor tweak.
This commit is contained in:
parent
eb1103393e
commit
c53bfc4176
@ -16,31 +16,36 @@ fastfloat_really_inline bool is_integer(char c) noexcept { return (c >= '0' &&
|
|||||||
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
// credit: https://johnnylee-sde.github.io/Fast-numeric-string-to-int/
|
||||||
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
memcpy(&val, chars, sizeof(uint64_t));
|
::memcpy(&val, chars, sizeof(uint64_t));
|
||||||
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
val = (val & 0x0F0F0F0F0F0F0F0F) * 2561 >> 8;
|
||||||
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
val = (val & 0x00FF00FF00FF00FF) * 6553601 >> 16;
|
||||||
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
return uint32_t((val & 0x0000FFFF0000FFFF) * 42949672960001 >> 32);
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||||
uint64_t val;
|
|
||||||
memcpy(&val, chars, 8);
|
|
||||||
return (((val & 0xF0F0F0F0F0F0F0F0) |
|
return (((val & 0xF0F0F0F0F0F0F0F0) |
|
||||||
(((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) ==
|
(((val + 0x0606060606060606) & 0xF0F0F0F0F0F0F0F0) >> 4)) ==
|
||||||
0x3333333333333333);
|
0x3333333333333333);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||||
|
uint64_t val;
|
||||||
|
::memcpy(&val, chars, 8);
|
||||||
|
return is_made_of_eight_digits_fast(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fastfloat_really_inline uint32_t parse_four_digits_unrolled(const char *chars) noexcept {
|
fastfloat_really_inline uint32_t parse_four_digits_unrolled(const char *chars) noexcept {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
memcpy(&val, chars, sizeof(uint32_t));
|
::memcpy(&val, chars, sizeof(uint32_t));
|
||||||
val = (val & 0x0F0F0F0F) * 2561 >> 8;
|
val = (val & 0x0F0F0F0F) * 2561 >> 8;
|
||||||
return (val & 0x00FF00FF) * 6553601 >> 16;
|
return (val & 0x00FF00FF) * 6553601 >> 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline bool is_made_of_four_digits_fast(const char *chars) noexcept {
|
fastfloat_really_inline bool is_made_of_four_digits_fast(const char *chars) noexcept {
|
||||||
uint32_t val;
|
uint32_t val;
|
||||||
memcpy(&val, chars, 4);
|
::memcpy(&val, chars, 4);
|
||||||
return (((val & 0xF0F0F0F0) |
|
return (((val & 0xF0F0F0F0) |
|
||||||
(((val + 0x06060606) & 0xF0F0F0F0) >> 4)) ==
|
(((val + 0x06060606) & 0xF0F0F0F0) >> 4)) ==
|
||||||
0x33333333);
|
0x33333333);
|
||||||
@ -162,95 +167,20 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
|
|||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This should always succeed since it follows a call to parse_number_string.
|
|
||||||
// It assumes that there are more than 19 mantissa digits to parse.
|
|
||||||
parsed_number_string parse_truncated_decimal(const char *&p, const char *pend) noexcept {
|
|
||||||
parsed_number_string answer;
|
|
||||||
answer.valid = true;
|
|
||||||
answer.negative = (*p == '-');
|
|
||||||
if ((*p == '-') || (*p == '+')) {
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
size_t number_of_digits{0};
|
|
||||||
|
|
||||||
|
|
||||||
uint64_t i = 0;
|
|
||||||
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
|
||||||
// multiplication
|
|
||||||
if(number_of_digits < 19) {
|
|
||||||
|
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
|
||||||
i = 10 * i + digit;
|
|
||||||
number_of_digits ++;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
int64_t exponent = 0;
|
|
||||||
if ((p != pend) && (*p == '.')) {
|
|
||||||
++p;
|
|
||||||
const char *first_after_period = p;
|
|
||||||
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
if(number_of_digits < 19) {
|
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
|
||||||
i = i * 10 + digit;
|
|
||||||
number_of_digits ++;
|
|
||||||
} else if (exponent == 0) {
|
|
||||||
exponent = first_after_period - p;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((p != pend) && (('e' == *p) || ('E' == *p))) {
|
|
||||||
int64_t exp_number = 0; // exponential part
|
|
||||||
++p;
|
|
||||||
bool neg_exp = false;
|
|
||||||
if ((p != pend) && ('-' == *p)) {
|
|
||||||
neg_exp = true;
|
|
||||||
++p;
|
|
||||||
} else if ((p != pend) && ('+' == *p)) {
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
if ((p == pend) || !is_integer(*p)) {
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
while ((p != pend) && is_integer(*p)) {
|
|
||||||
uint8_t digit = uint8_t(*p - '0');
|
|
||||||
if (exp_number < 0x10000) {
|
|
||||||
exp_number = 10 * exp_number + digit;
|
|
||||||
}
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
exponent += (neg_exp ? -exp_number : exp_number);
|
|
||||||
}
|
|
||||||
answer.lastmatch = p;
|
|
||||||
answer.valid = true;
|
|
||||||
answer.too_many_digits = true; // assumed
|
|
||||||
answer.exponent = exponent;
|
|
||||||
answer.mantissa = i;
|
|
||||||
return answer;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This should always succeed since it follows a call to parse_number_string.
|
// This should always succeed since it follows a call to parse_number_string.
|
||||||
decimal parse_decimal(const char *&p, const char *pend) noexcept {
|
decimal parse_decimal(const char *p, const char *pend) noexcept {
|
||||||
decimal answer;
|
decimal answer;
|
||||||
answer.num_digits = 0;
|
answer.num_digits = 0;
|
||||||
answer.decimal_point = 0;
|
answer.decimal_point = 0;
|
||||||
answer.negative = false;
|
answer.negative = false;
|
||||||
answer.truncated = false;
|
answer.truncated = false;
|
||||||
// skip leading whitespace
|
// any whitespace has been skipped.
|
||||||
while (fast_float::is_space(*p)) {
|
|
||||||
p++;
|
|
||||||
}
|
|
||||||
answer.negative = (*p == '-');
|
answer.negative = (*p == '-');
|
||||||
if ((*p == '-') || (*p == '+')) {
|
if ((*p == '-') || (*p == '+')) {
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
// skip leading zeroes
|
||||||
while ((p != pend) && (*p == '0')) {
|
while ((p != pend) && (*p == '0')) {
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
@ -273,8 +203,17 @@ decimal parse_decimal(const char *&p, const char *pend) noexcept {
|
|||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
while ((p + 8 <= pend) && (answer.num_digits + 8 < max_digits)) {
|
||||||
|
uint64_t val;
|
||||||
|
::memcpy(&val, p, sizeof(uint64_t));
|
||||||
|
if(! is_made_of_eight_digits_fast(val)) break;
|
||||||
|
val -= 0x3030303030303030;
|
||||||
|
::memcpy(answer.digits + answer.num_digits, &val, sizeof(uint64_t));
|
||||||
|
answer.num_digits += 8;
|
||||||
|
p += 8;
|
||||||
|
}
|
||||||
while ((p != pend) && is_integer(*p)) {
|
while ((p != pend) && is_integer(*p)) {
|
||||||
if (answer.num_digits + 1 < max_digits) {
|
if (answer.num_digits < max_digits) {
|
||||||
answer.digits[answer.num_digits] = uint8_t(*p - '0');
|
answer.digits[answer.num_digits] = uint8_t(*p - '0');
|
||||||
} else {
|
} else {
|
||||||
answer.truncated = true;
|
answer.truncated = true;
|
||||||
@ -299,7 +238,7 @@ decimal parse_decimal(const char *&p, const char *pend) noexcept {
|
|||||||
uint8_t digit = uint8_t(*p - '0');
|
uint8_t digit = uint8_t(*p - '0');
|
||||||
if (exp_number < 0x10000) {
|
if (exp_number < 0x10000) {
|
||||||
exp_number = 10 * exp_number + digit;
|
exp_number = 10 * exp_number + digit;
|
||||||
}
|
}
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
answer.decimal_point += (neg_exp ? -exp_number : exp_number);
|
answer.decimal_point += (neg_exp ? -exp_number : exp_number);
|
||||||
|
|||||||
@ -139,7 +139,14 @@ struct decimal {
|
|||||||
bool negative;
|
bool negative;
|
||||||
bool truncated;
|
bool truncated;
|
||||||
uint8_t digits[max_digits];
|
uint8_t digits[max_digits];
|
||||||
|
decimal() = default;
|
||||||
|
// Copies are not allowed since this is a fat object.
|
||||||
|
decimal(const decimal &) = delete;
|
||||||
|
// Copies are not allowed since this is a fat object.
|
||||||
|
decimal & operator=(const decimal &) = delete;
|
||||||
|
// Moves are allowed:
|
||||||
|
decimal(decimal &&) = default;
|
||||||
|
decimal& operator=(decimal&& other) = default;
|
||||||
// Generates a mantissa by truncating to 19 digits; this function assumes
|
// Generates a mantissa by truncating to 19 digits; this function assumes
|
||||||
// that num_digits >= 19 (the caller is responsible for the check).
|
// that num_digits >= 19 (the caller is responsible for the check).
|
||||||
// This function should be reasonably fast.
|
// This function should be reasonably fast.
|
||||||
|
|||||||
@ -107,7 +107,7 @@ from_chars_result from_chars(const char *first, const char *last,
|
|||||||
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||||
word = pns.negative
|
word = pns.negative
|
||||||
? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
|
? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
|
||||||
memcpy(&value, &word, sizeof(T));
|
::memcpy(&value, &word, sizeof(T));
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user