Skip to content

Commit 4f9180d

Browse files
mamebyroot
authored andcommitted
Use efficient object-type dispatching
Dispatching based on Ruby's VALUE structure is more efficient than simply cascaded "if ... else if ..." checks. This speeds up `JSON.generate` by about 5% in a benchmark.
1 parent c5d80f9 commit 4f9180d

File tree

1 file changed

+44
-23
lines changed

1 file changed

+44
-23
lines changed

ext/json/ext/generator/generator.c

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -827,35 +827,56 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
827827
static void generate_json(FBuffer *buffer, VALUE Vstate, JSON_Generator_State *state, VALUE obj)
828828
{
829829
VALUE tmp;
830-
VALUE klass = CLASS_OF(obj);
831-
if (klass == rb_cHash) {
832-
generate_json_object(buffer, Vstate, state, obj);
833-
} else if (klass == rb_cArray) {
834-
generate_json_array(buffer, Vstate, state, obj);
835-
} else if (klass == rb_cString) {
836-
generate_json_string(buffer, Vstate, state, obj);
837-
} else if (obj == Qnil) {
830+
if (obj == Qnil) {
838831
generate_json_null(buffer, Vstate, state, obj);
839832
} else if (obj == Qfalse) {
840833
generate_json_false(buffer, Vstate, state, obj);
841834
} else if (obj == Qtrue) {
842835
generate_json_true(buffer, Vstate, state, obj);
843-
} else if (FIXNUM_P(obj)) {
844-
generate_json_fixnum(buffer, Vstate, state, obj);
845-
} else if (RB_TYPE_P(obj, T_BIGNUM)) {
846-
generate_json_bignum(buffer, Vstate, state, obj);
847-
} else if (klass == rb_cFloat) {
848-
generate_json_float(buffer, Vstate, state, obj);
849-
} else if (state->strict) {
850-
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
851-
} else if (rb_respond_to(obj, i_to_json)) {
852-
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
853-
Check_Type(tmp, T_STRING);
854-
fbuffer_append_str(buffer, tmp);
836+
} else if (RB_SPECIAL_CONST_P(obj)) {
837+
if (RB_FIXNUM_P(obj)) {
838+
generate_json_fixnum(buffer, Vstate, state, obj);
839+
} else if (RB_FLONUM_P(obj)) {
840+
generate_json_float(buffer, Vstate, state, obj);
841+
} else {
842+
goto general;
843+
}
855844
} else {
856-
tmp = rb_funcall(obj, i_to_s, 0);
857-
Check_Type(tmp, T_STRING);
858-
generate_json_string(buffer, Vstate, state, tmp);
845+
VALUE klass = RBASIC_CLASS(obj);
846+
switch (RB_BUILTIN_TYPE(obj)) {
847+
case T_BIGNUM:
848+
generate_json_bignum(buffer, Vstate, state, obj);
849+
break;
850+
case T_HASH:
851+
if (klass != rb_cHash) goto general;
852+
generate_json_object(buffer, Vstate, state, obj);
853+
break;
854+
case T_ARRAY:
855+
if (klass != rb_cArray) goto general;
856+
generate_json_array(buffer, Vstate, state, obj);
857+
break;
858+
case T_STRING:
859+
if (klass != rb_cString) goto general;
860+
generate_json_string(buffer, Vstate, state, obj);
861+
break;
862+
case T_FLOAT:
863+
if (klass != rb_cFloat) goto general;
864+
generate_json_float(buffer, Vstate, state, obj);
865+
break;
866+
default:
867+
general:
868+
if (state->strict) {
869+
rb_raise(eGeneratorError, "%"PRIsVALUE" not allowed in JSON", RB_OBJ_STRING(CLASS_OF(obj)));
870+
} else if (rb_respond_to(obj, i_to_json)) {
871+
tmp = rb_funcall(obj, i_to_json, 1, Vstate);
872+
Check_Type(tmp, T_STRING);
873+
fbuffer_append_str(buffer, tmp);
874+
} else {
875+
tmp = rb_funcall(obj, i_to_s, 0);
876+
Check_Type(tmp, T_STRING);
877+
generate_json_string(buffer, Vstate, state, tmp);
878+
}
879+
}
859880
}
860881
}
861882

0 commit comments

Comments
 (0)