mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-06 16:56:57 +08:00
Merge pull request #101 from fastfloat/dlemire/const
C++ 20 support and tests
This commit is contained in:
commit
8c4405e76e
19
.github/workflows/ubuntu20-cxx20.yml
vendored
Normal file
19
.github/workflows/ubuntu20-cxx20.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Ubuntu 20.04 CI (C++20)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
ubuntu-build:
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Use cmake
|
||||||
|
run: |
|
||||||
|
mkdir build &&
|
||||||
|
cd build &&
|
||||||
|
cmake -DCMAKE_CXX_STANDARD=20 -DFASTFLOAT_TEST=ON -DCMAKE_INSTALL_PREFIX:PATH=destination .. &&
|
||||||
|
cmake --build . &&
|
||||||
|
ctest --output-on-failure &&
|
||||||
|
cmake --install .
|
||||||
2
.github/workflows/ubuntu20.yml
vendored
2
.github/workflows/ubuntu20.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Ubuntu 20.04 CI (GCC 9, 8)
|
name: Ubuntu 20.04 CI (GCC 9)
|
||||||
|
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.9)
|
|||||||
|
|
||||||
project(fast_float VERSION 2.0.0 LANGUAGES CXX)
|
project(fast_float VERSION 2.0.0 LANGUAGES CXX)
|
||||||
option(FASTFLOAT_TEST "Enable tests" OFF)
|
option(FASTFLOAT_TEST "Enable tests" OFF)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ standard to be used")
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
if(FASTFLOAT_TEST)
|
if(FASTFLOAT_TEST)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
|
|||||||
@ -7,15 +7,24 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
|
|
||||||
|
#if defined __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#if defined(__cpp_lib_bit_cast)
|
||||||
|
#include <bit>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "float_common.h"
|
#include "float_common.h"
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
|
|
||||||
// Next function can be micro-optimized, but compilers are entirely
|
// Next function can be micro-optimized, but compilers are entirely
|
||||||
// able to optimize it well.
|
// able to optimize it well.
|
||||||
fastfloat_really_inline bool is_integer(char c) noexcept { return c >= '0' && c <= '9'; }
|
CXX20_CONSTEXPR fastfloat_really_inline bool is_integer(char c) noexcept { return c >= '0' && c <= '9'; }
|
||||||
|
|
||||||
fastfloat_really_inline uint64_t byteswap(uint64_t val) {
|
CXX20_CONSTEXPR fastfloat_really_inline uint64_t byteswap(uint64_t val) {
|
||||||
return (val & 0xFF00000000000000) >> 56
|
return (val & 0xFF00000000000000) >> 56
|
||||||
| (val & 0x00FF000000000000) >> 40
|
| (val & 0x00FF000000000000) >> 40
|
||||||
| (val & 0x0000FF0000000000) >> 24
|
| (val & 0x0000FF0000000000) >> 24
|
||||||
@ -26,9 +35,13 @@ fastfloat_really_inline uint64_t byteswap(uint64_t val) {
|
|||||||
| (val & 0x00000000000000FF) << 56;
|
| (val & 0x00000000000000FF) << 56;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline uint64_t read_u64(const char *chars) {
|
CXX20_CONSTEXPR fastfloat_really_inline uint64_t read_u64(const char *chars) {
|
||||||
uint64_t val;
|
uint64_t val;
|
||||||
|
#if defined(__cpp_lib_bit_cast)
|
||||||
|
val = std::bit_cast<uint64_t>(reinterpret_cast<const char (&)[8]>(chars));
|
||||||
|
#else
|
||||||
::memcpy(&val, chars, sizeof(uint64_t));
|
::memcpy(&val, chars, sizeof(uint64_t));
|
||||||
|
#endif
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
||||||
// Need to read as-if the number was in little-endian order.
|
// Need to read as-if the number was in little-endian order.
|
||||||
val = byteswap(val);
|
val = byteswap(val);
|
||||||
@ -36,16 +49,26 @@ fastfloat_really_inline uint64_t read_u64(const char *chars) {
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {
|
CXX20_CONSTEXPR fastfloat_really_inline void write_u64(uint8_t *chars, uint64_t val) {
|
||||||
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
#if FASTFLOAT_IS_BIG_ENDIAN == 1
|
||||||
// Need to read as-if the number was in little-endian order.
|
// Need to read as-if the number was in little-endian order.
|
||||||
val = byteswap(val);
|
val = byteswap(val);
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(__cpp_lib_bit_cast)
|
||||||
|
if (std::is_constant_evaluated()) {
|
||||||
|
char (&dst)[8] = reinterpret_cast<char (&)[8]>(chars);
|
||||||
|
const char (&src)[8] = reinterpret_cast<const char (&)[8]>(val);
|
||||||
|
std::copy(std::begin(src), std::end(src), std::begin(dst));
|
||||||
|
} else {
|
||||||
|
::memcpy(chars, &val, sizeof(uint64_t));
|
||||||
|
}
|
||||||
|
#else
|
||||||
::memcpy(chars, &val, sizeof(uint64_t));
|
::memcpy(chars, &val, sizeof(uint64_t));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// credit @aqrit
|
// credit @aqrit
|
||||||
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
CXX20_CONSTEXPR fastfloat_really_inline uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
||||||
const uint64_t mask = 0x000000FF000000FF;
|
const uint64_t mask = 0x000000FF000000FF;
|
||||||
const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
const uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
|
||||||
const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
const uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
|
||||||
@ -55,17 +78,17 @@ fastfloat_really_inline uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
|||||||
return uint32_t(val);
|
return uint32_t(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
CXX20_CONSTEXPR fastfloat_really_inline uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
|
||||||
return parse_eight_digits_unrolled(read_u64(chars));
|
return parse_eight_digits_unrolled(read_u64(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
// credit @aqrit
|
// credit @aqrit
|
||||||
fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
CXX20_CONSTEXPR fastfloat_really_inline bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
|
||||||
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
|
return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) &
|
||||||
0x8080808080808080));
|
0x8080808080808080));
|
||||||
}
|
}
|
||||||
|
|
||||||
fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
CXX20_CONSTEXPR fastfloat_really_inline bool is_made_of_eight_digits_fast(const char *chars) noexcept {
|
||||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
return is_made_of_eight_digits_fast(read_u64(chars));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +104,7 @@ struct parsed_number_string {
|
|||||||
|
|
||||||
// Assuming that you use no more than 19 digits, this will
|
// Assuming that you use no more than 19 digits, this will
|
||||||
// parse an ASCII string.
|
// parse an ASCII string.
|
||||||
fastfloat_really_inline
|
CXX20_CONSTEXPR fastfloat_really_inline
|
||||||
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
parsed_number_string parse_number_string(const char *p, const char *pend, parse_options options) noexcept {
|
||||||
const chars_format fmt = options.format;
|
const chars_format fmt = options.format;
|
||||||
const char decimal_point = options.decimal_point;
|
const char decimal_point = options.decimal_point;
|
||||||
@ -221,7 +244,7 @@ parsed_number_string parse_number_string(const char *p, const char *pend, parse_
|
|||||||
// This function could be optimized. In particular, we could stop after 19 digits
|
// This function could be optimized. In particular, we could stop after 19 digits
|
||||||
// and try to bail out. Furthermore, we should be able to recover the computed
|
// and try to bail out. Furthermore, we should be able to recover the computed
|
||||||
// exponent from the pass in parse_number_string.
|
// exponent from the pass in parse_number_string.
|
||||||
fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend, parse_options options) noexcept {
|
CXX20_CONSTEXPR fastfloat_really_inline decimal parse_decimal(const char *p, const char *pend, parse_options options) noexcept {
|
||||||
const char decimal_point = options.decimal_point;
|
const char decimal_point = options.decimal_point;
|
||||||
|
|
||||||
decimal answer;
|
decimal answer;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace fast_float {
|
|||||||
// low part corresponding to the least significant bits.
|
// low part corresponding to the least significant bits.
|
||||||
//
|
//
|
||||||
template <int bit_precision>
|
template <int bit_precision>
|
||||||
fastfloat_really_inline
|
CXX20_CONSTEXPR fastfloat_really_inline
|
||||||
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
value128 compute_product_approximation(int64_t q, uint64_t w) {
|
||||||
const int index = 2 * int(q - powers::smallest_power_of_five);
|
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
|
// For small values of q, e.g., q in [0,27], the answer is always exact because
|
||||||
@ -56,7 +56,7 @@ namespace detail {
|
|||||||
* where
|
* where
|
||||||
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
* p = log(5**-q)/log(2) = -q * log(5)/log(2)
|
||||||
*/
|
*/
|
||||||
fastfloat_really_inline int power(int q) noexcept {
|
constexpr fastfloat_really_inline int power(int q) noexcept {
|
||||||
return (((152170 + 65536) * q) >> 16) + 63;
|
return (((152170 + 65536) * q) >> 16) + 63;
|
||||||
}
|
}
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
@ -68,7 +68,7 @@ namespace detail {
|
|||||||
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
// return an adjusted_mantissa with a negative power of 2: the caller should recompute
|
||||||
// in such cases.
|
// in such cases.
|
||||||
template <typename binary>
|
template <typename binary>
|
||||||
fastfloat_really_inline
|
CXX20_CONSTEXPR fastfloat_really_inline
|
||||||
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
adjusted_mantissa compute_float(int64_t q, uint64_t w) noexcept {
|
||||||
adjusted_mantissa answer;
|
adjusted_mantissa answer;
|
||||||
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
if ((w == 0) || (q < binary::smallest_power_of_ten())) {
|
||||||
|
|||||||
@ -1,8 +1,23 @@
|
|||||||
#ifndef FASTFLOAT_FAST_FLOAT_H
|
#ifndef FASTFLOAT_FAST_FLOAT_H
|
||||||
#define FASTFLOAT_FAST_FLOAT_H
|
#define FASTFLOAT_FAST_FLOAT_H
|
||||||
|
|
||||||
|
|
||||||
#include <system_error>
|
#include <system_error>
|
||||||
|
|
||||||
|
#if !defined(CXX20_CONSTEXPR)
|
||||||
|
#define CXX20_CONSTEXPR
|
||||||
|
#if defined __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#if defined(__cpp_lib_bit_cast)
|
||||||
|
#undef CXX20_CONSTEXPR
|
||||||
|
#define CXX20_CONSTEXPR constexpr
|
||||||
|
#define HAS_CXX20_CONSTEXPR 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
enum chars_format {
|
enum chars_format {
|
||||||
scientific = 1<<0,
|
scientific = 1<<0,
|
||||||
@ -18,7 +33,7 @@ struct from_chars_result {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct parse_options {
|
struct parse_options {
|
||||||
explicit parse_options(chars_format fmt = chars_format::general,
|
constexpr explicit parse_options(chars_format fmt = chars_format::general,
|
||||||
char dot = '.')
|
char dot = '.')
|
||||||
: format(fmt), decimal_point(dot) {}
|
: format(fmt), decimal_point(dot) {}
|
||||||
|
|
||||||
@ -48,14 +63,14 @@ struct parse_options {
|
|||||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
CXX20_CONSTEXPR from_chars_result from_chars(const char *first, const char *last,
|
||||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
CXX20_CONSTEXPR from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||||
T &value, parse_options options) noexcept;
|
T &value, parse_options options) noexcept;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -73,10 +73,24 @@
|
|||||||
#define fastfloat_really_inline inline __attribute__((always_inline))
|
#define fastfloat_really_inline inline __attribute__((always_inline))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(CXX20_CONSTEXPR)
|
||||||
|
#define CXX20_CONSTEXPR
|
||||||
|
#if defined __has_include
|
||||||
|
#if __has_include(<version>)
|
||||||
|
#include <version>
|
||||||
|
#if defined(__cpp_lib_bit_cast)
|
||||||
|
#undef CXX20_CONSTEXPR
|
||||||
|
#define CXX20_CONSTEXPR constexpr
|
||||||
|
#define HAS_CXX20_CONSTEXPR 1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace fast_float {
|
namespace fast_float {
|
||||||
|
|
||||||
// Compares two ASCII strings in a case insensitive manner.
|
// Compares two ASCII strings in a case insensitive manner.
|
||||||
inline bool fastfloat_strncasecmp(const char *input1, const char *input2,
|
CXX20_CONSTEXPR inline bool fastfloat_strncasecmp(const char *input1, const char *input2,
|
||||||
size_t length) {
|
size_t length) {
|
||||||
char running_diff{0};
|
char running_diff{0};
|
||||||
for (size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
@ -103,7 +117,7 @@ struct value128 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* 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) {
|
CXX20_CONSTEXPR fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
|
||||||
assert(input_num > 0);
|
assert(input_num > 0);
|
||||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||||
#if defined(_M_X64) || defined(_M_ARM64)
|
#if defined(_M_X64) || defined(_M_ARM64)
|
||||||
@ -130,13 +144,13 @@ fastfloat_really_inline int leading_zeroes(uint64_t input_num) {
|
|||||||
#ifdef FASTFLOAT_32BIT
|
#ifdef FASTFLOAT_32BIT
|
||||||
|
|
||||||
// slow emulation routine for 32-bit
|
// slow emulation routine for 32-bit
|
||||||
fastfloat_really_inline uint64_t emulu(uint32_t x, uint32_t y) {
|
CXX20_CONSTEXPR fastfloat_really_inline 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
|
// slow emulation routine for 32-bit
|
||||||
#if !defined(__MINGW64__)
|
#if !defined(__MINGW64__)
|
||||||
fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
|
CXX20_CONSTEXPR fastfloat_really_inline uint64_t _umul128(uint64_t ab, uint64_t cd,
|
||||||
uint64_t *hi) {
|
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);
|
||||||
|
|||||||
@ -20,7 +20,7 @@ namespace detail {
|
|||||||
* strings a null-free and fixed.
|
* strings a null-free and fixed.
|
||||||
**/
|
**/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
|
CXX20_CONSTEXPR from_chars_result parse_infnan(const char *first, const char *last, T &value) noexcept {
|
||||||
from_chars_result answer;
|
from_chars_result answer;
|
||||||
answer.ptr = first;
|
answer.ptr = first;
|
||||||
answer.ec = std::errc(); // be optimistic
|
answer.ec = std::errc(); // be optimistic
|
||||||
@ -61,7 +61,7 @@ from_chars_result parse_infnan(const char *first, const char *last, T &value) n
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
|
CXX20_CONSTEXPR fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||||
uint64_t word = am.mantissa;
|
uint64_t word = am.mantissa;
|
||||||
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
word |= uint64_t(am.power2) << binary_format<T>::mantissa_explicit_bits();
|
||||||
word = negative
|
word = negative
|
||||||
@ -83,13 +83,13 @@ fastfloat_really_inline void to_float(bool negative, adjusted_mantissa am, T &va
|
|||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
from_chars_result from_chars(const char *first, const char *last,
|
CXX20_CONSTEXPR from_chars_result from_chars(const char *first, const char *last,
|
||||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||||
return from_chars_advanced(first, last, value, parse_options{fmt});
|
return from_chars_advanced(first, last, value, parse_options{fmt});
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
from_chars_result from_chars_advanced(const char *first, const char *last,
|
CXX20_CONSTEXPR from_chars_result from_chars_advanced(const char *first, const char *last,
|
||||||
T &value, parse_options options) noexcept {
|
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");
|
static_assert (std::is_same<T, double>::value || std::is_same<T, float>::value, "only float and double are supported");
|
||||||
|
|||||||
@ -22,7 +22,7 @@ namespace fast_float {
|
|||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
// remove all final zeroes
|
// remove all final zeroes
|
||||||
inline void trim(decimal &h) {
|
CXX20_CONSTEXPR inline void trim(decimal &h) {
|
||||||
while ((h.num_digits > 0) && (h.digits[h.num_digits - 1] == 0)) {
|
while ((h.num_digits > 0) && (h.digits[h.num_digits - 1] == 0)) {
|
||||||
h.num_digits--;
|
h.num_digits--;
|
||||||
}
|
}
|
||||||
@ -30,9 +30,9 @@ inline void trim(decimal &h) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t shift) {
|
CXX20_CONSTEXPR inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t shift) {
|
||||||
shift &= 63;
|
shift &= 63;
|
||||||
const static uint16_t number_of_digits_decimal_left_shift_table[65] = {
|
constexpr uint16_t number_of_digits_decimal_left_shift_table[65] = {
|
||||||
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
|
0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
|
||||||
0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
|
0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
|
||||||
0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
|
0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
|
||||||
@ -47,7 +47,7 @@ inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t s
|
|||||||
uint32_t num_new_digits = x_a >> 11;
|
uint32_t num_new_digits = x_a >> 11;
|
||||||
uint32_t pow5_a = 0x7FF & x_a;
|
uint32_t pow5_a = 0x7FF & x_a;
|
||||||
uint32_t pow5_b = 0x7FF & x_b;
|
uint32_t pow5_b = 0x7FF & x_b;
|
||||||
const static uint8_t
|
constexpr uint8_t
|
||||||
number_of_digits_decimal_left_shift_table_powers_of_5[0x051C] = {
|
number_of_digits_decimal_left_shift_table_powers_of_5[0x051C] = {
|
||||||
5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3,
|
5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3,
|
||||||
9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8,
|
9, 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8,
|
||||||
@ -123,7 +123,7 @@ inline uint32_t number_of_digits_decimal_left_shift(const decimal &h, uint32_t s
|
|||||||
return num_new_digits;
|
return num_new_digits;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t round(decimal &h) {
|
CXX20_CONSTEXPR inline uint64_t round(decimal &h) {
|
||||||
if ((h.num_digits == 0) || (h.decimal_point < 0)) {
|
if ((h.num_digits == 0) || (h.decimal_point < 0)) {
|
||||||
return 0;
|
return 0;
|
||||||
} else if (h.decimal_point > 18) {
|
} else if (h.decimal_point > 18) {
|
||||||
@ -150,7 +150,7 @@ inline uint64_t round(decimal &h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// computes h * 2^-shift
|
// computes h * 2^-shift
|
||||||
inline void decimal_left_shift(decimal &h, uint32_t shift) {
|
CXX20_CONSTEXPR inline void decimal_left_shift(decimal &h, uint32_t shift) {
|
||||||
if (h.num_digits == 0) {
|
if (h.num_digits == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -192,7 +192,7 @@ inline void decimal_left_shift(decimal &h, uint32_t shift) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// computes h * 2^shift
|
// computes h * 2^shift
|
||||||
inline void decimal_right_shift(decimal &h, uint32_t shift) {
|
CXX20_CONSTEXPR inline void decimal_right_shift(decimal &h, uint32_t shift) {
|
||||||
uint32_t read_index = 0;
|
uint32_t read_index = 0;
|
||||||
uint32_t write_index = 0;
|
uint32_t write_index = 0;
|
||||||
|
|
||||||
@ -241,7 +241,7 @@ inline void decimal_right_shift(decimal &h, uint32_t shift) {
|
|||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
template <typename binary>
|
template <typename binary>
|
||||||
adjusted_mantissa compute_float(decimal &d) {
|
CXX20_CONSTEXPR adjusted_mantissa compute_float(decimal &d) {
|
||||||
adjusted_mantissa answer;
|
adjusted_mantissa answer;
|
||||||
if (d.num_digits == 0) {
|
if (d.num_digits == 0) {
|
||||||
// should be zero
|
// should be zero
|
||||||
@ -271,9 +271,9 @@ adjusted_mantissa compute_float(decimal &d) {
|
|||||||
answer.mantissa = 0;
|
answer.mantissa = 0;
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
static const uint32_t max_shift = 60;
|
constexpr uint32_t max_shift = 60;
|
||||||
static const uint32_t num_powers = 19;
|
constexpr uint32_t num_powers = 19;
|
||||||
static const uint8_t decimal_powers[19] = {
|
constexpr uint8_t decimal_powers[19] = {
|
||||||
0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
|
0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
|
||||||
33, 36, 39, 43, 46, 49, 53, 56, 59, //
|
33, 36, 39, 43, 46, 49, 53, 56, 59, //
|
||||||
};
|
};
|
||||||
@ -351,7 +351,7 @@ adjusted_mantissa compute_float(decimal &d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename binary>
|
template <typename binary>
|
||||||
adjusted_mantissa parse_long_mantissa(const char *first, const char* last, parse_options options) {
|
CXX20_CONSTEXPR adjusted_mantissa parse_long_mantissa(const char *first, const char* last, parse_options options) {
|
||||||
decimal d = parse_decimal(first, last, options);
|
decimal d = parse_decimal(first, last, options);
|
||||||
return compute_float<binary>(d);
|
return compute_float<binary>(d);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,11 @@
|
|||||||
#define FASTFLOAT_ODDPLATFORM 1
|
#define FASTFLOAT_ODDPLATFORM 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAS_CXX20_CONSTEXPR
|
||||||
|
#include <bit>
|
||||||
|
#include <string_view>
|
||||||
|
#endif
|
||||||
|
|
||||||
// C++ 17 because it is otherwise annoying to browse all files in a directory.
|
// C++ 17 because it is otherwise annoying to browse all files in a directory.
|
||||||
// We also only run these tests on little endian systems.
|
// We also only run these tests on little endian systems.
|
||||||
#if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && !defined(FASTFLOAT_ODDPLATFORM)
|
#if (FASTFLOAT_CPLUSPLUS >= 201703L) && (FASTFLOAT_IS_BIG_ENDIAN == 0) && !defined(FASTFLOAT_ODDPLATFORM)
|
||||||
@ -101,6 +106,7 @@ bool check_file(std::string file_name) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_CASE("supplemental") {
|
TEST_CASE("supplemental") {
|
||||||
std::string path = SUPPLEMENTAL_TEST_DATA_DIR;
|
std::string path = SUPPLEMENTAL_TEST_DATA_DIR;
|
||||||
for (const auto & entry : std::filesystem::directory_iterator(path)) {
|
for (const auto & entry : std::filesystem::directory_iterator(path)) {
|
||||||
@ -109,6 +115,27 @@ TEST_CASE("supplemental") {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if HAS_CXX20_CONSTEXPR
|
||||||
|
|
||||||
|
constexpr double tryParse(std::string_view input)
|
||||||
|
{
|
||||||
|
double result{};
|
||||||
|
fast_float::from_chars_result parseResult = fast_float::from_chars(input.data(), input.data() + input.size(), result);
|
||||||
|
if (parseResult.ec != std::errc()) {
|
||||||
|
return std::numeric_limits<double>::quiet_NaN();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_assert(tryParse("1.0") == 1.0);
|
||||||
|
static_assert(tryParse("2.0") == 2.0);
|
||||||
|
static_assert(tryParse("3.14156") == 3.14156);
|
||||||
|
static_assert(tryParse("3.14156") != 3.1415600000001);
|
||||||
|
#if !defined(_MSVC_LANG)
|
||||||
|
static_assert(std::isnan(tryParse("hellothere"))); // technically isnan is not constexpr but GCC and clang allow it
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //#if HAS_CXX20_CONSTEXPR
|
||||||
|
|
||||||
TEST_CASE("leading_zeroes") {
|
TEST_CASE("leading_zeroes") {
|
||||||
constexpr const uint64_t bit = 1;
|
constexpr const uint64_t bit = 1;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user