зеркало из https://github.com/github/ruby.git
[flori/json] 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 ``` https://github.com/flori/json/commit/a73323dc5e
This commit is contained in:
Родитель
2003755a2c
Коммит
a2f9c38a71
|
@ -719,6 +719,53 @@ static VALUE cState_aset(VALUE self, VALUE name, VALUE value)
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
struct hash_foreach_arg {
|
||||
FBuffer *buffer;
|
||||
JSON_Generator_State *state;
|
||||
VALUE Vstate;
|
||||
int iter;
|
||||
};
|
||||
|
||||
static int
|
||||
json_object_i(VALUE key, VALUE val, VALUE _arg)
|
||||
{
|
||||
struct hash_foreach_arg *arg = (struct hash_foreach_arg *)_arg;
|
||||
FBuffer *buffer = arg->buffer;
|
||||
JSON_Generator_State *state = arg->state;
|
||||
VALUE Vstate = arg->Vstate;
|
||||
|
||||
char *object_nl = state->object_nl;
|
||||
long object_nl_len = state->object_nl_len;
|
||||
char *indent = state->indent;
|
||||
long indent_len = state->indent_len;
|
||||
char *delim = FBUFFER_PTR(state->object_delim);
|
||||
long delim_len = FBUFFER_LEN(state->object_delim);
|
||||
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
||||
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
||||
long depth = state->depth;
|
||||
int j;
|
||||
VALUE key_to_s;
|
||||
|
||||
if (arg->iter > 0) fbuffer_append(buffer, delim, delim_len);
|
||||
if (object_nl) {
|
||||
fbuffer_append(buffer, object_nl, object_nl_len);
|
||||
}
|
||||
if (indent) {
|
||||
for (j = 0; j < depth; j++) {
|
||||
fbuffer_append(buffer, indent, indent_len);
|
||||
}
|
||||
}
|
||||
|
||||
key_to_s = rb_funcall(key, i_to_s, 0);
|
||||
Check_Type(key_to_s, T_STRING);
|
||||
generate_json(buffer, Vstate, state, key_to_s);
|
||||
fbuffer_append(buffer, delim2, delim2_len);
|
||||
generate_json(buffer, Vstate, state, val);
|
||||
|
||||
arg->iter++;
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
|
||||
{
|
||||
char *object_nl = state->object_nl;
|
||||
|
@ -726,36 +773,22 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
|
|||
char *indent = state->indent;
|
||||
long indent_len = state->indent_len;
|
||||
long max_nesting = state->max_nesting;
|
||||
char *delim = FBUFFER_PTR(state->object_delim);
|
||||
long delim_len = FBUFFER_LEN(state->object_delim);
|
||||
char *delim2 = FBUFFER_PTR(state->object_delim2);
|
||||
long delim2_len = FBUFFER_LEN(state->object_delim2);
|
||||
long depth = ++state->depth;
|
||||
int i, j;
|
||||
VALUE key, key_to_s, keys;
|
||||
int j;
|
||||
struct hash_foreach_arg arg;
|
||||
|
||||
if (max_nesting != 0 && depth > max_nesting) {
|
||||
fbuffer_free(buffer);
|
||||
rb_raise(eNestingError, "nesting of %ld is too deep", --state->depth);
|
||||
}
|
||||
fbuffer_append_char(buffer, '{');
|
||||
keys = rb_funcall(obj, i_keys, 0);
|
||||
for(i = 0; i < RARRAY_LEN(keys); i++) {
|
||||
if (i > 0) fbuffer_append(buffer, delim, delim_len);
|
||||
if (object_nl) {
|
||||
fbuffer_append(buffer, object_nl, object_nl_len);
|
||||
}
|
||||
if (indent) {
|
||||
for (j = 0; j < depth; j++) {
|
||||
fbuffer_append(buffer, indent, indent_len);
|
||||
}
|
||||
}
|
||||
key = rb_ary_entry(keys, i);
|
||||
key_to_s = rb_funcall(key, i_to_s, 0);
|
||||
Check_Type(key_to_s, T_STRING);
|
||||
generate_json(buffer, Vstate, state, key_to_s);
|
||||
fbuffer_append(buffer, delim2, delim2_len);
|
||||
generate_json(buffer, Vstate, state, rb_hash_aref(obj, key));
|
||||
}
|
||||
|
||||
arg.buffer = buffer;
|
||||
arg.state = state;
|
||||
arg.Vstate = Vstate;
|
||||
arg.iter = 0;
|
||||
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
||||
|
||||
depth = --state->depth;
|
||||
if (object_nl) {
|
||||
fbuffer_append(buffer, object_nl, object_nl_len);
|
||||
|
|
Загрузка…
Ссылка в новой задаче