mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-02-16 23:29:54 +08:00
Constexpr proof of concept
This commit is contained in:
parent
3fd4c1b507
commit
51ec158148
@ -12,9 +12,11 @@ namespace fast_float {
|
||||
|
||||
// Next function can be micro-optimized, but compilers are entirely
|
||||
// able to optimize it well.
|
||||
fastfloat_really_inline bool is_integer(char c) noexcept { return c >= '0' && c <= '9'; }
|
||||
fastfloat_really_inline constexpr bool is_integer(char c) noexcept {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
fastfloat_really_inline uint64_t byteswap(uint64_t val) {
|
||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||
return (val & 0xFF00000000000000) >> 56
|
||||
| (val & 0x00FF000000000000) >> 40
|
||||
| (val & 0x0000FF0000000000) >> 24
|
||||
@ -84,8 +86,9 @@ struct parsed_number_string {
|
||||
|
||||
// Assuming that you use no more than 19 digits, this will
|
||||
// parse an ASCII string.
|
||||
fastfloat_really_inline
|
||||
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
||||
fastfloat_really_inline constexpr parsed_number_string
|
||||
parse_number_string(const char *p, const char *pend,
|
||||
parse_options options) noexcept {
|
||||
const chars_format fmt = options.format;
|
||||
const char decimal_point = options.decimal_point;
|
||||
|
||||
|
||||
@ -17,8 +17,8 @@ namespace fast_float {
|
||||
// low part corresponding to the least significant bits.
|
||||
//
|
||||
template <int bit_precision>
|
||||
fastfloat_really_inline
|
||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||
fastfloat_really_inline constexpr 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
|
||||
// The line value128 firstproduct = full_multiplication(w, power_of_five_128[index]);
|
||||
@ -90,8 +90,8 @@ 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 <typename binary>
|
||||
fastfloat_really_inline
|
||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||
fastfloat_really_inline constexpr adjusted_mantissa
|
||||
compute_float(int64_t q, uint64_t w) noexcept {
|
||||
adjusted_mantissa answer;
|
||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
||||
answer.power2 = 0;
|
||||
|
||||
@ -48,15 +48,17 @@ struct parse_options {
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
*/
|
||||
template<typename T>
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
constexpr from_chars_result
|
||||
from_chars(const char *first, const char *last, T &value,
|
||||
chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
/**
|
||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||
*/
|
||||
template<typename T>
|
||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||
T &value, parse_options options) noexcept;
|
||||
constexpr from_chars_result from_chars_advanced(const char *first,
|
||||
const char *last, T &value,
|
||||
parse_options options) noexcept;
|
||||
|
||||
} // namespace fast_float
|
||||
#include "parse_number.h"
|
||||
|
||||
@ -40,7 +40,7 @@ static const uint64_t power_of_five_128[number_of_entries];
|
||||
};
|
||||
|
||||
template <class unused>
|
||||
const uint64_t powers_template<unused>::power_of_five_128[number_of_entries] = {
|
||||
constexpr uint64_t powers_template<unused>::power_of_five_128[number_of_entries] = {
|
||||
0xeef453d6923bd65a,0x113faa2906a13b3f,
|
||||
0x9558b4661b6565f8,0x4ac7ca59a424c507,
|
||||
0xbaaee17fa23ebf76,0x5d79bcf00d2df649,
|
||||
|
||||
@ -6,6 +6,11 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
# include <bit>
|
||||
#endif
|
||||
|
||||
#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
|
||||
|| defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) \
|
||||
@ -112,14 +117,14 @@ template <typename T>
|
||||
struct span {
|
||||
const T* ptr;
|
||||
size_t length;
|
||||
span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {}
|
||||
span() : ptr(nullptr), length(0) {}
|
||||
constexpr span(const T* _ptr, size_t _length) : ptr(_ptr), length(_length) {}
|
||||
constexpr span() : ptr(nullptr), length(0) {}
|
||||
|
||||
constexpr size_t len() const noexcept {
|
||||
return length;
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const noexcept {
|
||||
constexpr const T& operator[](size_t index) const noexcept {
|
||||
FASTFLOAT_DEBUG_ASSERT(index < length);
|
||||
return ptr[index];
|
||||
}
|
||||
@ -128,12 +133,12 @@ struct span {
|
||||
struct value128 {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
|
||||
value128() : low(0), high(0) {}
|
||||
constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
|
||||
constexpr value128() : low(0), high(0) {}
|
||||
};
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
|
||||
fastfloat_really_inline constexpr int leading_zeroes(uint64_t input_num) {
|
||||
assert(input_num > 0);
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
@ -183,8 +188,8 @@ fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
|
||||
|
||||
|
||||
// compute 64-bit a*b
|
||||
fastfloat_really_inline value128 full_multiplication(uint64_t a,
|
||||
uint64_t b) {
|
||||
fastfloat_really_inline constexpr value128 full_multiplication(uint64_t a,
|
||||
uint64_t b) {
|
||||
value128 answer;
|
||||
#if defined(_M_ARM64) && !defined(__MINGW32__)
|
||||
// ARM64 has native support for 64-bit multiplications, no need to emulate
|
||||
@ -435,7 +440,8 @@ template <> inline constexpr binary_format<double>::equiv_uint
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||
fastfloat_really_inline constexpr void
|
||||
to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||
uint64_t word = am.mantissa;
|
||||
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||
word = negative
|
||||
@ -448,8 +454,17 @@ fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &va
|
||||
}
|
||||
#else
|
||||
// For little-endian systems:
|
||||
#ifdef __cpp_lib_bit_cast
|
||||
if constexpr (std::is_same_v<T, float>) {
|
||||
uint32_t word32 = word;
|
||||
value = std::bit_cast<float>(word32);
|
||||
} else { // double
|
||||
value = std::bit_cast<double>(word);
|
||||
}
|
||||
#else
|
||||
::memcpy(&value, &word, sizeof(T));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
#if FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
@ -127,14 +128,16 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
||||
} // namespace detail
|
||||
|
||||
template<typename T>
|
||||
from_chars_result from_chars(const char *first, const char *last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
constexpr 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<typename T>
|
||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||
T &value, parse_options options) noexcept {
|
||||
constexpr from_chars_result
|
||||
from_chars_advanced(const char *first, const char *last, T &value,
|
||||
parse_options options) noexcept {
|
||||
|
||||
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
||||
|
||||
@ -169,7 +172,11 @@ 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 (
|
||||
#if __cpp_lib_is_constant_evaluated
|
||||
std::is_constant_evaluated() ||
|
||||
#endif
|
||||
detail::rounds_to_nearest()) {
|
||||
// We have that fegetround() == FE_TONEAREST.
|
||||
// Next is Clinger's fast path.
|
||||
if (pns.mantissa <=binary_format<T>::max_mantissa_fast_path()) {
|
||||
|
||||
@ -65,6 +65,8 @@ target_compile_features(basictest PRIVATE cxx_std_17)
|
||||
fast_float_add_cpp_test(long_test)
|
||||
fast_float_add_cpp_test(powersoffive_hardround)
|
||||
fast_float_add_cpp_test(string_test)
|
||||
fast_float_add_cpp_test(constexpr)
|
||||
target_compile_features(constexpr PRIVATE cxx_std_20)
|
||||
|
||||
|
||||
|
||||
|
||||
39
tests/constexpr.cpp
Normal file
39
tests/constexpr.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "fast_float/fast_float.h"
|
||||
|
||||
constexpr double zero = [] {
|
||||
double ret = 0;
|
||||
|
||||
const char *str = "0";
|
||||
|
||||
fast_float::from_chars(str, str + 1, ret);
|
||||
|
||||
return ret;
|
||||
}();
|
||||
|
||||
static_assert(zero == 0.);
|
||||
|
||||
constexpr double pi = [] {
|
||||
double ret = 0;
|
||||
|
||||
const char *str = "3.1415";
|
||||
|
||||
fast_float::from_chars(str, str + 6, ret);
|
||||
|
||||
return ret;
|
||||
}();
|
||||
|
||||
static_assert(pi == 3.1415);
|
||||
|
||||
constexpr double googol = [] {
|
||||
double ret = 0;
|
||||
|
||||
const char *str = "1e100";
|
||||
|
||||
fast_float::from_chars(str, str + 5, ret);
|
||||
|
||||
return ret;
|
||||
}();
|
||||
|
||||
static_assert(googol == 1e100);
|
||||
|
||||
int main() { return 0; }
|
||||
Loading…
x
Reference in New Issue
Block a user