Skip to content

Commit f7cd41c

Browse files
authored
Merge pull request ruby#887 from byroot/improve-consecutive-digits
parser.c: Optimize `json_parse_digits`
2 parents 3ea744a + 82b030f commit f7cd41c

File tree

3 files changed

+33
-7
lines changed

3 files changed

+33
-7
lines changed

ext/json/ext/parser/parser.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -612,12 +612,14 @@ json_eat_whitespace(JSON_ParserState *state)
612612
while (rest(state) > 8) {
613613
uint64_t chunk;
614614
memcpy(&chunk, state->cursor, sizeof(uint64_t));
615-
size_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
615+
if (chunk == 0x2020202020202020) {
616+
state->cursor += 8;
617+
continue;
618+
}
616619

620+
uint32_t consecutive_spaces = trailing_zeros64(chunk ^ 0x2020202020202020) / CHAR_BIT;
617621
state->cursor += consecutive_spaces;
618-
if (consecutive_spaces != 8) {
619-
break;
620-
}
622+
break;
621623
}
622624
#endif
623625
break;
@@ -1101,13 +1103,21 @@ static inline int json_parse_digits(JSON_ParserState *state, uint64_t *accumulat
11011103
continue;
11021104
}
11031105

1104-
if ((match & 0xFFFFFFFF) == 0x33333333) { // 4 consecutive digits
1106+
uint32_t consecutive_digits = trailing_zeros64(match ^ 0x3333333333333333) / CHAR_BIT;
1107+
1108+
if (consecutive_digits >= 4) {
11051109
*accumulator = (*accumulator * 10000) + decode_4digits_unrolled((uint32_t)next_8bytes);
11061110
state->cursor += 4;
1107-
break;
1111+
consecutive_digits -= 4;
1112+
}
1113+
1114+
while (consecutive_digits) {
1115+
*accumulator = *accumulator * 10 + (*state->cursor - '0');
1116+
consecutive_digits--;
1117+
state->cursor++;
11081118
}
11091119

1110-
break;
1120+
return (int)(state->cursor - start);
11111121
}
11121122
#endif
11131123

ext/json/ext/simd/simd.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
#ifdef JSON_DEBUG
2+
#include <assert.h>
3+
#endif
4+
15
typedef enum {
26
SIMD_NONE,
37
SIMD_NEON,
@@ -18,6 +22,10 @@ typedef enum {
1822

1923
static inline uint32_t trailing_zeros64(uint64_t input)
2024
{
25+
#ifdef JSON_DEBUG
26+
assert(input > 0); // __builtin_ctz(0) is undefined behavior
27+
#endif
28+
2129
#if HAVE_BUILTIN_CTZLL
2230
return __builtin_ctzll(input);
2331
#else
@@ -33,6 +41,10 @@ static inline uint32_t trailing_zeros64(uint64_t input)
3341

3442
static inline int trailing_zeros(int input)
3543
{
44+
#ifdef JSON_DEBUG
45+
assert(input > 0); // __builtin_ctz(0) is undefined behavior
46+
#endif
47+
3648
#if HAVE_BUILTIN_CTZLL
3749
return __builtin_ctz(input);
3850
#else

test/json/json_parser_test.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -804,6 +804,10 @@ def test_parse_leading_slash
804804
end
805805
end
806806

807+
def test_parse_whitespace_after_newline
808+
assert_equal [], JSON.parse("[\n#{' ' * (8 + 8 + 4 + 3)}]")
809+
end
810+
807811
private
808812

809813
def assert_equal_float(expected, actual, delta = 1e-2)

0 commit comments

Comments
 (0)