Implement JSON rules

This commit is contained in:
Maya Warrier 2023-09-13 19:17:45 -04:00
parent 6a390f63e9
commit 396f41271f
2 changed files with 30 additions and 5 deletions

View File

@ -273,6 +273,7 @@ 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 = options.format;
parse_rules const rules = options.rules;
UC const decimal_point = options.decimal_point;
parsed_number_string_t<UC> answer;
@ -288,8 +289,15 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
if (p == pend) {
return answer;
}
if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
return answer;
if (rules == parse_rules::json) {
if (!is_integer(*p)) { // a sign must be followed by an integer
return answer;
}
} else {
FASTFLOAT_DEBUG_ASSERT(rules == parse_rules::std);
if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
return answer;
}
}
}
UC const * const start_digits = p;
@ -306,8 +314,14 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
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));
// disallow leading zeros
if (rules == parse_rules::json && start_digits[0] == UC('0') && digit_count > 1) {
return answer;
}
int64_t exponent = 0;
if ((p != pend) && (*p == decimal_point)) {
const bool has_decimal_point = (p != pend) && (*p == decimal_point);
if (has_decimal_point) {
++p;
UC const * before = p;
// can occur at most twice without overflowing, but let it occur more, since
@ -327,6 +341,10 @@ parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, par
if (digit_count == 0) {
return answer;
}
// or at least two if a decimal point exists, with json rules
else if (rules == parse_rules::json && has_decimal_point && digit_count == 1) {
return answer;
}
int64_t exp_number = 0; // explicit exponential part
if ((fmt & chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) {
UC const * location_of_e = p;

View File

@ -19,6 +19,11 @@ enum chars_format {
general = fixed | scientific
};
enum class parse_rules {
std,
json
};
template <typename UC>
struct from_chars_result_t {
UC const* ptr;
@ -29,13 +34,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('.'), parse_rules prules = parse_rules::std)
: format(fmt), decimal_point(dot), rules(prules) {}
/** Which number formats are accepted */
chars_format format;
/** The character used as decimal point */
UC decimal_point;
/** Rules to use for parsing */
parse_rules rules;
};
using parse_options = parse_options_t<char>;