Merge branch 'fastfloat:main' into main

This commit is contained in:
RealTimeChris 2025-01-08 10:04:25 -05:00 committed by GitHub
commit 4ed10f7e39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 144 additions and 19 deletions

View File

@ -1,2 +1,4 @@
BasedOnStyle: LLVM BasedOnStyle: LLVM
SortIncludes: false SortIncludes: false
SeparateDefinitionBlocks: Always
MaxEmptyLinesToKeep: 1

View File

@ -27,7 +27,7 @@ jobs:
- uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7 - uses: actions/checkout@9a9194f87191a7e9055e3e9b95b8cfb13023bb08 # v4.1.7
- name: Run clang-format - name: Run clang-format
uses: jidicula/clang-format-action@c74383674bf5f7c69f60ce562019c1c94bc1421a # v4.13.0 uses: jidicula/clang-format-action@d05cecd4a1a5b7e64c22f5a468456135a43f13f6 # v4.14.0
with: with:
clang-format-version: '17' clang-format-version: '17'

View File

@ -366,7 +366,7 @@ The fast_float library is part of:
* [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's * [WebKit](https://github.com/WebKit/WebKit), the engine behind Safari (Apple's
web browser), web browser),
* [DuckDB](https://duckdb.org), * [DuckDB](https://duckdb.org),
* [Redis](https://github.com/redis/redis), * [Redis](https://github.com/redis/redis) and [Valkey](https://github.com/valkey-io/valkey),
* [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied * [Apache Arrow](https://github.com/apache/arrow/pull/8494) where it multiplied
the number parsing speed by two or three times, the number parsing speed by two or three times,
* [Google Jsonnet](https://github.com/google/jsonnet), * [Google Jsonnet](https://github.com/google/jsonnet),

View File

@ -52,10 +52,13 @@ struct performance_counters {
double branches; double branches;
double missed_branches; double missed_branches;
double instructions; double instructions;
performance_counters(uint64_t c, uint64_t b, uint64_t m, uint64_t i) performance_counters(uint64_t c, uint64_t b, uint64_t m, uint64_t i)
: cycles(c), branches(b), missed_branches(m), instructions(i) {} : cycles(c), branches(b), missed_branches(m), instructions(i) {}
performance_counters(double c, double b, double m, double i) performance_counters(double c, double b, double m, double i)
: cycles(c), branches(b), missed_branches(m), instructions(i) {} : cycles(c), branches(b), missed_branches(m), instructions(i) {}
performance_counters(double init) performance_counters(double init)
: cycles(init), branches(init), missed_branches(init), : cycles(init), branches(init), missed_branches(init),
instructions(init) {} instructions(init) {}
@ -67,6 +70,7 @@ struct performance_counters {
instructions -= other.instructions; instructions -= other.instructions;
return *this; return *this;
} }
inline performance_counters &min(const performance_counters &other) { inline performance_counters &min(const performance_counters &other) {
cycles = other.cycles < cycles ? other.cycles : cycles; cycles = other.cycles < cycles ? other.cycles : cycles;
branches = other.branches < branches ? other.branches : branches; branches = other.branches < branches ? other.branches : branches;
@ -77,6 +81,7 @@ struct performance_counters {
other.instructions < instructions ? other.instructions : instructions; other.instructions < instructions ? other.instructions : instructions;
return *this; return *this;
} }
inline performance_counters &operator+=(const performance_counters &other) { inline performance_counters &operator+=(const performance_counters &other) {
cycles += other.cycles; cycles += other.cycles;
branches += other.branches; branches += other.branches;
@ -920,6 +925,7 @@ static int kdebug_wait(usize timeout_ms, bool *suc) {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
#define EVENT_NAME_MAX 8 #define EVENT_NAME_MAX 8
typedef struct { typedef struct {
const char *alias; /// name for print const char *alias; /// name for print
const char *names[EVENT_NAME_MAX]; /// name from pmc db const char *names[EVENT_NAME_MAX]; /// name from pmc db

View File

@ -187,7 +187,7 @@ std::vector<std::u16string> widen(const std::vector<std::string> &lines) {
} }
void process(std::vector<std::string> &lines, size_t volume) { void process(std::vector<std::string> &lines, size_t volume) {
size_t repeat = 100; size_t repeat = 1000;
double volumeMB = volume / (1024. * 1024.); double volumeMB = volume / (1024. * 1024.);
std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl; std::cout << "ASCII volume = " << volumeMB << " MB " << std::endl;
pretty_print(volume, lines.size(), "fastfloat (64)", pretty_print(volume, lines.size(), "fastfloat (64)",

View File

@ -24,10 +24,13 @@
struct event_count { struct event_count {
std::chrono::duration<double> elapsed; std::chrono::duration<double> elapsed;
std::vector<unsigned long long> event_counts; std::vector<unsigned long long> event_counts;
event_count() : elapsed(0), event_counts{0, 0, 0, 0, 0} {} event_count() : elapsed(0), event_counts{0, 0, 0, 0, 0} {}
event_count(const std::chrono::duration<double> _elapsed, event_count(const std::chrono::duration<double> _elapsed,
const std::vector<unsigned long long> _event_counts) const std::vector<unsigned long long> _event_counts)
: elapsed(_elapsed), event_counts(_event_counts) {} : elapsed(_elapsed), event_counts(_event_counts) {}
event_count(const event_count &other) event_count(const event_count &other)
: elapsed(other.elapsed), event_counts(other.event_counts) {} : elapsed(other.elapsed), event_counts(other.event_counts) {}
@ -42,18 +45,23 @@ struct event_count {
double elapsed_sec() const { double elapsed_sec() const {
return std::chrono::duration<double>(elapsed).count(); return std::chrono::duration<double>(elapsed).count();
} }
double elapsed_ns() const { double elapsed_ns() const {
return std::chrono::duration<double, std::nano>(elapsed).count(); return std::chrono::duration<double, std::nano>(elapsed).count();
} }
double cycles() const { double cycles() const {
return static_cast<double>(event_counts[CPU_CYCLES]); return static_cast<double>(event_counts[CPU_CYCLES]);
} }
double instructions() const { double instructions() const {
return static_cast<double>(event_counts[INSTRUCTIONS]); return static_cast<double>(event_counts[INSTRUCTIONS]);
} }
double branches() const { double branches() const {
return static_cast<double>(event_counts[BRANCHES]); return static_cast<double>(event_counts[BRANCHES]);
} }
double missed_branches() const { double missed_branches() const {
return static_cast<double>(event_counts[MISSED_BRANCHES]); return static_cast<double>(event_counts[MISSED_BRANCHES]);
} }
@ -63,6 +71,7 @@ struct event_count {
this->event_counts = other.event_counts; this->event_counts = other.event_counts;
return *this; return *this;
} }
event_count operator+(const event_count &other) const { event_count operator+(const event_count &other) const {
return event_count(elapsed + other.elapsed, return event_count(elapsed + other.elapsed,
{ {
@ -98,10 +107,15 @@ struct event_aggregate {
} }
double elapsed_sec() const { return total.elapsed_sec() / iterations; } double elapsed_sec() const { return total.elapsed_sec() / iterations; }
double elapsed_ns() const { return total.elapsed_ns() / iterations; } double elapsed_ns() const { return total.elapsed_ns() / iterations; }
double cycles() const { return total.cycles() / iterations; } double cycles() const { return total.cycles() / iterations; }
double instructions() const { return total.instructions() / iterations; } double instructions() const { return total.instructions() / iterations; }
double branches() const { return total.branches() / iterations; } double branches() const { return total.branches() / iterations; }
double missed_branches() const { double missed_branches() const {
return total.missed_branches() / iterations; return total.missed_branches() / iterations;
} }
@ -113,18 +127,23 @@ struct event_collector {
#if defined(__linux__) #if defined(__linux__)
LinuxEvents<PERF_TYPE_HARDWARE> linux_events; LinuxEvents<PERF_TYPE_HARDWARE> linux_events;
event_collector() event_collector()
: linux_events(std::vector<int>{ : linux_events(std::vector<int>{
PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS, PERF_COUNT_HW_CPU_CYCLES, PERF_COUNT_HW_INSTRUCTIONS,
PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions PERF_COUNT_HW_BRANCH_INSTRUCTIONS, // Retired branch instructions
PERF_COUNT_HW_BRANCH_MISSES}) {} PERF_COUNT_HW_BRANCH_MISSES}) {}
bool has_events() { return linux_events.is_working(); } bool has_events() { return linux_events.is_working(); }
#elif __APPLE__ && __aarch64__ #elif __APPLE__ && __aarch64__
performance_counters diff; performance_counters diff;
event_collector() : diff(0) { setup_performance_counters(); } event_collector() : diff(0) { setup_performance_counters(); }
bool has_events() { return setup_performance_counters(); } bool has_events() { return setup_performance_counters(); }
#else #else
event_collector() {} event_collector() {}
bool has_events() { return false; } bool has_events() { return false; }
#endif #endif
@ -138,6 +157,7 @@ struct event_collector {
#endif #endif
start_clock = std::chrono::steady_clock::now(); start_clock = std::chrono::steady_clock::now();
} }
inline event_count &end() { inline event_count &end() {
const auto end_clock = std::chrono::steady_clock::now(); const auto end_clock = std::chrono::steady_clock::now();
#if defined(__linux) #if defined(__linux)

View File

@ -57,10 +57,12 @@ template <uint16_t size> struct stackvec {
FASTFLOAT_DEBUG_ASSERT(index < length); FASTFLOAT_DEBUG_ASSERT(index < length);
return data[index]; return data[index];
} }
FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept {
FASTFLOAT_DEBUG_ASSERT(index < length); FASTFLOAT_DEBUG_ASSERT(index < length);
return data[index]; return data[index];
} }
// index from the end of the container // index from the end of the container
FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept {
FASTFLOAT_DEBUG_ASSERT(index < length); FASTFLOAT_DEBUG_ASSERT(index < length);
@ -72,14 +74,19 @@ template <uint16_t size> struct stackvec {
FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept {
length = uint16_t(len); length = uint16_t(len);
} }
constexpr size_t len() const noexcept { return length; } constexpr size_t len() const noexcept { return length; }
constexpr bool is_empty() const noexcept { return length == 0; } constexpr bool is_empty() const noexcept { return length == 0; }
constexpr size_t capacity() const noexcept { return size; } constexpr size_t capacity() const noexcept { return size; }
// append item to vector, without bounds checking // append item to vector, without bounds checking
FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept {
data[length] = value; data[length] = value;
length++; length++;
} }
// append item to vector, returning if item was added // append item to vector, returning if item was added
FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept { FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept {
if (len() < capacity()) { if (len() < capacity()) {
@ -89,12 +96,14 @@ template <uint16_t size> struct stackvec {
return false; return false;
} }
} }
// add items to the vector, from a span, without bounds checking // add items to the vector, from a span, without bounds checking
FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept {
limb *ptr = data + length; limb *ptr = data + length;
std::copy_n(s.ptr, s.len(), ptr); std::copy_n(s.ptr, s.len(), ptr);
set_len(len() + s.len()); set_len(len() + s.len());
} }
// try to add items to the vector, returning if items were added // try to add items to the vector, returning if items were added
FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept { FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept {
if (len() + s.len() <= capacity()) { if (len() + s.len() <= capacity()) {
@ -104,6 +113,7 @@ template <uint16_t size> struct stackvec {
return false; return false;
} }
} }
// resize the vector, without bounds checking // resize the vector, without bounds checking
// if the new size is longer than the vector, assign value to each // if the new size is longer than the vector, assign value to each
// appended item. // appended item.
@ -119,6 +129,7 @@ template <uint16_t size> struct stackvec {
set_len(new_len); set_len(new_len);
} }
} }
// try to resize the vector, returning if the vector was resized. // try to resize the vector, returning if the vector was resized.
FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept {
if (new_len > capacity()) { if (new_len > capacity()) {
@ -128,6 +139,7 @@ template <uint16_t size> struct stackvec {
return true; return true;
} }
} }
// check if any limbs are non-zero after the given index. // check if any limbs are non-zero after the given index.
// this needs to be done in reverse order, since the index // this needs to be done in reverse order, since the index
// is relative to the most significant limbs. // is relative to the most significant limbs.
@ -140,6 +152,7 @@ template <uint16_t size> struct stackvec {
} }
return false; return false;
} }
// normalize the big integer, so most-significant zero limbs are removed. // normalize the big integer, so most-significant zero limbs are removed.
FASTFLOAT_CONSTEXPR14 void normalize() noexcept { FASTFLOAT_CONSTEXPR14 void normalize() noexcept {
while (len() > 0 && rindex(0) == 0) { while (len() > 0 && rindex(0) == 0) {
@ -423,6 +436,7 @@ struct bigint : pow5_tables<> {
stackvec<bigint_limbs> vec; stackvec<bigint_limbs> vec;
FASTFLOAT_CONSTEXPR20 bigint() : vec() {} FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
bigint(bigint const &) = delete; bigint(bigint const &) = delete;
bigint &operator=(bigint const &) = delete; bigint &operator=(bigint const &) = delete;
bigint(bigint &&) = delete; bigint(bigint &&) = delete;

View File

@ -62,7 +62,7 @@ scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
template <typename T> template <typename T>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
to_extended(T value) noexcept { to_extended(T value) noexcept {
using equiv_uint = typename binary_format<T>::equiv_uint; using equiv_uint = equiv_uint_t<T>;
constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask(); constexpr equiv_uint exponent_mask = binary_format<T>::exponent_mask();
constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask(); constexpr equiv_uint mantissa_mask = binary_format<T>::mantissa_mask();
constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask(); constexpr equiv_uint hidden_bit_mask = binary_format<T>::hidden_bit_mask();
@ -170,6 +170,7 @@ round_down(adjusted_mantissa &am, int32_t shift) noexcept {
} }
am.power2 += shift; am.power2 += shift;
} }
template <typename UC> template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
skip_zeros(UC const *&first, UC const *last) noexcept { skip_zeros(UC const *&first, UC const *last) noexcept {
@ -213,6 +214,7 @@ is_truncated(UC const *first, UC const *last) noexcept {
} }
return false; return false;
} }
template <typename UC> template <typename UC>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool
is_truncated(span<UC const> s) noexcept { is_truncated(span<UC const> s) noexcept {

View File

@ -54,5 +54,6 @@ FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept; from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept;
} // namespace fast_float } // namespace fast_float
#include "parse_number.h" #include "parse_number.h"
#endif // FASTFLOAT_FAST_FLOAT_H #endif // FASTFLOAT_FAST_FLOAT_H

View File

@ -58,6 +58,7 @@ template <typename UC> struct from_chars_result_t {
UC const *ptr; UC const *ptr;
std::errc ec; std::errc ec;
}; };
using from_chars_result = from_chars_result_t<char>; using from_chars_result = from_chars_result_t<char>;
template <typename UC> struct parse_options_t { template <typename UC> struct parse_options_t {
@ -72,6 +73,7 @@ template <typename UC> struct parse_options_t {
/** The base used for integers */ /** The base used for integers */
int base; int base;
}; };
using parse_options = parse_options_t<char>; using parse_options = parse_options_t<char>;
} // namespace fast_float } // namespace fast_float
@ -225,15 +227,23 @@ template <typename T>
struct is_supported_float_type struct is_supported_float_type
: std::integral_constant<bool, std::is_same<T, float>::value || : std::integral_constant<bool, std::is_same<T, float>::value ||
std::is_same<T, double>::value std::is_same<T, double>::value
#if __STDCPP_FLOAT32_T__ #ifdef __STDCPP_FLOAT32_T__
|| std::is_same<T, std::float32_t>::value || std::is_same<T, std::float32_t>::value
#endif #endif
#if __STDCPP_FLOAT64_T__ #ifdef __STDCPP_FLOAT64_T__
|| std::is_same<T, std::float64_t>::value || std::is_same<T, std::float64_t>::value
#endif #endif
> { > {
}; };
template <typename T>
using equiv_uint_t = typename std::conditional<
sizeof(T) == 1, uint8_t,
typename std::conditional<
sizeof(T) == 2, uint16_t,
typename std::conditional<sizeof(T) == 4, uint32_t,
uint64_t>::type>::type>::type;
template <typename T> struct is_supported_integer_type : std::is_integral<T> {}; template <typename T> struct is_supported_integer_type : std::is_integral<T> {};
template <typename UC> template <typename UC>
@ -270,7 +280,9 @@ fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
template <typename T> struct span { template <typename T> struct span {
T const *ptr; T const *ptr;
size_t length; size_t length;
constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {}
constexpr span() : ptr(nullptr), length(0) {} constexpr span() : ptr(nullptr), length(0) {}
constexpr size_t len() const noexcept { return length; } constexpr size_t len() const noexcept { return length; }
@ -284,7 +296,9 @@ template <typename T> struct span {
struct value128 { struct value128 {
uint64_t low; uint64_t low;
uint64_t high; uint64_t high;
constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
constexpr value128() : low(0), high(0) {} constexpr value128() : low(0), high(0) {}
}; };
@ -400,9 +414,11 @@ struct adjusted_mantissa {
uint64_t mantissa{0}; uint64_t mantissa{0};
int32_t power2{0}; // a negative value indicates an invalid result int32_t power2{0}; // a negative value indicates an invalid result
adjusted_mantissa() = default; adjusted_mantissa() = default;
constexpr bool operator==(adjusted_mantissa const &o) const { constexpr bool operator==(adjusted_mantissa const &o) const {
return mantissa == o.mantissa && power2 == o.power2; return mantissa == o.mantissa && power2 == o.power2;
} }
constexpr bool operator!=(adjusted_mantissa const &o) const { constexpr bool operator!=(adjusted_mantissa const &o) const {
return mantissa != o.mantissa || power2 != o.power2; return mantissa != o.mantissa || power2 != o.power2;
} }
@ -417,8 +433,7 @@ constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5;
template <typename T, typename U = void> struct binary_format_lookup_tables; template <typename T, typename U = void> struct binary_format_lookup_tables;
template <typename T> struct binary_format : binary_format_lookup_tables<T> { template <typename T> struct binary_format : binary_format_lookup_tables<T> {
using equiv_uint = using equiv_uint = equiv_uint_t<T>;
typename std::conditional<sizeof(T) == 4, uint32_t, uint64_t>::type;
static inline constexpr int mantissa_explicit_bits(); static inline constexpr int mantissa_explicit_bits();
static inline constexpr int minimum_exponent(); static inline constexpr int minimum_exponent();
@ -546,6 +561,7 @@ template <>
inline constexpr int binary_format<double>::mantissa_explicit_bits() { inline constexpr int binary_format<double>::mantissa_explicit_bits() {
return 52; return 52;
} }
template <> template <>
inline constexpr int binary_format<float>::mantissa_explicit_bits() { inline constexpr int binary_format<float>::mantissa_explicit_bits() {
return 23; return 23;
@ -574,6 +590,7 @@ inline constexpr int binary_format<float>::min_exponent_round_to_even() {
template <> inline constexpr int binary_format<double>::minimum_exponent() { template <> inline constexpr int binary_format<double>::minimum_exponent() {
return -1023; return -1023;
} }
template <> inline constexpr int binary_format<float>::minimum_exponent() { template <> inline constexpr int binary_format<float>::minimum_exponent() {
return -127; return -127;
} }
@ -581,6 +598,7 @@ template <> inline constexpr int binary_format<float>::minimum_exponent() {
template <> inline constexpr int binary_format<double>::infinite_power() { template <> inline constexpr int binary_format<double>::infinite_power() {
return 0x7FF; return 0x7FF;
} }
template <> inline constexpr int binary_format<float>::infinite_power() { template <> inline constexpr int binary_format<float>::infinite_power() {
return 0xFF; return 0xFF;
} }
@ -588,6 +606,7 @@ template <> inline constexpr int binary_format<float>::infinite_power() {
template <> inline constexpr int binary_format<double>::sign_index() { template <> inline constexpr int binary_format<double>::sign_index() {
return 63; return 63;
} }
template <> inline constexpr int binary_format<float>::sign_index() { template <> inline constexpr int binary_format<float>::sign_index() {
return 31; return 31;
} }
@ -596,6 +615,7 @@ template <>
inline constexpr int binary_format<double>::max_exponent_fast_path() { inline constexpr int binary_format<double>::max_exponent_fast_path() {
return 22; return 22;
} }
template <> template <>
inline constexpr int binary_format<float>::max_exponent_fast_path() { inline constexpr int binary_format<float>::max_exponent_fast_path() {
return 10; return 10;
@ -605,6 +625,7 @@ template <>
inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() { inline constexpr uint64_t binary_format<double>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits(); return uint64_t(2) << mantissa_explicit_bits();
} }
template <> template <>
inline constexpr uint64_t inline constexpr uint64_t
binary_format<double>::max_mantissa_fast_path(int64_t power) { binary_format<double>::max_mantissa_fast_path(int64_t power) {
@ -614,10 +635,12 @@ binary_format<double>::max_mantissa_fast_path(int64_t power) {
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)max_mantissa[0], max_mantissa[power]; return (void)max_mantissa[0], max_mantissa[power];
} }
template <> template <>
inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() { inline constexpr uint64_t binary_format<float>::max_mantissa_fast_path() {
return uint64_t(2) << mantissa_explicit_bits(); return uint64_t(2) << mantissa_explicit_bits();
} }
template <> template <>
inline constexpr uint64_t inline constexpr uint64_t
binary_format<float>::max_mantissa_fast_path(int64_t power) { binary_format<float>::max_mantissa_fast_path(int64_t power) {
@ -634,6 +657,7 @@ binary_format<double>::exact_power_of_ten(int64_t power) {
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
return (void)powers_of_ten[0], powers_of_ten[power]; return (void)powers_of_ten[0], powers_of_ten[power];
} }
template <> template <>
inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) { inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
// Work around clang bug https://godbolt.org/z/zedh7rrhc // Work around clang bug https://godbolt.org/z/zedh7rrhc
@ -643,6 +667,7 @@ inline constexpr float binary_format<float>::exact_power_of_ten(int64_t power) {
template <> inline constexpr int binary_format<double>::largest_power_of_ten() { template <> inline constexpr int binary_format<double>::largest_power_of_ten() {
return 308; return 308;
} }
template <> inline constexpr int binary_format<float>::largest_power_of_ten() { template <> inline constexpr int binary_format<float>::largest_power_of_ten() {
return 38; return 38;
} }
@ -651,6 +676,7 @@ template <>
inline constexpr int binary_format<double>::smallest_power_of_ten() { inline constexpr int binary_format<double>::smallest_power_of_ten() {
return -342; return -342;
} }
template <> inline constexpr int binary_format<float>::smallest_power_of_ten() { template <> inline constexpr int binary_format<float>::smallest_power_of_ten() {
return -64; return -64;
} }
@ -658,6 +684,7 @@ template <> inline constexpr int binary_format<float>::smallest_power_of_ten() {
template <> inline constexpr size_t binary_format<double>::max_digits() { template <> inline constexpr size_t binary_format<double>::max_digits() {
return 769; return 769;
} }
template <> inline constexpr size_t binary_format<float>::max_digits() { template <> inline constexpr size_t binary_format<float>::max_digits() {
return 114; return 114;
} }
@ -667,6 +694,7 @@ inline constexpr binary_format<float>::equiv_uint
binary_format<float>::exponent_mask() { binary_format<float>::exponent_mask() {
return 0x7F800000; return 0x7F800000;
} }
template <> template <>
inline constexpr binary_format<double>::equiv_uint inline constexpr binary_format<double>::equiv_uint
binary_format<double>::exponent_mask() { binary_format<double>::exponent_mask() {
@ -678,6 +706,7 @@ inline constexpr binary_format<float>::equiv_uint
binary_format<float>::mantissa_mask() { binary_format<float>::mantissa_mask() {
return 0x007FFFFF; return 0x007FFFFF;
} }
template <> template <>
inline constexpr binary_format<double>::equiv_uint inline constexpr binary_format<double>::equiv_uint
binary_format<double>::mantissa_mask() { binary_format<double>::mantissa_mask() {
@ -689,6 +718,7 @@ inline constexpr binary_format<float>::equiv_uint
binary_format<float>::hidden_bit_mask() { binary_format<float>::hidden_bit_mask() {
return 0x00800000; return 0x00800000;
} }
template <> template <>
inline constexpr binary_format<double>::equiv_uint inline constexpr binary_format<double>::equiv_uint
binary_format<double>::hidden_bit_mask() { binary_format<double>::hidden_bit_mask() {
@ -698,11 +728,10 @@ binary_format<double>::hidden_bit_mask() {
template <typename T> template <typename T>
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
to_float(bool negative, adjusted_mantissa am, T &value) { to_float(bool negative, adjusted_mantissa am, T &value) {
using fastfloat_uint = typename binary_format<T>::equiv_uint; using equiv_uint = equiv_uint_t<T>;
fastfloat_uint word = (fastfloat_uint)am.mantissa; equiv_uint word = equiv_uint(am.mantissa);
word |= fastfloat_uint(am.power2) word |= equiv_uint(am.power2) << binary_format<T>::mantissa_explicit_bits();
<< binary_format<T>::mantissa_explicit_bits(); word |= equiv_uint(negative) << binary_format<T>::sign_index();
word |= fastfloat_uint(negative) << binary_format<T>::sign_index();
#if FASTFLOAT_HAS_BIT_CAST #if FASTFLOAT_HAS_BIT_CAST
value = std::bit_cast<T>(word); value = std::bit_cast<T>(word);
#else #else
@ -744,16 +773,21 @@ template <typename UC> static constexpr uint64_t int_cmp_zeros() {
uint64_t(UC('0')) << 16 | UC('0')) uint64_t(UC('0')) << 16 | UC('0'))
: (uint64_t(UC('0')) << 32 | UC('0')); : (uint64_t(UC('0')) << 32 | UC('0'));
} }
template <typename UC> static constexpr int int_cmp_len() { template <typename UC> static constexpr int int_cmp_len() {
return sizeof(uint64_t) / sizeof(UC); return sizeof(uint64_t) / sizeof(UC);
} }
template <typename UC> constexpr UC const *str_const_nan(); template <typename UC> constexpr UC const *str_const_nan();
template <> constexpr char const *str_const_nan<char>() { return "nan"; } template <> constexpr char const *str_const_nan<char>() { return "nan"; }
template <> constexpr wchar_t const *str_const_nan<wchar_t>() { return L"nan"; } template <> constexpr wchar_t const *str_const_nan<wchar_t>() { return L"nan"; }
template <> constexpr char16_t const *str_const_nan<char16_t>() { template <> constexpr char16_t const *str_const_nan<char16_t>() {
return u"nan"; return u"nan";
} }
template <> constexpr char32_t const *str_const_nan<char32_t>() { template <> constexpr char32_t const *str_const_nan<char32_t>() {
return U"nan"; return U"nan";
} }
@ -764,13 +798,17 @@ template <> constexpr char8_t const *str_const_nan<char8_t>() {
#endif #endif
template <typename UC> constexpr UC const *str_const_inf(); template <typename UC> constexpr UC const *str_const_inf();
template <> constexpr char const *str_const_inf<char>() { return "infinity"; } template <> constexpr char const *str_const_inf<char>() { return "infinity"; }
template <> constexpr wchar_t const *str_const_inf<wchar_t>() { template <> constexpr wchar_t const *str_const_inf<wchar_t>() {
return L"infinity"; return L"infinity";
} }
template <> constexpr char16_t const *str_const_inf<char16_t>() { template <> constexpr char16_t const *str_const_inf<char16_t>() {
return u"infinity"; return u"infinity";
} }
template <> constexpr char32_t const *str_const_inf<char32_t>() { template <> constexpr char32_t const *str_const_inf<char32_t>() {
return U"infinity"; return U"infinity";
} }
@ -845,6 +883,21 @@ fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) {
return int_luts<>::min_safe_u64[base - 2]; return int_luts<>::min_safe_u64[base - 2];
} }
static_assert(std::is_same<equiv_uint_t<double>, uint64_t>::value,
"equiv_uint should be uint64_t for double");
static_assert(std::is_same<equiv_uint_t<float>, uint32_t>::value,
"equiv_uint should be uint32_t for float");
#ifdef __STDCPP_FLOAT64_T__
static_assert(std::is_same<equiv_uint_t<std::float64_t>, uint64_t>::value,
"equiv_uint should be uint64_t for std::float64_t");
#endif
#ifdef __STDCPP_FLOAT32_T__
static_assert(std::is_same<equiv_uint_t<std::float32_t>, uint32_t>::value,
"equiv_uint should be uint32_t for std::float32_t");
#endif
constexpr chars_format operator~(chars_format rhs) noexcept { constexpr chars_format operator~(chars_format rhs) noexcept {
using int_type = std::underlying_type<chars_format>::type; using int_type = std::underlying_type<chars_format>::type;
return static_cast<chars_format>(~static_cast<int_type>(rhs)); return static_cast<chars_format>(~static_cast<int_type>(rhs));

View File

@ -10,6 +10,7 @@
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include <system_error> #include <system_error>
namespace fast_float { namespace fast_float {
namespace detail { namespace detail {
@ -145,7 +146,7 @@ template <typename T> struct from_chars_caller {
} }
}; };
#if __STDCPP_FLOAT32_T__ == 1 #ifdef __STDCPP_FLOAT32_T__
template <> struct from_chars_caller<std::float32_t> { template <> struct from_chars_caller<std::float32_t> {
template <typename UC> template <typename UC>
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC> FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
@ -162,7 +163,7 @@ template <> struct from_chars_caller<std::float32_t> {
}; };
#endif #endif
#if __STDCPP_FLOAT64_T__ == 1 #ifdef __STDCPP_FLOAT64_T__
template <> struct from_chars_caller<std::float64_t> { template <> struct from_chars_caller<std::float64_t> {
template <typename UC> template <typename UC>
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC> FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>

View File

@ -729,8 +729,7 @@ constexpr void check_basic_test_result(stringtype str, result_type result,
auto copysign = [](double x, double y) -> double { auto copysign = [](double x, double y) -> double {
#if FASTFLOAT_HAS_BIT_CAST #if FASTFLOAT_HAS_BIT_CAST
if (fast_float::cpp20_and_in_constexpr()) { if (fast_float::cpp20_and_in_constexpr()) {
using equiv_int = std::make_signed_t< using equiv_int = std::make_signed_t<fast_float::equiv_uint_t<double>>;
typename fast_float::binary_format<double>::equiv_uint>;
auto const i = std::bit_cast<equiv_int>(y); auto const i = std::bit_cast<equiv_int>(y);
if (i < 0) { if (i < 0) {
return -x; return -x;

View File

@ -1,2 +1,3 @@
#include "test.h" #include "test.h"
void foo() {} void foo() {}

View File

@ -1,2 +1,3 @@
#include "test.h" #include "test.h"
int main() { return 0; } int main() { return 0; }

View File

@ -14,6 +14,7 @@
// gcc. // gcc.
#include <locale> #include <locale>
#include <sstream> #include <sstream>
// workaround for CYGWIN // workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) { double cygwin_strtod_l(char const *start, char **end) {
double d; double d;
@ -31,6 +32,7 @@ double cygwin_strtod_l(char const *start, char **end) {
*end = const_cast<char *>(start) + nread; *end = const_cast<char *>(start) + nread;
return d; return d;
} }
float cygwin_strtof_l(char const *start, char **end) { float cygwin_strtof_l(char const *start, char **end) {
float d; float d;
std::stringstream ss; std::stringstream ss;
@ -164,6 +166,7 @@ inline void Assert(bool Assertion) {
} }
#endif #endif
} }
int main() { int main() {
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \ #if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__MINGW64__) || \
defined(sun) || defined(__sun) defined(sun) || defined(__sun)

View File

@ -12,7 +12,7 @@
int main() { int main() {
// Write some testcases for the parsing of floating point numbers in the // Write some testcases for the parsing of floating point numbers in the
// float32_t type. We use the from_chars function defined in this library. // float32_t type. We use the from_chars function defined in this library.
#if __STDCPP_FLOAT32_T__ #ifdef __STDCPP_FLOAT32_T__
std::vector<std::float32_t> const float32_test_expected{ std::vector<std::float32_t> const float32_test_expected{
123.456f, -78.9f, 0.0001f, 3.40282e+038f}; 123.456f, -78.9f, 0.0001f, 3.40282e+038f};
std::vector<std::string_view> const float32_test{"123.456", "-78.9", "0.0001", std::vector<std::string_view> const float32_test{"123.456", "-78.9", "0.0001",
@ -37,7 +37,7 @@ int main() {
std::cout << "No std::float32_t type available." << std::endl; std::cout << "No std::float32_t type available." << std::endl;
#endif #endif
#if __STDCPP_FLOAT64_T__ #ifdef __STDCPP_FLOAT64_T__
// Test cases for std::float64_t // Test cases for std::float64_t
std::vector<std::float64_t> const float64_test_expected{ std::vector<std::float64_t> const float64_test_expected{
1.23e4, -5.67e-8, 1.7976931348623157e+308, -1.7976931348623157e+308}; 1.23e4, -5.67e-8, 1.7976931348623157e+308, -1.7976931348623157e+308};

View File

@ -54,6 +54,7 @@ struct ExpectedResult {
double value; double value;
std::string junk_chars; std::string junk_chars;
}; };
struct AcceptedValue { struct AcceptedValue {
std::string input; std::string input;
ExpectedResult expected; ExpectedResult expected;
@ -63,6 +64,7 @@ struct RejectReason {
fast_float::parse_error error; fast_float::parse_error error;
intptr_t location_offset; intptr_t location_offset;
}; };
struct RejectedValue { struct RejectedValue {
std::string input; std::string input;
RejectReason reason; RejectReason reason;

View File

@ -15,6 +15,7 @@
// always use this fallback because we cannot rely on it behaving as normal // always use this fallback because we cannot rely on it behaving as normal
// gcc. // gcc.
#include <locale> #include <locale>
// workaround for CYGWIN // workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) { double cygwin_strtod_l(char const *start, char **end) {
double d; double d;
@ -32,6 +33,7 @@ double cygwin_strtod_l(char const *start, char **end) {
*end = const_cast<char *>(start) + nread; *end = const_cast<char *>(start) + nread;
return d; return d;
} }
float cygwin_strtof_l(char const *start, char **end) { float cygwin_strtof_l(char const *start, char **end) {
float d; float d;
std::stringstream ss; std::stringstream ss;

View File

@ -14,6 +14,7 @@
// gcc. // gcc.
#include <locale> #include <locale>
#include <sstream> #include <sstream>
// workaround for CYGWIN // workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) { double cygwin_strtod_l(char const *start, char **end) {
double d; double d;
@ -31,6 +32,7 @@ double cygwin_strtod_l(char const *start, char **end) {
*end = const_cast<char *>(start) + nread; *end = const_cast<char *>(start) + nread;
return d; return d;
} }
float cygwin_strtof_l(char const *start, char **end) { float cygwin_strtof_l(char const *start, char **end) {
float d; float d;
std::stringstream ss; std::stringstream ss;
@ -53,6 +55,7 @@ class RandomEngine {
public: public:
RandomEngine() = delete; RandomEngine() = delete;
RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){};
uint64_t next() { uint64_t next() {
// Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
// Inspired from // Inspired from
@ -65,9 +68,13 @@ public:
uint64_t m2 = (tmp.high) ^ tmp.low; uint64_t m2 = (tmp.high) ^ tmp.low;
return m2; return m2;
} }
bool next_bool() { return (next() & 1) == 1; } bool next_bool() { return (next() & 1) == 1; }
int next_int() { return static_cast<int>(next()); } int next_int() { return static_cast<int>(next()); }
char next_char() { return static_cast<char>(next()); } char next_char() { return static_cast<char>(next()); }
double next_double() { return static_cast<double>(next()); } double next_double() { return static_cast<double>(next()); }
int next_ranged_int(int min, int max) { // min and max are included int next_ranged_int(int min, int max) { // min and max are included
@ -90,6 +97,7 @@ public:
} }
return int(m.high) + min; return int(m.high) + min;
} }
int next_digit() { return next_ranged_int(0, 9); } int next_digit() { return next_ranged_int(0, 9); }
private: private:

View File

@ -14,6 +14,7 @@
// gcc. // gcc.
#include <locale> #include <locale>
#include <sstream> #include <sstream>
// workaround for CYGWIN // workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) { double cygwin_strtod_l(char const *start, char **end) {
double d; double d;
@ -31,6 +32,7 @@ double cygwin_strtod_l(char const *start, char **end) {
*end = const_cast<char *>(start) + nread; *end = const_cast<char *>(start) + nread;
return d; return d;
} }
float cygwin_strtof_l(char const *start, char **end) { float cygwin_strtof_l(char const *start, char **end) {
float d; float d;
std::stringstream ss; std::stringstream ss;
@ -53,6 +55,7 @@ class RandomEngine {
public: public:
RandomEngine() = delete; RandomEngine() = delete;
RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){}; RandomEngine(uint64_t new_seed) : wyhash64_x_(new_seed){};
uint64_t next() { uint64_t next() {
// Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h // Adapted from https://github.com/wangyi-fudan/wyhash/blob/master/wyhash.h
// Inspired from // Inspired from
@ -65,9 +68,13 @@ public:
uint64_t m2 = (tmp.high) ^ tmp.low; uint64_t m2 = (tmp.high) ^ tmp.low;
return m2; return m2;
} }
bool next_bool() { return (next() & 1) == 1; } bool next_bool() { return (next() & 1) == 1; }
int next_int() { return static_cast<int>(next()); } int next_int() { return static_cast<int>(next()); }
char next_char() { return static_cast<char>(next()); } char next_char() { return static_cast<char>(next()); }
double next_double() { return static_cast<double>(next()); } double next_double() { return static_cast<double>(next()); }
int next_ranged_int(int min, int max) { // min and max are included int next_ranged_int(int min, int max) { // min and max are included
@ -90,6 +97,7 @@ public:
} }
return int(m.high) + min; return int(m.high) + min;
} }
int next_digit() { return next_ranged_int(0, 9); } int next_digit() { return next_ranged_int(0, 9); }
private: private:

View File

@ -16,6 +16,7 @@
// gcc. // gcc.
#include <locale> #include <locale>
#include <sstream> #include <sstream>
// workaround for CYGWIN // workaround for CYGWIN
double cygwin_strtod_l(char const *start, char **end) { double cygwin_strtod_l(char const *start, char **end) {
double d; double d;
@ -33,6 +34,7 @@ double cygwin_strtod_l(char const *start, char **end) {
*end = const_cast<char *>(start) + nread; *end = const_cast<char *>(start) + nread;
return d; return d;
} }
float cygwin_strtof_l(char const *start, char **end) { float cygwin_strtof_l(char const *start, char **end) {
float d; float d;
std::stringstream ss; std::stringstream ss;