Skip to content

Commit 1bf405e

Browse files
committed
parser.c: Extract json_parse_digits
1 parent 2681b23 commit 1bf405e

File tree

1 file changed

+23
-26
lines changed

1 file changed

+23
-26
lines changed

ext/json/ext/parser/parser.c

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,24 +1022,28 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
10221022
return Qfalse;
10231023
}
10241024

1025+
static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulator)
1026+
{
1027+
const char *start = state->cursor;
1028+
while ((state->cursor < state->end) && rb_isdigit(*state->cursor)) {
1029+
*accumulator = *accumulator * 10 + (*state->cursor - '0');
1030+
state->cursor++;
1031+
}
1032+
return (int)(state->cursor - start);
1033+
}
1034+
10251035
static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig *config, bool negative, const char *start)
10261036
{
10271037
bool integer = true;
1038+
const char first_digit = *state->cursor;
10281039

10291040
// Variables for Ryu optimization - extract digits during parsing
1030-
uint64_t mantissa = 0;
1031-
int mantissa_digits = 0;
10321041
int32_t exponent = 0;
10331042
int decimal_point_pos = -1;
1034-
1035-
const char first_digit = *state->cursor;
1043+
uint64_t mantissa = 0;
10361044

10371045
// Parse integer part and extract mantissa digits
1038-
while ((state->cursor < state->end) && rb_isdigit(*state->cursor)) {
1039-
mantissa = mantissa * 10 + (*state->cursor - '0');
1040-
mantissa_digits++;
1041-
state->cursor++;
1042-
}
1046+
int mantissa_digits = json_parse_digits(state, &mantissa);
10431047

10441048
if (RB_UNLIKELY(first_digit == '0' && mantissa_digits > 1 || negative && mantissa_digits == 0)) {
10451049
raise_parse_error_at("invalid number: %s", state, start);
@@ -1051,19 +1055,16 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
10511055
decimal_point_pos = mantissa_digits; // Remember position of decimal point
10521056
state->cursor++;
10531057

1054-
if (state->cursor == state->end || !rb_isdigit(*state->cursor)) {
1055-
raise_parse_error_at("invalid number: %s", state, start);
1056-
}
1058+
int fractional_digits = json_parse_digits(state, &mantissa);
1059+
mantissa_digits += fractional_digits;
10571060

1058-
while ((state->cursor < state->end) && rb_isdigit(*state->cursor)) {
1059-
mantissa = mantissa * 10 + (*state->cursor - '0');
1060-
mantissa_digits++;
1061-
state->cursor++;
1061+
if (RB_UNLIKELY(!fractional_digits)) {
1062+
raise_parse_error_at("invalid number: %s", state, start);
10621063
}
10631064
}
10641065

10651066
// Parse exponent
1066-
if ((state->cursor < state->end) && ((*state->cursor == 'e') || (*state->cursor == 'E'))) {
1067+
if ((state->cursor < state->end) && ((rb_tolower(*state->cursor) == 'e'))) {
10671068
integer = false;
10681069
state->cursor++;
10691070

@@ -1073,18 +1074,14 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
10731074
state->cursor++;
10741075
}
10751076

1076-
if (state->cursor == state->end || !rb_isdigit(*state->cursor)) {
1077-
raise_parse_error_at("invalid number: %s", state, start);
1078-
}
1077+
uint64_t abs_exponent = 0;
1078+
int exponent_digits = json_parse_digits(state, &abs_exponent);
10791079

1080-
while ((state->cursor < state->end) && rb_isdigit(*state->cursor)) {
1081-
exponent = exponent * 10 + (*state->cursor - '0');
1082-
state->cursor++;
1080+
if (RB_UNLIKELY(!exponent_digits)) {
1081+
raise_parse_error_at("invalid number: %s", state, start);
10831082
}
10841083

1085-
if (negative_exponent) {
1086-
exponent = -exponent;
1087-
}
1084+
exponent = negative_exponent ? -((int32_t)abs_exponent) : ((int32_t)abs_exponent);
10881085
}
10891086

10901087
if (integer) {

0 commit comments

Comments
 (0)