mirror of
https://github.com/fastfloat/fast_float.git
synced 2025-12-07 09:16:50 +08:00
* Added an option disallow_leading_sign and stronger constexpr / consteval, also significantly reduce register pressure by reducing copy of constant data.
This commit is contained in:
parent
3c5b166f6c
commit
63f6abebdf
@ -202,7 +202,7 @@ template <typename UC>
|
||||
template <typename UC, FASTFLOAT_ENABLE_IF(!has_simd_opt<UC>()) = 0>
|
||||
#endif
|
||||
// dummy for compile
|
||||
bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) {
|
||||
FASTFLOAT_CONSTEVAL20 bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -269,7 +269,7 @@ using parsed_number_string = parsed_number_string_t<char>;
|
||||
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
|
||||
report_parse_error(UC const *p, parse_error error) {
|
||||
report_parse_error(UC const *p, parse_error error) noexcept {
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.lastmatch = p;
|
||||
@ -282,38 +282,41 @@ report_parse_error(UC const *p, parse_error error) {
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t<UC>
|
||||
parse_number_string(UC const *p, UC const *pend,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
UC const decimal_point = options.decimal_point;
|
||||
const parse_options_t<UC> options) noexcept {
|
||||
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.too_many_digits = false;
|
||||
// assume p < pend, so dereference without checks;
|
||||
answer.negative = (*p == UC('-'));
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*p == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) &&
|
||||
!uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) {
|
||||
++p;
|
||||
if (p == pend) {
|
||||
return report_parse_error<UC>(
|
||||
p, parse_error::missing_integer_or_dot_after_sign);
|
||||
}
|
||||
if (uint64_t(fmt & detail::basic_json_fmt)) {
|
||||
if (!is_integer(*p)) { // a sign must be followed by an integer
|
||||
return report_parse_error<UC>(p,
|
||||
parse_error::missing_integer_after_sign);
|
||||
}
|
||||
} else {
|
||||
if (!is_integer(*p) &&
|
||||
(*p !=
|
||||
decimal_point)) { // a sign must be followed by an integer or the dot
|
||||
[[assume(p < pend)]]; // assume p < pend, so dereference without checks;
|
||||
if (!uint64_t(options.format & chars_format::disallow_leading_sign)) {
|
||||
answer.negative = (*p == UC('-'));
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*p == UC('-')) ||
|
||||
(uint64_t(options.format & chars_format::allow_leading_plus) &&
|
||||
!uint64_t(options.format & detail::basic_json_fmt) && *p == UC('+'))) {
|
||||
++p;
|
||||
if (p == pend) {
|
||||
return report_parse_error<UC>(
|
||||
p, parse_error::missing_integer_or_dot_after_sign);
|
||||
}
|
||||
if (uint64_t(options.format & detail::basic_json_fmt)) {
|
||||
if (!is_integer(*p)) { // a sign must be followed by an integer
|
||||
return report_parse_error<UC>(p,
|
||||
parse_error::missing_integer_after_sign);
|
||||
}
|
||||
} else {
|
||||
if (!is_integer(*p) &&
|
||||
(*p !=
|
||||
options.decimal_point)) { // a sign must be followed by an integer or the dot
|
||||
return report_parse_error<UC>(
|
||||
p, parse_error::missing_integer_or_dot_after_sign);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
answer.negative = false;
|
||||
}
|
||||
|
||||
UC const *const start_digits = p;
|
||||
|
||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||
@ -329,7 +332,7 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
UC const *const end_of_integer_part = p;
|
||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
||||
answer.integer = span<UC const>(start_digits, size_t(digit_count));
|
||||
if (uint64_t(fmt & detail::basic_json_fmt)) {
|
||||
if (uint64_t(options.format & detail::basic_json_fmt)) {
|
||||
// at least 1 digit in integer part, without leading zeros
|
||||
if (digit_count == 0) {
|
||||
return report_parse_error<UC>(p, parse_error::no_digits_in_integer_part);
|
||||
@ -341,7 +344,7 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
}
|
||||
|
||||
int64_t exponent = 0;
|
||||
bool const has_decimal_point = (p != pend) && (*p == decimal_point);
|
||||
bool const has_decimal_point = (p != pend) && (*p == options.decimal_point);
|
||||
if (has_decimal_point) {
|
||||
++p;
|
||||
UC const *before = p;
|
||||
@ -358,7 +361,7 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
answer.fraction = span<UC const>(before, size_t(p - before));
|
||||
digit_count -= exponent;
|
||||
}
|
||||
if (uint64_t(fmt & detail::basic_json_fmt)) {
|
||||
if (uint64_t(options.format & detail::basic_json_fmt)) {
|
||||
// at least 1 digit in fractional part
|
||||
if (has_decimal_point && exponent == 0) {
|
||||
return report_parse_error<UC>(p,
|
||||
@ -369,9 +372,9 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
return report_parse_error<UC>(p, parse_error::no_digits_in_mantissa);
|
||||
}
|
||||
int64_t exp_number = 0; // explicit exponential part
|
||||
if ((uint64_t(fmt & chars_format::scientific) && (p != pend) &&
|
||||
if ((uint64_t(options.format & chars_format::scientific) && (p != pend) &&
|
||||
((UC('e') == *p) || (UC('E') == *p))) ||
|
||||
(uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) &&
|
||||
(uint64_t(options.format & detail::basic_fortran_fmt) && (p != pend) &&
|
||||
((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) ||
|
||||
(UC('D') == *p)))) {
|
||||
UC const *location_of_e = p;
|
||||
@ -389,7 +392,7 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
if (!uint64_t(fmt & chars_format::fixed)) {
|
||||
if (!uint64_t(options.format & chars_format::fixed)) {
|
||||
// The exponential part is invalid for scientific notation, so it must
|
||||
// be a trailing token for fixed notation. However, fixed notation is
|
||||
// disabled, so report a scientific notation error.
|
||||
@ -412,8 +415,8 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
}
|
||||
} else {
|
||||
// If it scientific and not fixed, we have to bail out.
|
||||
if (uint64_t(fmt & chars_format::scientific) &&
|
||||
!uint64_t(fmt & chars_format::fixed)) {
|
||||
if (uint64_t(options.format & chars_format::scientific) &&
|
||||
!uint64_t(options.format & chars_format::fixed)) {
|
||||
return report_parse_error<UC>(p, parse_error::missing_exponential_part);
|
||||
}
|
||||
}
|
||||
@ -431,7 +434,8 @@ parse_number_string(UC const *p, UC const *pend,
|
||||
// We need to be mindful of the case where we only have zeroes...
|
||||
// E.g., 0.000000000...000.
|
||||
UC const *start = start_digits;
|
||||
while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
|
||||
while ((start != pend) && (*start == UC('0') ||
|
||||
*start == options.decimal_point)) {
|
||||
if (*start == UC('0')) {
|
||||
digit_count--;
|
||||
}
|
||||
@ -474,29 +478,32 @@ template <typename T, typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
parse_int_string(UC const *p, UC const *pend, T &value,
|
||||
parse_options_t<UC> options) {
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
int const base = options.base;
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
|
||||
UC const *const first = p;
|
||||
|
||||
bool const negative = (*p == UC('-'));
|
||||
bool negative;
|
||||
if (!uint64_t(options.fmt & chars_format::disallow_leading_sign)) {
|
||||
negative = (*p == UC('-'));
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4127)
|
||||
#endif
|
||||
if (!std::is_signed<T>::value && negative) {
|
||||
if (!std::is_signed<T>::value && negative) {
|
||||
#ifdef FASTFLOAT_VISUAL_STUDIO
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
if ((*p == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
|
||||
++p;
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
if ((*p == UC('-')) ||
|
||||
(uint64_t(options.fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
|
||||
++p;
|
||||
}
|
||||
} else {
|
||||
negative = false;
|
||||
}
|
||||
|
||||
UC const *const start_num = p;
|
||||
@ -510,15 +517,15 @@ parse_int_string(UC const *p, UC const *pend, T &value,
|
||||
UC const *const start_digits = p;
|
||||
|
||||
uint64_t i = 0;
|
||||
if (base == 10) {
|
||||
if (options.base == 10) {
|
||||
loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible
|
||||
}
|
||||
while (p != pend) {
|
||||
uint8_t digit = ch_to_digit(*p);
|
||||
if (digit >= base) {
|
||||
const uint8_t digit = ch_to_digit(*p);
|
||||
if (digit >= options.base) {
|
||||
break;
|
||||
}
|
||||
i = uint64_t(base) * i + digit; // might overflow, check this later
|
||||
i = static_cast<uint64_t>(options.base) * i + digit; // might overflow, check this later
|
||||
p++;
|
||||
}
|
||||
|
||||
@ -539,14 +546,14 @@ parse_int_string(UC const *p, UC const *pend, T &value,
|
||||
answer.ptr = p;
|
||||
|
||||
// check u64 overflow
|
||||
size_t max_digits = max_digits_u64(base);
|
||||
size_t const max_digits = max_digits_u64(options.base);
|
||||
if (digit_count > max_digits) {
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
return answer;
|
||||
}
|
||||
// this check can be eliminated for all other types, but they will all require
|
||||
// a max_digits(base) equivalent
|
||||
if (digit_count == max_digits && i < min_safe_u64(base)) {
|
||||
if (digit_count == max_digits && i < min_safe_u64(options.base)) {
|
||||
answer.ec = std::errc::result_out_of_range;
|
||||
return answer;
|
||||
}
|
||||
|
||||
@ -42,14 +42,14 @@ template <uint16_t size> struct stackvec {
|
||||
// we never need more than 150 limbs
|
||||
uint16_t length{0};
|
||||
|
||||
stackvec() = default;
|
||||
FASTFLOAT_CONSTEXPR20 stackvec() noexcept = default;
|
||||
stackvec(stackvec const &) = delete;
|
||||
stackvec &operator=(stackvec const &) = delete;
|
||||
stackvec(stackvec &&) = delete;
|
||||
stackvec &operator=(stackvec &&other) = delete;
|
||||
|
||||
// create stack vector from existing limb span.
|
||||
FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) {
|
||||
FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) noexcept {
|
||||
FASTFLOAT_ASSERT(try_extend(s));
|
||||
}
|
||||
|
||||
@ -435,14 +435,14 @@ struct bigint : pow5_tables<> {
|
||||
// storage of the limbs, in little-endian order.
|
||||
stackvec<bigint_limbs> vec;
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bigint() : vec() {}
|
||||
FASTFLOAT_CONSTEXPR20 bigint() noexcept : vec() {}
|
||||
|
||||
bigint(bigint const &) = delete;
|
||||
bigint &operator=(bigint const &) = delete;
|
||||
bigint(bigint &&) = delete;
|
||||
bigint &operator=(bigint &&other) = delete;
|
||||
|
||||
FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() {
|
||||
FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) noexcept : vec() {
|
||||
#ifdef FASTFLOAT_64BIT_LIMB
|
||||
vec.push_unchecked(value);
|
||||
#else
|
||||
@ -517,8 +517,8 @@ struct bigint : pow5_tables<> {
|
||||
FASTFLOAT_DEBUG_ASSERT(n != 0);
|
||||
FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8);
|
||||
|
||||
size_t shl = n;
|
||||
size_t shr = limb_bits - shl;
|
||||
size_t const shl = n;
|
||||
size_t const shr = limb_bits - shl;
|
||||
limb prev = 0;
|
||||
for (size_t index = 0; index < vec.len(); index++) {
|
||||
limb xi = vec[index];
|
||||
@ -556,8 +556,8 @@ struct bigint : pow5_tables<> {
|
||||
|
||||
// move the limbs left by `n` bits.
|
||||
FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept {
|
||||
size_t rem = n % limb_bits;
|
||||
size_t div = n / limb_bits;
|
||||
size_t const rem = n % limb_bits;
|
||||
size_t const div = n / limb_bits;
|
||||
if (rem != 0) {
|
||||
FASTFLOAT_TRY(shl_bits(rem));
|
||||
}
|
||||
@ -598,8 +598,8 @@ struct bigint : pow5_tables<> {
|
||||
// multiply as if by 5 raised to a power.
|
||||
FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept {
|
||||
// multiply by a power of 5
|
||||
size_t large_length = sizeof(large_power_of_5) / sizeof(limb);
|
||||
limb_span large = limb_span(large_power_of_5, large_length);
|
||||
size_t const large_length = sizeof(large_power_of_5) / sizeof(limb);
|
||||
limb_span const large = limb_span(large_power_of_5, large_length);
|
||||
while (exp >= large_step) {
|
||||
FASTFLOAT_TRY(large_mul(vec, large));
|
||||
exp -= large_step;
|
||||
|
||||
@ -32,9 +32,11 @@
|
||||
defined(__cpp_lib_constexpr_algorithms) && \
|
||||
__cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/
|
||||
#define FASTFLOAT_CONSTEXPR20 constexpr
|
||||
#define FASTFLOAT_CONSTEVAL20 consteval
|
||||
#define FASTFLOAT_IS_CONSTEXPR 1
|
||||
#else
|
||||
#define FASTFLOAT_CONSTEXPR20
|
||||
#define FASTFLOAT_CONSTEVAL20
|
||||
#define FASTFLOAT_IS_CONSTEXPR 0
|
||||
#endif
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ namespace fast_float {
|
||||
//
|
||||
template <int bit_precision>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
|
||||
compute_product_approximation(int64_t q, uint64_t w) {
|
||||
compute_product_approximation(int64_t q, uint64_t w) noexcept {
|
||||
int const 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,
|
||||
|
||||
@ -40,7 +40,7 @@ constexpr static uint64_t powers_of_ten_uint64[] = {1UL,
|
||||
// to slow down performance for faster algorithms, and this is still fast.
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t
|
||||
scientific_exponent(parsed_number_string_t<UC> &num) noexcept {
|
||||
scientific_exponent(const parsed_number_string_t<UC> &num) noexcept {
|
||||
uint64_t mantissa = num.mantissa;
|
||||
int32_t exponent = int32_t(num.exponent);
|
||||
while (mantissa >= 10000) {
|
||||
@ -258,7 +258,7 @@ round_up_bigint(bigint &big, size_t &count) noexcept {
|
||||
// parse the significant digits into a big integer
|
||||
template <typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20 void
|
||||
parse_mantissa(bigint &result, parsed_number_string_t<UC> &num,
|
||||
parse_mantissa(bigint &result, const parsed_number_string_t<UC> &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
|
||||
@ -370,9 +370,9 @@ positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept {
|
||||
// are of the same magnitude.
|
||||
template <typename T>
|
||||
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
|
||||
bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept {
|
||||
bigint &bigmant, const adjusted_mantissa& am, const int32_t exponent) noexcept {
|
||||
bigint &real_digits = bigmant;
|
||||
int32_t real_exp = exponent;
|
||||
const int32_t &real_exp = exponent;
|
||||
|
||||
// get the value of `b`, rounded down, and get a bigint representation of b+h
|
||||
adjusted_mantissa am_b = am;
|
||||
@ -434,7 +434,7 @@ inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp(
|
||||
// of both, and use that to direct rounding.
|
||||
template <typename T, typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa
|
||||
digit_comp(parsed_number_string_t<UC> &num, adjusted_mantissa am) noexcept {
|
||||
digit_comp(const parsed_number_string_t<UC> &num, adjusted_mantissa& am) noexcept {
|
||||
// remove the invalid exponent bias
|
||||
am.power2 -= invalid_am_bias;
|
||||
|
||||
|
||||
@ -53,6 +53,7 @@ enum class chars_format : uint64_t {
|
||||
general = fixed | scientific,
|
||||
allow_leading_plus = 1 << 7,
|
||||
skip_white_space = 1 << 8,
|
||||
disallow_leading_sign = 1 << 9,
|
||||
};
|
||||
|
||||
template <typename UC> struct from_chars_result_t {
|
||||
@ -63,16 +64,24 @@ template <typename UC> struct from_chars_result_t {
|
||||
using from_chars_result = from_chars_result_t<char>;
|
||||
|
||||
template <typename UC> struct parse_options_t {
|
||||
constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
|
||||
UC dot = UC('.'), int b = 10)
|
||||
FASTFLOAT_CONSTEXPR20 explicit parse_options_t(chars_format fmt = chars_format::general,
|
||||
UC dot = UC('.'), unsigned char b = 10) noexcept
|
||||
: format(fmt), decimal_point(dot), base(b) {}
|
||||
|
||||
/** Which number formats are accepted */
|
||||
chars_format format;
|
||||
const chars_format format
|
||||
// adjust for deprecated feature macros
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS
|
||||
| chars_format::allow_leading_plus
|
||||
#endif
|
||||
#ifdef FASTFLOAT_SKIP_WHITE_SPACE
|
||||
| chars_format::skip_white_space
|
||||
#endif
|
||||
;
|
||||
/** The character used as decimal point */
|
||||
UC decimal_point;
|
||||
const UC decimal_point;
|
||||
/** The base used for integers */
|
||||
int base;
|
||||
const unsigned char base;
|
||||
};
|
||||
|
||||
using parse_options = parse_options_t<char>;
|
||||
@ -212,7 +221,7 @@ using parse_options = parse_options_t<char>;
|
||||
|
||||
namespace fast_float {
|
||||
|
||||
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
||||
fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() noexcept {
|
||||
#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED
|
||||
return std::is_constant_evaluated();
|
||||
#else
|
||||
@ -265,7 +274,7 @@ struct is_supported_char_type
|
||||
template <typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR14 bool
|
||||
fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase,
|
||||
size_t length) {
|
||||
size_t length) noexcept {
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
UC const actual = actual_mixedcase[i];
|
||||
if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) {
|
||||
@ -300,9 +309,9 @@ struct value128 {
|
||||
uint64_t low;
|
||||
uint64_t high;
|
||||
|
||||
constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {}
|
||||
constexpr value128(uint64_t _low, uint64_t _high) noexcept : low(_low), high(_high) {}
|
||||
|
||||
constexpr value128() : low(0), high(0) {}
|
||||
constexpr value128() noexcept : low(0), high(0) {}
|
||||
};
|
||||
|
||||
/* Helper C++14 constexpr generic implementation of leading_zeroes */
|
||||
@ -336,8 +345,9 @@ leading_zeroes_generic(uint64_t input_num, int last_bit = 0) {
|
||||
|
||||
/* result might be undefined when input_num is zero */
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int
|
||||
leading_zeroes(uint64_t input_num) {
|
||||
leading_zeroes(uint64_t input_num) noexcept {
|
||||
assert(input_num > 0);
|
||||
[[assume(input_num > 0)]];
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
return leading_zeroes_generic(input_num);
|
||||
}
|
||||
@ -357,12 +367,12 @@ leading_zeroes(uint64_t input_num) {
|
||||
}
|
||||
|
||||
// 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) noexcept {
|
||||
return x * (uint64_t)y;
|
||||
}
|
||||
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t
|
||||
umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) {
|
||||
umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) noexcept {
|
||||
uint64_t ad = emulu((uint32_t)(ab >> 32), (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));
|
||||
@ -388,7 +398,7 @@ fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab,
|
||||
|
||||
// compute 64-bit a*b
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128
|
||||
full_multiplication(uint64_t a, uint64_t b) {
|
||||
full_multiplication(uint64_t a, uint64_t b) noexcept {
|
||||
if (cpp20_and_in_constexpr()) {
|
||||
value128 answer;
|
||||
answer.low = umul128_generic(a, b, &answer.high);
|
||||
@ -416,13 +426,13 @@ full_multiplication(uint64_t a, uint64_t b) {
|
||||
struct adjusted_mantissa {
|
||||
uint64_t mantissa{0};
|
||||
int32_t power2{0}; // a negative value indicates an invalid result
|
||||
adjusted_mantissa() = default;
|
||||
adjusted_mantissa() noexcept = default;
|
||||
|
||||
constexpr bool operator==(adjusted_mantissa const &o) const {
|
||||
constexpr bool operator==(adjusted_mantissa const &o) const noexcept {
|
||||
return mantissa == o.mantissa && power2 == o.power2;
|
||||
}
|
||||
|
||||
constexpr bool operator!=(adjusted_mantissa const &o) const {
|
||||
constexpr bool operator!=(adjusted_mantissa const &o) const noexcept {
|
||||
return mantissa != o.mantissa || power2 != o.power2;
|
||||
}
|
||||
};
|
||||
@ -979,7 +989,7 @@ binary_format<double>::hidden_bit_mask() {
|
||||
|
||||
template <typename T>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void
|
||||
to_float(bool negative, adjusted_mantissa am, T &value) {
|
||||
to_float(const bool negative, const adjusted_mantissa am, T &value) noexcept {
|
||||
using equiv_uint = equiv_uint_t<T>;
|
||||
equiv_uint word = equiv_uint(am.mantissa);
|
||||
word = equiv_uint(word | equiv_uint(am.power2)
|
||||
@ -1221,20 +1231,6 @@ operator^=(chars_format &lhs, chars_format rhs) noexcept {
|
||||
return lhs = (lhs ^ rhs);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
// adjust for deprecated feature macros
|
||||
constexpr chars_format adjust_for_feature_macros(chars_format fmt) {
|
||||
return fmt
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS
|
||||
| chars_format::allow_leading_plus
|
||||
#endif
|
||||
#ifdef FASTFLOAT_SKIP_WHITE_SPACE
|
||||
| chars_format::skip_white_space
|
||||
#endif
|
||||
;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
} // namespace fast_float
|
||||
|
||||
#endif
|
||||
|
||||
@ -22,18 +22,26 @@ namespace detail {
|
||||
template <typename T, typename UC>
|
||||
from_chars_result_t<UC>
|
||||
FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last,
|
||||
T &value, chars_format fmt) noexcept {
|
||||
T &value, const chars_format fmt) noexcept {
|
||||
from_chars_result_t<UC> answer{};
|
||||
answer.ptr = first;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
// assume first < last, so dereference without checks;
|
||||
bool const minusSign = (*first == UC('-'));
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*first == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) &&
|
||||
(*first == UC('+')))) {
|
||||
++first;
|
||||
[[assume(first < last)]]; // so dereference without checks
|
||||
|
||||
bool minusSign;
|
||||
if (!uint64_t(fmt & chars_format::disallow_leading_sign)) {
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
minusSign = (*first == UC('-'));
|
||||
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if ((*first == UC('-')) ||
|
||||
(uint64_t(fmt & chars_format::allow_leading_plus) &&
|
||||
(*first == UC('+')))) {
|
||||
++first;
|
||||
}
|
||||
} else {
|
||||
minusSign = false;
|
||||
}
|
||||
|
||||
if (last - first >= 3) {
|
||||
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
|
||||
answer.ptr = (first += 3);
|
||||
@ -284,17 +292,15 @@ from_chars_advanced(parsed_number_string_t<UC> &pns, T &value) noexcept {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_float_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
const parse_options_t<UC> options) noexcept {
|
||||
|
||||
static_assert(is_supported_float_type<T>::value,
|
||||
"only some floating-point types are supported");
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
if (uint64_t(fmt & chars_format::skip_white_space)) {
|
||||
if (uint64_t(options.format & chars_format::skip_white_space)) {
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
first++;
|
||||
}
|
||||
@ -307,12 +313,12 @@ from_chars_float_advanced(UC const *first, UC const *last, T &value,
|
||||
parsed_number_string_t<UC> pns =
|
||||
parse_number_string<UC>(first, last, options);
|
||||
if (!pns.valid) {
|
||||
if (uint64_t(fmt & chars_format::no_infnan)) {
|
||||
if (uint64_t(options.format & chars_format::no_infnan)) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
} else {
|
||||
return detail::parse_infnan(first, last, value, fmt);
|
||||
return detail::parse_infnan(first, last, value, options.format);
|
||||
}
|
||||
}
|
||||
|
||||
@ -344,16 +350,13 @@ from_chars_int_advanced(UC const *first, UC const *last, T &value,
|
||||
static_assert(is_supported_char_type<UC>::value,
|
||||
"only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
chars_format const fmt = detail::adjust_for_feature_macros(options.format);
|
||||
int const base = options.base;
|
||||
|
||||
from_chars_result_t<UC> answer;
|
||||
if (uint64_t(fmt & chars_format::skip_white_space)) {
|
||||
if (uint64_t(options.format & chars_format::skip_white_space)) {
|
||||
while ((first != last) && fast_float::is_space(*first)) {
|
||||
first++;
|
||||
}
|
||||
}
|
||||
if (first == last || base < 2 || base > 36) {
|
||||
if (first == last || options.base < 2 || options.base > 36) {
|
||||
answer.ec = std::errc::invalid_argument;
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
@ -370,7 +373,7 @@ template <> struct from_chars_advanced_caller<1> {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
const parse_options_t<UC> options) noexcept {
|
||||
return from_chars_float_advanced(first, last, value, options);
|
||||
}
|
||||
};
|
||||
@ -379,7 +382,7 @@ template <> struct from_chars_advanced_caller<2> {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 static from_chars_result_t<UC>
|
||||
call(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
const parse_options_t<UC> options) noexcept {
|
||||
return from_chars_int_advanced(first, last, value, options);
|
||||
}
|
||||
};
|
||||
@ -387,7 +390,7 @@ template <> struct from_chars_advanced_caller<2> {
|
||||
template <typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
|
||||
from_chars_advanced(UC const *first, UC const *last, T &value,
|
||||
parse_options_t<UC> options) noexcept {
|
||||
const parse_options_t<UC> options) noexcept {
|
||||
return from_chars_advanced_caller<
|
||||
size_t(is_supported_float_type<T>::value) +
|
||||
2 * size_t(is_supported_integer_type<T>::value)>::call(first, last, value,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user