diff --git a/include/fast_float/ascii_number.h b/include/fast_float/ascii_number.h index 9afcdc4..eba8b9a 100644 --- a/include/fast_float/ascii_number.h +++ b/include/fast_float/ascii_number.h @@ -273,6 +273,7 @@ template fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t parse_number_string(UC const *p, UC const * pend, parse_options_t 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 answer; @@ -288,8 +289,15 @@ parsed_number_string_t 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 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(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 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; diff --git a/include/fast_float/float_common.h b/include/fast_float/float_common.h index 4a290f4..466d094 100644 --- a/include/fast_float/float_common.h +++ b/include/fast_float/float_common.h @@ -19,6 +19,11 @@ enum chars_format { general = fixed | scientific }; +enum class parse_rules { + std, + json +}; + template struct from_chars_result_t { UC const* ptr; @@ -29,13 +34,15 @@ using from_chars_result = from_chars_result_t; template 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;