mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 16:56:57 +08:00
Make all float_common.h functions constexpr in C++20
This commit is contained in:
parent
a3e00eed59
commit
52618851fd
@ -7,6 +7,25 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cpp_lib_bit_cast >= 201806L
|
||||||
|
#include <bit>
|
||||||
|
#define FASTFLOAT_HAS_BIT_CAST 1
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_HAS_BIT_CAST 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __cpp_lib_is_constant_evaluated >= 201811L
|
||||||
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
||||||
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
|
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
|
||||||
|| defined(__MINGW64__) \
|
|| defined(__MINGW64__) \
|
||||||
@ -98,8 +117,25 @@
|
|||||||
#define FASTFLOAT_CONSTEXPR14
|
#define FASTFLOAT_CONSTEXPR14
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Testing for relevant C++20 constexpr library features
|
||||||
|
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED \
|
||||||
|
&& FASTFLOAT_HAS_BIT_CAST \
|
||||||
|
&& __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||||
|
#define FASTFLOAT_CONSTEXPR20 constexpr
|
||||||
|
#else
|
||||||
|
#define FASTFLOAT_CONSTEXPR20
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
|
|
||||||
|
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
||||||
|
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
|
||||||
|
return std::is_constant_evaluated();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Compares two ASCII strings in a case insensitive manner.
|
// Compares two ASCII strings in a case insensitive manner.
|
||||||
inline FASTFLOAT_CONSTEXPR14 bool
|
inline FASTFLOAT_CONSTEXPR14 bool
|
||||||
fastfloat_strncasecmp(const char *input1, const char *input2, size_t length) {
|
fastfloat_strncasecmp(const char *input1, const char *input2, size_t length) {
|
||||||
@ -139,9 +175,27 @@ struct value128 {
|
|||||||
constexpr value128() : low(0), high(0) {}
|
constexpr value128() : low(0), high(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Helper C++11 constexpr generic implementation of leading_zeroes */
|
||||||
|
fastfloat_really_inline constexpr
|
||||||
|
int leading_zeroes_generic(uint64_t input_num, int last_bit = 0) {
|
||||||
|
return (
|
||||||
|
((input_num & uint64_t(0xffffffff00000000)) && (input_num >>= 32, last_bit |= 32)),
|
||||||
|
((input_num & uint64_t( 0xffff0000)) && (input_num >>= 16, last_bit |= 16)),
|
||||||
|
((input_num & uint64_t( 0xff00)) && (input_num >>= 8, last_bit |= 8)),
|
||||||
|
((input_num & uint64_t( 0xf0)) && (input_num >>= 4, last_bit |= 4)),
|
||||||
|
((input_num & uint64_t( 0xc)) && (input_num >>= 2, last_bit |= 2)),
|
||||||
|
((input_num & uint64_t( 0x2)) && (input_num >>= 1, last_bit |= 1)),
|
||||||
|
63 - last_bit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/* result might be undefined when input_num is zero */
|
/* result might be undefined when input_num is zero */
|
||||||
fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
int leading_zeroes(uint64_t input_num) {
|
||||||
assert(input_num > 0);
|
assert(input_num > 0);
|
||||||
|
if (cpp20_and_in_constexpr()) {
|
||||||
|
return leading_zeroes_generic(input_num);
|
||||||
|
}
|
||||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
#if defined(_M_X64) || defined(_M_ARM64)
|
#if defined(_M_X64) || defined(_M_ARM64)
|
||||||
unsigned long leading_zero = 0;
|
unsigned long leading_zero = 0;
|
||||||
@ -150,31 +204,20 @@ fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
_BitScanReverse64(&leading_zero, input_num);
|
_BitScanReverse64(&leading_zero, input_num);
|
||||||
return (int)(63 - leading_zero);
|
return (int)(63 - leading_zero);
|
||||||
#else
|
#else
|
||||||
int last_bit = 0;
|
return leading_zeroes_generic(input_num);
|
||||||
if(input_num & uint64_t(0xffffffff00000000)) input_num >>= 32, last_bit |= 32;
|
|
||||||
if(input_num & uint64_t( 0xffff0000)) input_num >>= 16, last_bit |= 16;
|
|
||||||
if(input_num & uint64_t( 0xff00)) input_num >>= 8, last_bit |= 8;
|
|
||||||
if(input_num & uint64_t( 0xf0)) input_num >>= 4, last_bit |= 4;
|
|
||||||
if(input_num & uint64_t( 0xc)) input_num >>= 2, last_bit |= 2;
|
|
||||||
if(input_num & uint64_t( 0x2)) input_num >>= 1, last_bit |= 1;
|
|
||||||
return 63 - last_bit;
|
|
||||||
#endif
|
#endif
|
||||||
#else
|
#else
|
||||||
return __builtin_clzll(input_num);
|
return __builtin_clzll(input_num);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FASTFLOAT_32BIT
|
|
||||||
|
|
||||||
// slow emulation routine for 32-bit
|
// slow emulation routine for 32-bit
|
||||||
fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) {
|
fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) {
|
||||||
return x * (uint64_t)y;
|
return x * (uint64_t)y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// slow emulation routine for 32-bit
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||||
#if !defined(__MINGW64__)
|
uint64_t umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||||
fastfloat_really_inline constexpr uint64_t _umul128(uint64_t ab, uint64_t cd,
|
|
||||||
uint64_t *hi) {
|
|
||||||
uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
|
uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd);
|
||||||
uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
|
uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd);
|
||||||
uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
|
uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32));
|
||||||
@ -184,14 +227,28 @@ fastfloat_really_inline constexpr uint64_t _umul128(uint64_t ab, uint64_t cd,
|
|||||||
(adbc_carry << 32) + !!(lo < bd);
|
(adbc_carry << 32) + !!(lo < bd);
|
||||||
return lo;
|
return lo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef FASTFLOAT_32BIT
|
||||||
|
|
||||||
|
// slow emulation routine for 32-bit
|
||||||
|
#if !defined(__MINGW64__)
|
||||||
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||||
|
uint64_t _umul128(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||||
|
return umul128_generic(ab, cd, hi);
|
||||||
|
}
|
||||||
#endif // !__MINGW64__
|
#endif // !__MINGW64__
|
||||||
|
|
||||||
#endif // FASTFLOAT_32BIT
|
#endif // FASTFLOAT_32BIT
|
||||||
|
|
||||||
|
|
||||||
// compute 64-bit a*b
|
// compute 64-bit a*b
|
||||||
fastfloat_really_inline value128 full_multiplication(uint64_t a,
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
uint64_t b) {
|
value128 full_multiplication(uint64_t a, uint64_t b) {
|
||||||
|
if (cpp20_and_in_constexpr()) {
|
||||||
|
value128 answer;
|
||||||
|
answer.low = umul128_generic(a, b, &answer.high);
|
||||||
|
return answer;
|
||||||
|
}
|
||||||
value128 answer;
|
value128 answer;
|
||||||
#if defined(_M_ARM64) && !defined(__MINGW32__)
|
#if defined(_M_ARM64) && !defined(__MINGW32__)
|
||||||
// ARM64 has native support for 64-bit multiplications, no need to emulate
|
// ARM64 has native support for 64-bit multiplications, no need to emulate
|
||||||
@ -205,7 +262,7 @@ fastfloat_really_inline value128 full_multiplication(uint64_t a,
|
|||||||
answer.low = uint64_t(r);
|
answer.low = uint64_t(r);
|
||||||
answer.high = uint64_t(r >> 64);
|
answer.high = uint64_t(r >> 64);
|
||||||
#else
|
#else
|
||||||
#error Not implemented
|
answer.low = umul128_generic(a, b, &answer.high);
|
||||||
#endif
|
#endif
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
@ -442,12 +499,17 @@ template <> inline constexpr binary_format<double>::equiv_uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
|
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||||
|
void to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||||
using uint = typename binary_format<T>::equiv_uint;
|
using uint = typename binary_format<T>::equiv_uint;
|
||||||
uint word = (uint)am.mantissa;
|
uint word = (uint)am.mantissa;
|
||||||
word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
word |= uint(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||||
word |= uint(negative) << binary_format<T>::sign_index();
|
word |= uint(negative) << binary_format<T>::sign_index();
|
||||||
|
#if FASTFLOAT_HAS_BIT_CAST
|
||||||
|
value = std::bit_cast<T>(word);
|
||||||
|
#else
|
||||||
::memcpy(&value, &word, sizeof(T));
|
::memcpy(&value, &word, sizeof(T));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user