Skip to content

Commit 445de6e

Browse files
mamebyroot
authored andcommitted
Stop prebuilding array_delim
The purpose of this change is to exploit `fbuffer_append_char` that is faster than `fbuffer_append`. `array_delim` was a buffer that concatenated a single comma with `array_nl`. However, in the typical use case (`JSON.generate(data)`), `array_nl` is empty. This means that `array_delim` was a single-character buffer in many cases. `fbuffer_append(buffer, array_delim)` used `memcpy` to copy one byte, which was not so efficient. Rather, this change uses `fbuffer_append_char(buffer, ',')` and then `fbuffer_append(buffer, array_nl)` only when `array_nl` is not NULL. This speeds up `JSON.generate` by about 9% in a benchmark.
1 parent e125072 commit 445de6e

File tree

2 files changed

+4
-14
lines changed

2 files changed

+4
-14
lines changed

ext/json/ext/generator/generator.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,6 @@ static void State_free(void *ptr)
421421
if (state->space_before) ruby_xfree(state->space_before);
422422
if (state->object_nl) ruby_xfree(state->object_nl);
423423
if (state->array_nl) ruby_xfree(state->array_nl);
424-
if (state->array_delim) fbuffer_free(state->array_delim);
425424
if (state->object_delim) fbuffer_free(state->object_delim);
426425
if (state->object_delim2) fbuffer_free(state->object_delim2);
427426
ruby_xfree(state);
@@ -436,7 +435,6 @@ static size_t State_memsize(const void *ptr)
436435
if (state->space_before) size += state->space_before_len + 1;
437436
if (state->object_nl) size += state->object_nl_len + 1;
438437
if (state->array_nl) size += state->array_nl_len + 1;
439-
if (state->array_delim) size += FBUFFER_CAPA(state->array_delim);
440438
if (state->object_delim) size += FBUFFER_CAPA(state->object_delim);
441439
if (state->object_delim2) size += FBUFFER_CAPA(state->object_delim2);
442440
return size;
@@ -731,8 +729,6 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
731729
char *indent = state->indent;
732730
long indent_len = state->indent_len;
733731
long max_nesting = state->max_nesting;
734-
char *delim = FBUFFER_PTR(state->array_delim);
735-
long delim_len = FBUFFER_LEN(state->array_delim);
736732
long depth = ++state->depth;
737733
int i, j;
738734
if (max_nesting != 0 && depth > max_nesting) {
@@ -741,7 +737,10 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
741737
fbuffer_append_char(buffer, '[');
742738
if (array_nl) fbuffer_append(buffer, array_nl, array_nl_len);
743739
for(i = 0; i < RARRAY_LEN(obj); i++) {
744-
if (i > 0) fbuffer_append(buffer, delim, delim_len);
740+
if (i > 0) {
741+
fbuffer_append_char(buffer, ',');
742+
if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
743+
}
745744
if (indent) {
746745
for (j = 0; j < depth; j++) {
747746
fbuffer_append(buffer, indent, indent_len);
@@ -905,13 +904,6 @@ static FBuffer *cState_prepare_buffer(VALUE self)
905904
fbuffer_append_char(state->object_delim2, ':');
906905
if (state->space) fbuffer_append(state->object_delim2, state->space, state->space_len);
907906

908-
if (state->array_delim) {
909-
fbuffer_clear(state->array_delim);
910-
} else {
911-
state->array_delim = fbuffer_alloc(16);
912-
}
913-
fbuffer_append_char(state->array_delim, ',');
914-
if (state->array_nl) fbuffer_append(state->array_delim, state->array_nl, state->array_nl_len);
915907
return buffer;
916908
}
917909

@@ -1024,7 +1016,6 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
10241016
objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
10251017
objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
10261018
objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
1027-
if (origState->array_delim) objState->array_delim = fbuffer_dup(origState->array_delim);
10281019
if (origState->object_delim) objState->object_delim = fbuffer_dup(origState->object_delim);
10291020
if (origState->object_delim2) objState->object_delim2 = fbuffer_dup(origState->object_delim2);
10301021
return obj;

ext/json/ext/generator/generator.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ typedef struct JSON_Generator_StateStruct {
5555
long object_nl_len;
5656
char *array_nl;
5757
long array_nl_len;
58-
FBuffer *array_delim;
5958
FBuffer *object_delim;
6059
FBuffer *object_delim2;
6160
long max_nesting;

0 commit comments

Comments
 (0)