diff --git a/include/fast_float/decimal_to_binary.h b/include/fast_float/decimal_to_binary.h index 64f3f5a..6d0f730 100644 --- a/include/fast_float/decimal_to_binary.h +++ b/include/fast_float/decimal_to_binary.h @@ -17,7 +17,7 @@ namespace fast_float { // low part corresponding to the least significant bits. // template -fastfloat_really_inline +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 compute_product_approximation(int64_t q, uint64_t w) { const int index = 2 * int(q - powers::smallest_power_of_five); // For small values of q, e.g., q in [0,27], the answer is always exact because @@ -76,7 +76,7 @@ adjusted_mantissa compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept // w * 10 ** q, without rounding the representation up. // the power2 in the exponent will be adjusted by invalid_am_bias. template -fastfloat_really_inline +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept { int lz = leading_zeroes(w); w <<= lz; @@ -90,7 +90,7 @@ adjusted_mantissa compute_error(int64_t q, uint64_t w) noexcept { // return an adjusted_mantissa with a negative power of 2: the caller should recompute // in such cases. template -fastfloat_really_inline +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept { adjusted_mantissa answer; if ((w == 0) || (q < binary::smallest_power_of_ten())) { diff --git a/include/fast_float/digit_comparison.h b/include/fast_float/digit_comparison.h index 4e0e6a8..3959ba0 100644 --- a/include/fast_float/digit_comparison.h +++ b/include/fast_float/digit_comparison.h @@ -44,7 +44,8 @@ int32_t scientific_exponent(parsed_number_string& num) noexcept { // this converts a native floating-point number to an extended-precision float. template -fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +adjusted_mantissa to_extended(T value) noexcept { using equiv_uint = typename binary_format::equiv_uint; constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); @@ -53,7 +54,11 @@ fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept { adjusted_mantissa am; int32_t bias = binary_format::mantissa_explicit_bits() - binary_format::minimum_exponent(); equiv_uint bits; +#if FASTFLOAT_HAS_BIT_CAST + bits = std::bit_cast(value); +#else ::memcpy(&bits, &value, sizeof(T)); +#endif if ((bits & exponent_mask) == 0) { // denormal am.power2 = 1 - bias; @@ -72,7 +77,8 @@ fastfloat_really_inline adjusted_mantissa to_extended(T value) noexcept { // we are given a native float that represents b, so we need to adjust it // halfway between b and b+u. template -fastfloat_really_inline adjusted_mantissa to_extended_halfway(T value) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +adjusted_mantissa to_extended_halfway(T value) noexcept { adjusted_mantissa am = to_extended(value); am.mantissa <<= 1; am.mantissa += 1; @@ -148,9 +154,10 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept { am.power2 += shift; } -fastfloat_really_inline void skip_zeros(const char*& first, const char* last) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +void skip_zeros(const char*& first, const char* last) noexcept { uint64_t val; - while (std::distance(first, last) >= 8) { + while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) { ::memcpy(&val, first, sizeof(uint64_t)); if (val != 0x3030303030303030) { break; @@ -167,10 +174,11 @@ fastfloat_really_inline void skip_zeros(const char*& first, const char* last) no // determine if any non-zero digits were truncated. // all characters must be valid digits. -fastfloat_really_inline bool is_truncated(const char* first, const char* last) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +bool is_truncated(const char* first, const char* last) noexcept { // do 8-bit optimizations, can just compare to 8 literal 0s. uint64_t val; - while (std::distance(first, last) >= 8) { + while (!cpp20_and_in_constexpr() && std::distance(first, last) >= 8) { ::memcpy(&val, first, sizeof(uint64_t)); if (val != 0x3030303030303030) { return true; @@ -186,11 +194,12 @@ fastfloat_really_inline bool is_truncated(const char* first, const char* last) n return false; } -fastfloat_really_inline bool is_truncated(byte_span s) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +bool is_truncated(byte_span s) noexcept { return is_truncated(s.ptr, s.ptr + s.len()); } -fastfloat_really_inline +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void parse_eight_digits(const char*& p, limb& value, size_t& counter, size_t& count) noexcept { value = value * 100000000 + parse_eight_digits_unrolled(p); p += 8; @@ -206,13 +215,14 @@ void parse_one_digit(const char*& p, limb& value, size_t& counter, size_t& count count++; } -fastfloat_really_inline +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void add_native(bigint& big, limb power, limb value) noexcept { big.mul(power); big.add(value); } -fastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcept { +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 +void round_up_bigint(bigint& big, size_t& count) noexcept { // need to round-up the digits, but need to avoid rounding // ....9999 to ...10000, which could cause a false halfway point. add_native(big, 10, 1); @@ -220,7 +230,8 @@ fastfloat_really_inline void round_up_bigint(bigint& big, size_t& count) noexcep } // parse the significant digits into a big integer -inline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept { +inline FASTFLOAT_CONSTEXPR20 +void parse_mantissa(bigint& result, parsed_number_string& num, size_t max_digits, size_t& digits) noexcept { // try to minimize the number of big integer and scalar multiplication. // therefore, try to parse 8 digits at a time, and multiply by the largest // scalar value (9 or 19 digits) for each step. @@ -300,7 +311,8 @@ inline void parse_mantissa(bigint& result, parsed_number_string& num, size_t max } template -inline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 +adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) noexcept { FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); adjusted_mantissa answer; bool truncated; @@ -323,7 +335,8 @@ inline adjusted_mantissa positive_digit_comp(bigint& bigmant, int32_t exponent) // we then need to scale by `2^(f- e)`, and then the two significant digits // are of the same magnitude. template -inline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept { +inline FASTFLOAT_CONSTEXPR20 +adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int32_t exponent) noexcept { bigint& real_digits = bigmant; int32_t real_exp = exponent; @@ -383,7 +396,8 @@ inline adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa // the actual digits. we then compare the big integer representations // of both, and use that to direct rounding. template -inline adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept { +inline FASTFLOAT_CONSTEXPR20 +adjusted_mantissa digit_comp(parsed_number_string& num, adjusted_mantissa am) noexcept { // remove the invalid exponent bias am.power2 -= invalid_am_bias; diff --git a/include/fast_float/fast_float.h b/include/fast_float/fast_float.h index d3497fd..12ec693 100644 --- a/include/fast_float/fast_float.h +++ b/include/fast_float/fast_float.h @@ -3,6 +3,8 @@ #include +#include "float_common.h" + namespace fast_float { enum chars_format { scientific = 1<<0, @@ -48,6 +50,7 @@ struct parse_options { * The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`. */ template +FASTFLOAT_CONSTEXPR20 from_chars_result from_chars(const char *first, const char *last, T &value, chars_format fmt = chars_format::general) noexcept; @@ -55,6 +58,7 @@ from_chars_result from_chars(const char *first, const char *last, * Like from_chars, but accepts an `options` argument to govern number parsing. */ template +FASTFLOAT_CONSTEXPR20 from_chars_result from_chars_advanced(const char *first, const char *last, T &value, parse_options options) noexcept; diff --git a/include/fast_float/parse_number.h b/include/fast_float/parse_number.h index 3284443..4f330ac 100644 --- a/include/fast_float/parse_number.h +++ b/include/fast_float/parse_number.h @@ -20,8 +20,9 @@ namespace detail { * strings a null-free and fixed. **/ template -from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept { - from_chars_result answer; +from_chars_result FASTFLOAT_CONSTEXPR14 +parse_infnan(const char *first, const char *last, T &value) noexcept { + from_chars_result answer{}; answer.ptr = first; answer.ec = std::errc(); // be optimistic bool minusSign = false; @@ -127,12 +128,14 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept { } // namespace detail template +FASTFLOAT_CONSTEXPR20 from_chars_result from_chars(const char *first, const char *last, T &value, chars_format fmt /*= chars_format::general*/) noexcept { return from_chars_advanced(first, last, value, parse_options{fmt}); } template +FASTFLOAT_CONSTEXPR20 from_chars_result from_chars_advanced(const char *first, const char *last, T &value, parse_options options) noexcept { @@ -169,7 +172,7 @@ from_chars_result from_chars_advanced(const char *first, const char *last, // We could check it first (before the previous branch), but // there might be performance advantages at having the check // be last. - if(detail::rounds_to_nearest()) { + if(!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { // We have that fegetround() == FE_TONEAREST. // Next is Clinger's fast path. if (pns.mantissa <=binary_format::max_mantissa_fast_path()) {