mirror of
https://github.com/fastfloat/fast_float.git
synced 2026-01-01 03:12:18 +08:00
cosmetic changes
This commit is contained in:
parent
764341c1d9
commit
2bfbe4ca96
@ -12,9 +12,9 @@ namespace fast_float {
|
||||
|
||||
// Next function can be micro-optimized, but compilers are entirely
|
||||
// able to optimize it well.
|
||||
template <typename TCH>
|
||||
fastfloat_really_inline constexpr bool is_integer(TCH c) noexcept {
|
||||
return !(c > TCH('9') || c < TCH('0'));
|
||||
template <typename UC>
|
||||
fastfloat_really_inline constexpr bool is_integer(UC c) noexcept {
|
||||
return !(c > UC('9') || c < UC('0'));
|
||||
}
|
||||
|
||||
fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||
@ -27,10 +27,10 @@ fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) {
|
||||
| (val & 0x000000000000FF00) << 40
|
||||
| (val & 0x00000000000000FF) << 56;
|
||||
}
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint64_t read_u64(TCH const * chars) {
|
||||
if (cpp20_and_in_constexpr() || sizeof(TCH) > 1) {
|
||||
uint64_t read_u64(UC const * chars) {
|
||||
if (cpp20_and_in_constexpr() || sizeof(UC) > 1) {
|
||||
uint64_t val{};
|
||||
for(int i = 0; i < 8; ++i) {
|
||||
val |= uint64_t(char(*chars)) << (i * 8);
|
||||
@ -75,9 +75,9 @@ uint32_t parse_eight_digits_unrolled(uint64_t val) {
|
||||
val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
|
||||
return uint32_t(val);
|
||||
}
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
uint32_t parse_eight_digits_unrolled(TCH const * chars) noexcept {
|
||||
uint32_t parse_eight_digits_unrolled(UC const * chars) noexcept {
|
||||
return parse_eight_digits_unrolled(read_u64(chars));
|
||||
}
|
||||
|
||||
@ -87,42 +87,42 @@ fastfloat_really_inline constexpr bool is_made_of_eight_digits_fast(uint64_t val
|
||||
0x8080808080808080));
|
||||
}
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_made_of_eight_digits_fast(TCH const * chars) noexcept {
|
||||
bool is_made_of_eight_digits_fast(UC const * chars) noexcept {
|
||||
return is_made_of_eight_digits_fast(read_u64(chars));
|
||||
}
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
struct parsed_number_string_t {
|
||||
int64_t exponent{0};
|
||||
uint64_t mantissa{0};
|
||||
TCH const * lastmatch{nullptr};
|
||||
UC const * lastmatch{nullptr};
|
||||
bool negative{false};
|
||||
bool valid{false};
|
||||
bool too_many_digits{false};
|
||||
// contains the range of the significant digits
|
||||
span<TCH> integer{}; // non-nullable
|
||||
span<TCH> fraction{}; // nullable
|
||||
span<UC> integer{}; // non-nullable
|
||||
span<UC> fraction{}; // nullable
|
||||
};
|
||||
using byte_span = span<char>;
|
||||
//using parsed_number_string = parsed_number_string_t<char>;
|
||||
using parsed_number_string = parsed_number_string_t<char>;
|
||||
// Assuming that you use no more than 19 digits, this will
|
||||
// parse an ASCII string.
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend, parse_options_t<TCH> options) noexcept {
|
||||
parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
|
||||
chars_format const fmt = options.format;
|
||||
TCH const decimal_point = options.decimal_point;
|
||||
UC const decimal_point = options.decimal_point;
|
||||
|
||||
parsed_number_string_t<TCH> answer;
|
||||
parsed_number_string_t<UC> answer;
|
||||
answer.valid = false;
|
||||
answer.too_many_digits = false;
|
||||
answer.negative = (*p == TCH('-'));
|
||||
answer.negative = (*p == UC('-'));
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||
if ((*p == TCH('-')) || (*p == TCH('+'))) {
|
||||
if ((*p == UC('-')) || (*p == UC('+'))) {
|
||||
#else
|
||||
if (*p == TCH('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
|
||||
#endif
|
||||
++p;
|
||||
if (p == pend) {
|
||||
@ -132,7 +132,7 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
return answer;
|
||||
}
|
||||
}
|
||||
TCH const * const start_digits = p;
|
||||
UC const * const start_digits = p;
|
||||
|
||||
uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
|
||||
|
||||
@ -140,16 +140,16 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
// a multiplication by 10 is cheaper than an arbitrary integer
|
||||
// multiplication
|
||||
i = 10 * i +
|
||||
uint64_t(*p - TCH('0')); // might overflow, we will handle the overflow later
|
||||
uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
|
||||
++p;
|
||||
}
|
||||
TCH const * const end_of_integer_part = p;
|
||||
UC const * const end_of_integer_part = p;
|
||||
int64_t digit_count = int64_t(end_of_integer_part - start_digits);
|
||||
answer.integer = span<TCH>(start_digits, size_t(digit_count));
|
||||
answer.integer = span<UC>(start_digits, size_t(digit_count));
|
||||
int64_t exponent = 0;
|
||||
if ((p != pend) && (*p == decimal_point)) {
|
||||
++p;
|
||||
TCH const * before = p;
|
||||
UC const * before = p;
|
||||
// can occur at most twice without overflowing, but let it occur more, since
|
||||
// for integers with many digits, digit parsing is the primary bottleneck.
|
||||
while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
|
||||
@ -157,12 +157,12 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
p += 8;
|
||||
}
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - TCH('0'));
|
||||
uint8_t digit = uint8_t(*p - UC('0'));
|
||||
++p;
|
||||
i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
|
||||
}
|
||||
exponent = before - p;
|
||||
answer.fraction = span<TCH>(before, size_t(p - before));
|
||||
answer.fraction = span<UC>(before, size_t(p - before));
|
||||
digit_count -= exponent;
|
||||
}
|
||||
// we must have encountered at least one integer!
|
||||
@ -170,14 +170,14 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
return answer;
|
||||
}
|
||||
int64_t exp_number = 0; // explicit exponential part
|
||||
if ((fmt & chars_format::scientific) && (p != pend) && ((TCH('e') == *p) || (TCH('E') == *p))) {
|
||||
TCH const * location_of_e = p;
|
||||
if ((fmt & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) {
|
||||
UC const * location_of_e = p;
|
||||
++p;
|
||||
bool neg_exp = false;
|
||||
if ((p != pend) && (TCH('-') == *p)) {
|
||||
if ((p != pend) && (UC('-') == *p)) {
|
||||
neg_exp = true;
|
||||
++p;
|
||||
} else if ((p != pend) && (TCH('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||
} else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
|
||||
++p;
|
||||
}
|
||||
if ((p == pend) || !is_integer(*p)) {
|
||||
@ -189,7 +189,7 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
p = location_of_e;
|
||||
} else {
|
||||
while ((p != pend) && is_integer(*p)) {
|
||||
uint8_t digit = uint8_t(*p - TCH('0'));
|
||||
uint8_t digit = uint8_t(*p - UC('0'));
|
||||
if (exp_number < 0x10000000) {
|
||||
exp_number = 10 * exp_number + digit;
|
||||
}
|
||||
@ -215,9 +215,9 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
// We have to handle the case where we have 0.0000somenumber.
|
||||
// We need to be mindful of the case where we only have zeroes...
|
||||
// E.g., 0.000000000...000.
|
||||
TCH const * start = start_digits;
|
||||
while ((start != pend) && (*start == TCH('0') || *start == decimal_point)) {
|
||||
if(*start == TCH('0')) { digit_count --; }
|
||||
UC const * start = start_digits;
|
||||
while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
|
||||
if(*start == UC('0')) { digit_count --; }
|
||||
start++;
|
||||
}
|
||||
if (digit_count > 19) {
|
||||
@ -227,19 +227,19 @@ parsed_number_string_t<TCH> parse_number_string(TCH const *p, TCH const * pend,
|
||||
// pre-tokenized spans from above.
|
||||
i = 0;
|
||||
p = answer.integer.ptr;
|
||||
TCH const * int_end = p + answer.integer.len();
|
||||
UC const * int_end = p + answer.integer.len();
|
||||
const uint64_t minimal_nineteen_digit_integer{1000000000000000000};
|
||||
while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
|
||||
i = i * 10 + uint64_t(*p - TCH('0'));
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
}
|
||||
if (i >= minimal_nineteen_digit_integer) { // We have a big integers
|
||||
exponent = end_of_integer_part - p + exp_number;
|
||||
} else { // We have a value with a fractional component.
|
||||
p = answer.fraction.ptr;
|
||||
TCH const * frac_end = p + answer.fraction.len();
|
||||
UC const * frac_end = p + answer.fraction.len();
|
||||
while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
|
||||
i = i * 10 + uint64_t(*p - TCH('0'));
|
||||
i = i * 10 + uint64_t(*p - UC('0'));
|
||||
++p;
|
||||
}
|
||||
exponent = answer.fraction.ptr - p + exp_number;
|
||||
|
||||
@ -23,9 +23,9 @@ constexpr static uint64_t powers_of_ten_uint64[] = {
|
||||
// this algorithm is not even close to optimized, but it has no practical
|
||||
// effect on performance: in order to have a faster algorithm, we'd need
|
||||
// to slow down performance for faster algorithms, and this is still fast.
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
int32_t scientific_exponent(parsed_number_string_t<TCH> & num) noexcept {
|
||||
int32_t scientific_exponent(parsed_number_string_t<UC> & num) noexcept {
|
||||
uint64_t mantissa = num.mantissa;
|
||||
int32_t exponent = int32_t(num.exponent);
|
||||
while (mantissa >= 10000) {
|
||||
@ -154,19 +154,19 @@ void round_down(adjusted_mantissa& am, int32_t shift) noexcept {
|
||||
}
|
||||
am.power2 += shift;
|
||||
}
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void skip_zeros(TCH const * & first, TCH const * last) noexcept {
|
||||
void skip_zeros(UC const * & first, UC const * last) noexcept {
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<TCH>()) {
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<TCH>()) {
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
break;
|
||||
}
|
||||
first += int_cmp_len<TCH>();
|
||||
first += int_cmp_len<UC>();
|
||||
}
|
||||
while (first != last) {
|
||||
if (*first != TCH('0')) {
|
||||
if (*first != UC('0')) {
|
||||
break;
|
||||
}
|
||||
first++;
|
||||
@ -175,45 +175,45 @@ void skip_zeros(TCH const * & first, TCH const * last) noexcept {
|
||||
|
||||
// determine if any non-zero digits were truncated.
|
||||
// all characters must be valid digits.
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(TCH const * first, TCH const * last) noexcept {
|
||||
bool is_truncated(UC const * first, UC const * last) noexcept {
|
||||
// do 8-bit optimizations, can just compare to 8 literal 0s.
|
||||
uint64_t val;
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<TCH>()) {
|
||||
while (!cpp20_and_in_constexpr() && std::distance(first, last) >= int_cmp_len<UC>()) {
|
||||
::memcpy(&val, first, sizeof(uint64_t));
|
||||
if (val != int_cmp_zeros<TCH>()) {
|
||||
if (val != int_cmp_zeros<UC>()) {
|
||||
return true;
|
||||
}
|
||||
first += int_cmp_len<TCH>();
|
||||
first += int_cmp_len<UC>();
|
||||
}
|
||||
while (first != last) {
|
||||
if (*first != TCH('0')) {
|
||||
if (*first != UC('0')) {
|
||||
return true;
|
||||
}
|
||||
++first;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
bool is_truncated(span<TCH> s) noexcept {
|
||||
bool is_truncated(span<UC> s) noexcept {
|
||||
return is_truncated(s.ptr, s.ptr + s.len());
|
||||
}
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_eight_digits(TCH const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
void parse_eight_digits(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 100000000 + parse_eight_digits_unrolled(p);
|
||||
p += 8;
|
||||
counter += 8;
|
||||
count += 8;
|
||||
}
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
fastfloat_really_inline FASTFLOAT_CONSTEXPR14
|
||||
void parse_one_digit(TCH const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 10 + limb(*p - TCH('0'));
|
||||
void parse_one_digit(UC const *& p, limb& value, size_t& counter, size_t& count) noexcept {
|
||||
value = value * 10 + limb(*p - UC('0'));
|
||||
p++;
|
||||
counter++;
|
||||
count++;
|
||||
@ -234,9 +234,9 @@ void round_up_bigint(bigint& big, size_t& count) noexcept {
|
||||
}
|
||||
|
||||
// parse the significant digits into a big integer
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
void parse_mantissa(bigint& result, parsed_number_string_t<TCH>& num, size_t max_digits, size_t& digits) noexcept {
|
||||
void parse_mantissa(bigint& result, 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
|
||||
// scalar value (9 or 19 digits) for each step.
|
||||
@ -250,8 +250,8 @@ void parse_mantissa(bigint& result, parsed_number_string_t<TCH>& num, size_t max
|
||||
#endif
|
||||
|
||||
// process all integer digits.
|
||||
TCH const * p = num.integer.ptr;
|
||||
TCH const * pend = p + num.integer.len();
|
||||
UC const * p = num.integer.ptr;
|
||||
UC const * pend = p + num.integer.len();
|
||||
skip_zeros(p, pend);
|
||||
// process all digits, in increments of step per loop
|
||||
while (p != pend) {
|
||||
@ -400,9 +400,9 @@ adjusted_mantissa negative_digit_comp(bigint& bigmant, adjusted_mantissa am, int
|
||||
// `b` as a big-integer type, scaled to the same binary exponent as
|
||||
// the actual digits. we then compare the big integer representations
|
||||
// of both, and use that to direct rounding.
|
||||
template <typename T, typename TCH>
|
||||
template <typename T, typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR20
|
||||
adjusted_mantissa digit_comp(parsed_number_string_t<TCH>& num, adjusted_mantissa am) noexcept {
|
||||
adjusted_mantissa digit_comp(parsed_number_string_t<UC>& num, adjusted_mantissa am) noexcept {
|
||||
// remove the invalid exponent bias
|
||||
am.power2 -= invalid_am_bias;
|
||||
|
||||
|
||||
@ -13,23 +13,23 @@ enum chars_format {
|
||||
general = fixed | scientific
|
||||
};
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
struct from_chars_result_t {
|
||||
TCH const * ptr;
|
||||
UC const * ptr;
|
||||
std::errc ec;
|
||||
};
|
||||
using from_chars_result = from_chars_result_t<char>;
|
||||
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
struct parse_options_t {
|
||||
constexpr explicit parse_options_t(chars_format fmt = chars_format::general,
|
||||
TCH dot = TCH('.'))
|
||||
UC dot = UC('.'))
|
||||
: format(fmt), decimal_point(dot) {}
|
||||
|
||||
/** Which number formats are accepted */
|
||||
chars_format format;
|
||||
/** The character used as decimal point */
|
||||
TCH decimal_point;
|
||||
UC decimal_point;
|
||||
};
|
||||
using parse_options = parse_options_t<char>;
|
||||
|
||||
@ -52,18 +52,18 @@ using parse_options = parse_options_t<char>;
|
||||
* to determine whether we allow the fixed point and scientific notation respectively.
|
||||
* The default is `fast_float::chars_format::general` which allows both `fixed` and `scientific`.
|
||||
*/
|
||||
template<typename T, typename TCH = char>
|
||||
template<typename T, typename UC = char>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<TCH> from_chars(TCH const * first, TCH const * last,
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt = chars_format::general) noexcept;
|
||||
|
||||
/**
|
||||
* Like from_chars, but accepts an `options` argument to govern number parsing.
|
||||
*/
|
||||
template<typename T, typename TCH = char>
|
||||
template<typename T, typename UC = char>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<TCH> from_chars_advanced(TCH const * first, TCH const * last,
|
||||
T &value, parse_options_t<TCH> options) noexcept;
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> options) noexcept;
|
||||
|
||||
} // namespace fast_float
|
||||
#include "parse_number.h"
|
||||
|
||||
@ -106,9 +106,9 @@ fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() {
|
||||
}
|
||||
|
||||
// Compares two ASCII strings in a case insensitive manner.
|
||||
template <typename TCH>
|
||||
template <typename UC>
|
||||
inline FASTFLOAT_CONSTEXPR14 bool
|
||||
fastfloat_strncasecmp(TCH const * input1, TCH const * input2, size_t length) {
|
||||
fastfloat_strncasecmp(UC const * input1, UC const * input2, size_t length) {
|
||||
char running_diff{0};
|
||||
for (size_t i = 0; i < length; ++i) {
|
||||
running_diff |= (char(input1[i]) ^ char(input2[i]));
|
||||
@ -505,24 +505,24 @@ constexpr bool space_lut<T>::value[];
|
||||
inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; }
|
||||
#endif
|
||||
|
||||
template<typename TCH>
|
||||
template<typename UC>
|
||||
static constexpr uint64_t int_cmp_zeros()
|
||||
{
|
||||
switch(sizeof(TCH))
|
||||
switch(sizeof(UC))
|
||||
{
|
||||
case 1: return 0x3030303030303030;
|
||||
case 2: return (uint64_t(TCH('0')) << 48 | uint64_t(TCH('0')) << 32 | uint64_t(TCH('0')) << 16 | TCH('0'));
|
||||
case 4: return (uint64_t(TCH('0')) << 32 | TCH('0'));
|
||||
case 2: return (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | uint64_t(UC('0')) << 16 | UC('0'));
|
||||
case 4: return (uint64_t(UC('0')) << 32 | UC('0'));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
template<typename TCH>
|
||||
template<typename UC>
|
||||
static constexpr int int_cmp_len()
|
||||
{
|
||||
return sizeof(uint64_t) / sizeof(TCH);
|
||||
return sizeof(uint64_t) / sizeof(UC);
|
||||
}
|
||||
template<typename TCH>
|
||||
static constexpr TCH const * str_const_nan()
|
||||
template<typename UC>
|
||||
static constexpr UC const * str_const_nan()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
@ -546,8 +546,8 @@ static constexpr char32_t const * str_const_nan<char32_t>()
|
||||
{
|
||||
return U"nan";
|
||||
}
|
||||
template<typename TCH>
|
||||
static constexpr TCH const * str_const_inf()
|
||||
template<typename UC>
|
||||
static constexpr UC const * str_const_inf()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -19,41 +19,41 @@ namespace detail {
|
||||
* The case comparisons could be made much faster given that we know that the
|
||||
* strings a null-free and fixed.
|
||||
**/
|
||||
template <typename T, typename TCH>
|
||||
from_chars_result_t<TCH> FASTFLOAT_CONSTEXPR14
|
||||
parse_infnan(TCH const * first, TCH const * last, T &value) noexcept {
|
||||
from_chars_result_t<TCH> answer{};
|
||||
template <typename T, typename UC>
|
||||
from_chars_result_t<UC> FASTFLOAT_CONSTEXPR14
|
||||
parse_infnan(UC const * first, UC const * last, T &value) noexcept {
|
||||
from_chars_result_t<UC> answer{};
|
||||
answer.ptr = first;
|
||||
answer.ec = std::errc(); // be optimistic
|
||||
bool minusSign = false;
|
||||
if (*first == TCH('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
||||
if (*first == UC('-')) { // assume first < last, so dereference without checks; C++17 20.19.3.(7.1) explicitly forbids '+' here
|
||||
minusSign = true;
|
||||
++first;
|
||||
}
|
||||
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
|
||||
if (*first == TCH('+')) {
|
||||
if (*first == UC('+')) {
|
||||
++first;
|
||||
}
|
||||
#endif
|
||||
if (last - first >= 3) {
|
||||
if (fastfloat_strncasecmp(first, str_const_nan<TCH>(), 3)) {
|
||||
if (fastfloat_strncasecmp(first, str_const_nan<UC>(), 3)) {
|
||||
answer.ptr = (first += 3);
|
||||
value = minusSign ? -std::numeric_limits<T>::quiet_NaN() : std::numeric_limits<T>::quiet_NaN();
|
||||
// Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan).
|
||||
if(first != last && *first == TCH('(')) {
|
||||
for(TCH const * ptr = first + 1; ptr != last; ++ptr) {
|
||||
if (*ptr == TCH(')')) {
|
||||
if(first != last && *first == UC('(')) {
|
||||
for(UC const * ptr = first + 1; ptr != last; ++ptr) {
|
||||
if (*ptr == UC(')')) {
|
||||
answer.ptr = ptr + 1; // valid nan(n-char-seq-opt)
|
||||
break;
|
||||
}
|
||||
else if(!((TCH('a') <= *ptr && *ptr <= TCH('z')) || (TCH('A') <= *ptr && *ptr <= TCH('Z')) || (TCH('0') <= *ptr && *ptr <= TCH('9')) || *ptr == TCH('_')))
|
||||
else if(!((UC('a') <= *ptr && *ptr <= UC('z')) || (UC('A') <= *ptr && *ptr <= UC('Z')) || (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_')))
|
||||
break; // forbidden char, not nan(n-char-seq-opt)
|
||||
}
|
||||
}
|
||||
return answer;
|
||||
}
|
||||
if (fastfloat_strncasecmp(first, str_const_inf<TCH>(), 3)) {
|
||||
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<TCH>() + 3, 5)) {
|
||||
if (fastfloat_strncasecmp(first, str_const_inf<UC>(), 3)) {
|
||||
if ((last - first >= 8) && fastfloat_strncasecmp(first + 3, str_const_inf<UC>() + 3, 5)) {
|
||||
answer.ptr = first + 8;
|
||||
} else {
|
||||
answer.ptr = first + 3;
|
||||
@ -132,25 +132,25 @@ fastfloat_really_inline bool rounds_to_nearest() noexcept {
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<typename T, typename TCH>
|
||||
template<typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<TCH> from_chars(TCH const * first, TCH const * last,
|
||||
from_chars_result_t<UC> from_chars(UC const * first, UC const * last,
|
||||
T &value, chars_format fmt /*= chars_format::general*/) noexcept {
|
||||
return from_chars_advanced(first, last, value, parse_options_t<TCH>{fmt});
|
||||
return from_chars_advanced(first, last, value, parse_options_t<UC>{fmt});
|
||||
}
|
||||
|
||||
template<typename T, typename TCH>
|
||||
template<typename T, typename UC>
|
||||
FASTFLOAT_CONSTEXPR20
|
||||
from_chars_result_t<TCH> from_chars_advanced(TCH const * first, TCH const * last,
|
||||
T &value, parse_options_t<TCH> options) noexcept {
|
||||
from_chars_result_t<UC> from_chars_advanced(UC const * first, UC const * last,
|
||||
T &value, parse_options_t<UC> 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<TCH, char>::value ||
|
||||
std::is_same<TCH, wchar_t>::value ||
|
||||
std::is_same<TCH, char16_t>::value ||
|
||||
std::is_same<TCH, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported");
|
||||
static_assert (std::is_same<UC, char>::value ||
|
||||
std::is_same<UC, wchar_t>::value ||
|
||||
std::is_same<UC, char16_t>::value ||
|
||||
std::is_same<UC, char32_t>::value , "only char, wchar_t, char16_t and char32_t are supported");
|
||||
|
||||
from_chars_result_t<TCH> answer;
|
||||
from_chars_result_t<UC> answer;
|
||||
#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
|
||||
while ((first != last) && fast_float::is_space(uint8_t(*first))) {
|
||||
first++;
|
||||
@ -161,7 +161,7 @@ from_chars_result_t<TCH> from_chars_advanced(TCH const * first, TCH const * last
|
||||
answer.ptr = first;
|
||||
return answer;
|
||||
}
|
||||
parsed_number_string_t<TCH> pns = parse_number_string<TCH>(first, last, options);
|
||||
parsed_number_string_t<UC> pns = parse_number_string<UC>(first, last, options);
|
||||
if (!pns.valid) {
|
||||
return detail::parse_infnan(first, last, value);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user