* 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:
IRainman 2025-03-05 23:21:24 +03:00
parent 3c5b166f6c
commit 63f6abebdf
7 changed files with 128 additions and 120 deletions

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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

View File

@ -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,