Skip to content

Commit

Permalink
moving from macros to forrmat flags
Browse files Browse the repository at this point in the history
  • Loading branch information
dalle committed Nov 17, 2024
1 parent f733dfd commit b4d26ef
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 55 deletions.
1 change: 1 addition & 0 deletions CONTRIBUTORS
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ Lénárd Szolnoki
Jan Pharago
Maya Warrier
Taha Khokhar
Anders Dalvander
32 changes: 19 additions & 13 deletions include/fast_float/ascii_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,18 +289,20 @@ parse_number_string(UC const *p, UC const *pend,
parsed_number_string_t<UC> answer;
answer.valid = false;
answer.too_many_digits = false;
answer.negative = (*p == UC('-'));
answer.negative = (*p == UC('-')); // assume p < pend, so dereference without checks;
// C++17 20.19.3.(7.1) explicitly forbids '+' sign here
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
if ((*p == UC('-')) || (!(fmt & FASTFLOAT_JSONFMT) && *p == UC('+'))) {
if ((*p == UC('-')) || (!(fmt & detail::basic_json_fmt) && *p == UC('+'))) {
#else
if (*p == UC('-')) { // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
if ((*p == UC('-')) || (int(fmt & chars_format::allow_leading_plus) &&
!int(fmt & detail::basic_json_fmt) && *p == UC('+'))) {
#endif
++p;
if (p == pend) {
return report_parse_error<UC>(
p, parse_error::missing_integer_or_dot_after_sign);
}
if (fmt & FASTFLOAT_JSONFMT) {
if (int(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);
Expand Down Expand Up @@ -329,7 +331,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<const UC>(start_digits, size_t(digit_count));
if (fmt & FASTFLOAT_JSONFMT) {
if (int(fmt & 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);
Expand Down Expand Up @@ -358,7 +360,7 @@ parse_number_string(UC const *p, UC const *pend,
answer.fraction = span<const UC>(before, size_t(p - before));
digit_count -= exponent;
}
if (fmt & FASTFLOAT_JSONFMT) {
if (int(fmt & detail::basic_json_fmt)) {
// at least 1 digit in fractional part
if (has_decimal_point && exponent == 0) {
return report_parse_error<UC>(p,
Expand All @@ -369,9 +371,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 (((fmt & chars_format::scientific) && (p != pend) &&
if ((int(fmt & chars_format::scientific) && (p != pend) &&
((UC('e') == *p) || (UC('E') == *p))) ||
((fmt & FASTFLOAT_FORTRANFMT) && (p != pend) &&
(int(fmt & detail::basic_fortran_fmt) && (p != pend) &&
((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) ||
(UC('D') == *p)))) {
UC const *location_of_e = p;
Expand All @@ -389,7 +391,7 @@ parse_number_string(UC const *p, UC const *pend,
++p;
}
if ((p == pend) || !is_integer(*p)) {
if (!(fmt & chars_format::fixed)) {
if (!int(fmt & 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.
Expand All @@ -412,7 +414,7 @@ parse_number_string(UC const *p, UC const *pend,
}
} else {
// If it scientific and not fixed, we have to bail out.
if ((fmt & chars_format::scientific) && !(fmt & chars_format::fixed)) {
if (int(fmt & chars_format::scientific) && !int(fmt & chars_format::fixed)) {
return report_parse_error<UC>(p, parse_error::missing_exponential_part);
}
}
Expand Down Expand Up @@ -471,12 +473,15 @@ parse_number_string(UC const *p, UC const *pend,

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, int base) {
parse_int_string(UC const *p, UC const *pend, T &value, parse_options_t<UC> options) {
chars_format const fmt = options.format;
int const base = options.base;

from_chars_result_t<UC> answer;

UC const *const first = p;

bool negative = (*p == UC('-'));
const bool negative = (*p == UC('-'));
if (!std::is_signed<T>::value && negative) {
answer.ec = std::errc::invalid_argument;
answer.ptr = first;
Expand All @@ -485,7 +490,8 @@ parse_int_string(UC const *p, UC const *pend, T &value, int base) {
#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS // disabled by default
if ((*p == UC('-')) || (*p == UC('+'))) {
#else
if (*p == UC('-')) {
if ((*p == UC('-')) ||
(int(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) {
#endif
++p;
}
Expand Down
16 changes: 9 additions & 7 deletions include/fast_float/fast_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,6 @@ FASTFLOAT_CONSTEXPR20 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 UC = char>
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars_advanced(UC const *first, UC const *last, T &value,
parse_options_t<UC> options) noexcept;
/**
* from_chars for integer types.
*/
Expand All @@ -51,6 +44,15 @@ template <typename T, typename UC = char,
FASTFLOAT_CONSTEXPR20 from_chars_result_t<UC>
from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept;

/**
* Like from_chars, but accepts an `options` argument to govern number parsing.
* Both for floating-point types and integer types.
*/
template <typename T, typename UC = char>
FASTFLOAT_CONSTEXPR20 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"
#endif // FASTFLOAT_FAST_FLOAT_H
70 changes: 57 additions & 13 deletions include/fast_float/float_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,22 +16,66 @@

namespace fast_float {

#define FASTFLOAT_JSONFMT (1 << 5)
#define FASTFLOAT_FORTRANFMT (1 << 6)
enum class chars_format;

enum chars_format {
namespace detail {
constexpr chars_format basic_json_fmt = chars_format(1 << 5);
constexpr chars_format basic_fortran_fmt = chars_format(1 << 6);
} // namespace detail

enum class chars_format {
scientific = 1 << 0,
fixed = 1 << 2,
hex = 1 << 3,
no_infnan = 1 << 4,
// RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6
json = FASTFLOAT_JSONFMT | fixed | scientific | no_infnan,
json = int(detail::basic_json_fmt) | fixed | scientific | no_infnan,
// Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed.
json_or_infnan = FASTFLOAT_JSONFMT | fixed | scientific,
fortran = FASTFLOAT_FORTRANFMT | fixed | scientific,
general = fixed | scientific
json_or_infnan = int(detail::basic_json_fmt) | fixed | scientific,
fortran = int(detail::basic_fortran_fmt) | fixed | scientific,
general = fixed | scientific,
allow_leading_plus = 1 << 7,
skip_white_space = 1 << 8,
};

constexpr chars_format operator~(chars_format rhs) noexcept {
using int_type = std::underlying_type<chars_format>::type;
return static_cast<chars_format>(~static_cast<int_type>(rhs));
}

constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept {
using int_type = std::underlying_type<chars_format>::type;
return static_cast<chars_format>(static_cast<int_type>(lhs) &
static_cast<int_type>(rhs));
}

constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept {
using int_type = std::underlying_type<chars_format>::type;
return static_cast<chars_format>(static_cast<int_type>(lhs) |
static_cast<int_type>(rhs));
}

constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept {
using int_type = std::underlying_type<chars_format>::type;
return static_cast<chars_format>(static_cast<int_type>(lhs) ^
static_cast<int_type>(rhs));
}

constexpr chars_format &operator&=(chars_format &lhs,
chars_format rhs) noexcept {
return lhs = (lhs & rhs);
}

constexpr chars_format &operator|=(chars_format &lhs,
chars_format rhs) noexcept {
return lhs = (lhs | rhs);
}

constexpr chars_format &operator^=(chars_format &lhs,
chars_format rhs) noexcept {
return lhs = (lhs ^ rhs);
}

template <typename UC> struct from_chars_result_t {
UC const *ptr;
std::errc ec;
Expand All @@ -40,13 +84,15 @@ 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('.'))
: format(fmt), decimal_point(dot) {}
UC dot = UC('.'), int b = 10)
: format(fmt), decimal_point(dot), base(b) {}

/** Which number formats are accepted */
chars_format format;
/** The character used as decimal point */
UC decimal_point;
/** The base used for integers */
int base;
};
using parse_options = parse_options_t<char>;

Expand Down Expand Up @@ -217,7 +263,7 @@ inline FASTFLOAT_CONSTEXPR14 bool
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]));
running_diff |= (char(input1[i]) ^ char(input2[i])); //Dalle: does this work for all char types?
}
return (running_diff == 0) || (running_diff == 32);
}
Expand Down Expand Up @@ -670,7 +716,6 @@ to_float(bool negative, adjusted_mantissa am, T &value) {
#endif
}

#ifdef FASTFLOAT_SKIP_WHITE_SPACE // disabled by default
template <typename = void> struct space_lut {
static constexpr bool value[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
Expand All @@ -692,8 +737,7 @@ template <typename T> constexpr bool space_lut<T>::value[];

#endif

inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; }
#endif
inline constexpr bool is_space(uint8_t c) { return space_lut<>::value[c]; } //Dalle: does this work for all char types?

template <typename UC> static constexpr uint64_t int_cmp_zeros() {
static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4),
Expand Down
Loading

0 comments on commit b4d26ef

Please sign in to comment.