Skip to content

Commit a73323d

Browse files
Watson1978flori
authored andcommitted
Convert Hash object using rb_hash_foreach()
To convert Hash convert, this part was using following pseudo code ``` obj.keys.each do |key| value = obj[key] ... end ``` and `rb_funcall()` was called for `obj.keys`. It might be slightly heavy to call the Ruby method. This patch will iterate to convert Hash object about key/value using `rb_hash_foreach()` Ruby API instead of `rb_funcall()`. ``` $ ruby bench_json_generate.rb Warming up -------------------------------------- json 55.000 i/100ms Calculating ------------------------------------- json 558.501 (± 1.1%) i/s - 2.805k in 5.022986s ``` ``` $ ruby bench_json_generate.rb Warming up -------------------------------------- json 65.000 i/100ms Calculating ------------------------------------- json 659.576 (± 1.5%) i/s - 3.315k in 5.027127s ``` ``` require 'json' require 'benchmark/ips' obj = [] 1000.times do |i| obj << { "id" => i, :age => 42, } end Benchmark.ips do |x| x.report "json" do |iter| count = 0 while count < iter JSON.generate(obj) count += 1 end end end ```
1 parent 167ada8 commit a73323d

File tree

1 file changed

+55
-22
lines changed

1 file changed

+55
-22
lines changed

ext/json/ext/generator/generator.c

Lines changed: 55 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -715,43 +715,76 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
715715
return Qnil;
716716
}
717717

718-
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
718+
struct hash_foreach_arg {
719+
FBuffer *buffer;
720+
JSON_Generator_State *state;
721+
VALUE Vstate;
722+
int iter;
723+
};
724+
725+
static int
726+
json_object_i(VALUE key, VALUE val, VALUE _arg)
719727
{
728+
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
729+
FBuffer *buffer = arg->buffer;
730+
JSON_Generator_State *state = arg->state;
731+
VALUE Vstate = arg->Vstate;
732+
720733
char *object_nl = state->object_nl;
721734
long object_nl_len = state->object_nl_len;
722735
char *indent = state->indent;
723736
long indent_len = state->indent_len;
724-
long max_nesting = state->max_nesting;
725737
char *delim = FBUFFER_PTR(state->object_delim);
726738
long delim_len = FBUFFER_LEN(state->object_delim);
727739
char *delim2 = FBUFFER_PTR(state->object_delim2);
728740
long delim2_len = FBUFFER_LEN(state->object_delim2);
741+
long depth = state->depth;
742+
int j;
743+
VALUE key_to_s;
744+
745+
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
746+
if (object_nl) {
747+
fbuffer_append(buffer, object_nl, object_nl_len);
748+
}
749+
if (indent) {
750+
for (j = 0; j < depth; j++) {
751+
fbuffer_append(buffer, indent, indent_len);
752+
}
753+
}
754+
755+
key_to_s = rb_funcall(key, i_to_s, 0);
756+
Check_Type(key_to_s, T_STRING);
757+
generate_json(buffer, Vstate, state, key_to_s);
758+
fbuffer_append(buffer, delim2, delim2_len);
759+
generate_json(buffer, Vstate, state, val);
760+
761+
arg->iter++;
762+
return ST_CONTINUE;
763+
}
764+
765+
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
766+
{
767+
char *object_nl = state->object_nl;
768+
long object_nl_len = state->object_nl_len;
769+
char *indent = state->indent;
770+
long indent_len = state->indent_len;
771+
long max_nesting = state->max_nesting;
729772
long depth = ++state->depth;
730-
int i, j;
731-
VALUE key, key_to_s, keys;
773+
int j;
774+
struct hash_foreach_arg arg;
775+
732776
if (max_nesting != 0 && depth > max_nesting) {
733777
fbuffer_free(buffer);
734778
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
735779
}
736780
fbuffer_append_char(buffer, '{');
737-
keys = rb_funcall(obj, i_keys, 0);
738-
for(i = 0; i < RARRAY_LEN(keys); i++) {
739-
if (i > 0) fbuffer_append(buffer, delim, delim_len);
740-
if (object_nl) {
741-
fbuffer_append(buffer, object_nl, object_nl_len);
742-
}
743-
if (indent) {
744-
for (j = 0; j < depth; j++) {
745-
fbuffer_append(buffer, indent, indent_len);
746-
}
747-
}
748-
key = rb_ary_entry(keys, i);
749-
key_to_s = rb_funcall(key, i_to_s, 0);
750-
Check_Type(key_to_s, T_STRING);
751-
generate_json(buffer, Vstate, state, key_to_s);
752-
fbuffer_append(buffer, delim2, delim2_len);
753-
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
754-
}
781+
782+
arg.buffer = buffer;
783+
arg.state = state;
784+
arg.Vstate = Vstate;
785+
arg.iter = 0;
786+
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
787+
755788
depth = --state->depth;
756789
if (object_nl) {
757790
fbuffer_append(buffer, object_nl, object_nl_len);

0 commit comments

Comments
 (0)