This might add support for big endian systems (untested).

This commit is contained in:
Daniel Lemire 2020-11-16 12:04:57 -05:00
parent db539b211c
commit 7ff364b59a
3 changed files with 51 additions and 1 deletions

View File

@ -78,6 +78,8 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
if ((p != pend) && (*p == '.')) {
++p;
const char *first_after_period = p;
#if FASTFLOAT_IS_BIG_ENDIAN == 0
// Fast approach only tested under little endian systems
if ((p + 8 <= pend) && is_made_of_eight_digits_fast(p)) {
i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
p += 8;
@ -86,6 +88,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, chars_
p += 8;
}
}
#endif
while ((p != pend) && is_integer(*p)) {
uint8_t digit = uint8_t(*p - '0');
++p;
@ -196,6 +199,7 @@ fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) n
++p;
}
}
#if FASTFLOAT_IS_BIG_ENDIAN == 0
// We expect that this loop will often take the bulk of the running time
// because when a value has lots of digits, these digits often
while ((p + 8 <= pend) && (answer.num_digits + 8 < max_digits)) {
@ -208,6 +212,7 @@ fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend) n
answer.num_digits += 8;
p += 8;
}
#endif
while ((p != pend) && is_integer(*p)) {
if (answer.num_digits < max_digits) {
answer.digits[answer.num_digits] = uint8_t(*p - '0');

View File

@ -8,6 +8,34 @@
#define FASTFLOAT_VISUAL_STUDIO 1
#endif
#ifdef _WIN32
#define FASTFLOAT_IS_BIG_ENDIAN 0
#else
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <machine/endian.h>
#else
#include <endian.h>
#endif
#
#ifndef __BYTE_ORDER__
// safe choice
#define FASTFLOAT_IS_BIG_ENDIAN 0
#endif
#
#ifndef __ORDER_LITTLE_ENDIAN__
// safe choice
#define FASTFLOAT_IS_BIG_ENDIAN 0
#endif
#
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define FASTFLOAT_IS_BIG_ENDIAN 0
#else
#define FASTFLOAT_IS_BIG_ENDIAN 1
#endif
#endif
#ifdef FASTFLOAT_VISUAL_STUDIO
#define fastfloat_really_inline __forceinline
#else
@ -154,6 +182,13 @@ struct decimal {
// Note that the user is responsible to ensure that digits are
// initialized to zero when there are fewer than 19.
inline uint64_t to_truncated_mantissa() {
#if FASTFLOAT_IS_BIG_ENDIAN == 1
for (uint32_t i = 0; i < max_digit_without_overflow;
i++) {
mantissa = mantissa * 10 + digits[i]; // can be accelerated
}
return mantissa;
#else
uint64_t val;
// 8 first digits
::memcpy(&val, digits, sizeof(uint64_t));
@ -173,6 +208,7 @@ struct decimal {
mantissa = mantissa * 10 + digits[i]; // can be accelerated
}
return mantissa;
#endif
}
// Generate san exponent matching to_truncated_mantissa()
inline int32_t to_truncated_exponent() {

View File

@ -107,7 +107,16 @@ from_chars_result from_chars(const char *first, const char *last,
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
word = pns.negative
? word | (uint64_t(1) << binary_format<T>::sign_index()) : word;
::memcpy(&value, &word, sizeof(T));
#if FASTFLOAT_IS_BIG_ENDIAN == 1
if (std::is_same<T, float>::value) {
::memcpy(&value, (char *)&word + 4, sizeof(T)); // extract value at offset 4-7 if float on big-endian
} else {
::memcpy(&value, &word, sizeof(T));
}
#else
// For little-endian systems:
::memcpy(&value, &word, sizeof(T));
#endif
return answer;
}