From 7ff364b59a9900a21f26c2609b2037277117b5eb Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Mon, 16 Nov 2020 12:04:57 -0500 Subject: [PATCH] This might add support for big endian systems (untested). --- include/fast_float/ascii_number.h | 5 +++++ include/fast_float/float_common.h | 36 +++++++++++++++++++++++++++++++ include/fast_float/parse_number.h | 11 +++++++++- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index bd072c6..d39ad52 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -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'); diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 7879654..a208741 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -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 +#else +#include +#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() { diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 4652cc8..1b7a419 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -107,7 +107,16 @@ from_chars_result from_chars(const char *first, const char *last, word |= uint64_t(am.power2) << binary_format::mantissa_explicit_bits(); word = pns.negative ? word | (uint64_t(1) << binary_format::sign_index()) : word; - ::memcpy(&value, &word, sizeof(T)); +#if FASTFLOAT_IS_BIG_ENDIAN == 1 + if (std::is_same::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; }