11#include "../fbuffer/fbuffer.h"
22#include "generator.h"
33
4+ #ifndef RB_UNLIKELY
5+ #define RB_UNLIKELY (cond ) (cond)
6+ #endif
7+
48static VALUE mJSON , mExt , mGenerator , cState , mGeneratorMethods , mObject ,
59 mHash , mArray ,
610#ifdef RUBY_INTEGER_UNIFICATION
@@ -417,9 +421,6 @@ static void State_free(void *ptr)
417421 if (state -> space_before ) ruby_xfree (state -> space_before );
418422 if (state -> object_nl ) ruby_xfree (state -> object_nl );
419423 if (state -> array_nl ) ruby_xfree (state -> array_nl );
420- if (state -> array_delim ) fbuffer_free (state -> array_delim );
421- if (state -> object_delim ) fbuffer_free (state -> object_delim );
422- if (state -> object_delim2 ) fbuffer_free (state -> object_delim2 );
423424 ruby_xfree (state );
424425}
425426
@@ -432,9 +433,6 @@ static size_t State_memsize(const void *ptr)
432433 if (state -> space_before ) size += state -> space_before_len + 1 ;
433434 if (state -> object_nl ) size += state -> object_nl_len + 1 ;
434435 if (state -> array_nl ) size += state -> array_nl_len + 1 ;
435- if (state -> array_delim ) size += FBUFFER_CAPA (state -> array_delim );
436- if (state -> object_delim ) size += FBUFFER_CAPA (state -> object_delim );
437- if (state -> object_delim2 ) size += FBUFFER_CAPA (state -> object_delim2 );
438436 return size ;
439437}
440438
@@ -644,24 +642,16 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
644642 JSON_Generator_State * state = arg -> state ;
645643 VALUE Vstate = arg -> Vstate ;
646644
647- char * object_nl = state -> object_nl ;
648- long object_nl_len = state -> object_nl_len ;
649- char * indent = state -> indent ;
650- long indent_len = state -> indent_len ;
651- char * delim = FBUFFER_PTR (state -> object_delim );
652- long delim_len = FBUFFER_LEN (state -> object_delim );
653- char * delim2 = FBUFFER_PTR (state -> object_delim2 );
654- long delim2_len = FBUFFER_LEN (state -> object_delim2 );
655645 long depth = state -> depth ;
656646 int j ;
657647
658- if (arg -> iter > 0 ) fbuffer_append (buffer , delim , delim_len );
659- if (object_nl ) {
660- fbuffer_append (buffer , object_nl , object_nl_len );
648+ if (arg -> iter > 0 ) fbuffer_append_char (buffer , ',' );
649+ if (RB_UNLIKELY ( state -> object_nl ) ) {
650+ fbuffer_append (buffer , state -> object_nl , state -> object_nl_len );
661651 }
662- if (indent ) {
652+ if (RB_UNLIKELY ( state -> indent ) ) {
663653 for (j = 0 ; j < depth ; j ++ ) {
664- fbuffer_append (buffer , indent , indent_len );
654+ fbuffer_append (buffer , state -> indent , state -> indent_len );
665655 }
666656 }
667657
@@ -678,8 +668,10 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
678668 break ;
679669 }
680670
681- generate_json (buffer , Vstate , state , key_to_s );
682- fbuffer_append (buffer , delim2 , delim2_len );
671+ generate_json_string (buffer , Vstate , state , key_to_s );
672+ if (RB_UNLIKELY (state -> space_before )) fbuffer_append (buffer , state -> space_before , state -> space_before_len );
673+ fbuffer_append_char (buffer , ':' );
674+ if (RB_UNLIKELY (state -> space )) fbuffer_append (buffer , state -> space , state -> space_len );
683675 generate_json (buffer , Vstate , state , val );
684676
685677 arg -> iter ++ ;
@@ -688,10 +680,6 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
688680
689681static void generate_json_object (FBuffer * buffer , VALUE Vstate , JSON_Generator_State * state , VALUE obj )
690682{
691- char * object_nl = state -> object_nl ;
692- long object_nl_len = state -> object_nl_len ;
693- char * indent = state -> indent ;
694- long indent_len = state -> indent_len ;
695683 long max_nesting = state -> max_nesting ;
696684 long depth = ++ state -> depth ;
697685 int j ;
@@ -709,11 +697,11 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
709697 rb_hash_foreach (obj , json_object_i , (VALUE )& arg );
710698
711699 depth = -- state -> depth ;
712- if (object_nl ) {
713- fbuffer_append (buffer , object_nl , object_nl_len );
714- if (indent ) {
700+ if (RB_UNLIKELY ( state -> object_nl ) ) {
701+ fbuffer_append (buffer , state -> object_nl , state -> object_nl_len );
702+ if (RB_UNLIKELY ( state -> indent ) ) {
715703 for (j = 0 ; j < depth ; j ++ ) {
716- fbuffer_append (buffer , indent , indent_len );
704+ fbuffer_append (buffer , state -> indent , state -> indent_len );
717705 }
718706 }
719707 }
@@ -722,52 +710,51 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
722710
723711static void generate_json_array (FBuffer * buffer , VALUE Vstate , JSON_Generator_State * state , VALUE obj )
724712{
725- char * array_nl = state -> array_nl ;
726- long array_nl_len = state -> array_nl_len ;
727- char * indent = state -> indent ;
728- long indent_len = state -> indent_len ;
729713 long max_nesting = state -> max_nesting ;
730- char * delim = FBUFFER_PTR (state -> array_delim );
731- long delim_len = FBUFFER_LEN (state -> array_delim );
732714 long depth = ++ state -> depth ;
733715 int i , j ;
734716 if (max_nesting != 0 && depth > max_nesting ) {
735717 rb_raise (eNestingError , "nesting of %ld is too deep" , -- state -> depth );
736718 }
737719 fbuffer_append_char (buffer , '[' );
738- if (array_nl ) fbuffer_append (buffer , array_nl , array_nl_len );
720+ if (RB_UNLIKELY ( state -> array_nl )) fbuffer_append (buffer , state -> array_nl , state -> array_nl_len );
739721 for (i = 0 ; i < RARRAY_LEN (obj ); i ++ ) {
740- if (i > 0 ) fbuffer_append (buffer , delim , delim_len );
741- if (indent ) {
722+ if (i > 0 ) {
723+ fbuffer_append_char (buffer , ',' );
724+ if (RB_UNLIKELY (state -> array_nl )) fbuffer_append (buffer , state -> array_nl , state -> array_nl_len );
725+ }
726+ if (RB_UNLIKELY (state -> indent )) {
742727 for (j = 0 ; j < depth ; j ++ ) {
743- fbuffer_append (buffer , indent , indent_len );
728+ fbuffer_append (buffer , state -> indent , state -> indent_len );
744729 }
745730 }
746- generate_json (buffer , Vstate , state , rb_ary_entry (obj , i ));
731+ generate_json (buffer , Vstate , state , RARRAY_AREF (obj , i ));
747732 }
748733 state -> depth = -- depth ;
749- if (array_nl ) {
750- fbuffer_append (buffer , array_nl , array_nl_len );
751- if (indent ) {
734+ if (RB_UNLIKELY ( state -> array_nl ) ) {
735+ fbuffer_append (buffer , state -> array_nl , state -> array_nl_len );
736+ if (RB_UNLIKELY ( state -> indent ) ) {
752737 for (j = 0 ; j < depth ; j ++ ) {
753- fbuffer_append (buffer , indent , indent_len );
738+ fbuffer_append (buffer , state -> indent , state -> indent_len );
754739 }
755740 }
756741 }
757742 fbuffer_append_char (buffer , ']' );
758743}
759744
760- static int enc_utf8_compatible_p (rb_encoding * enc )
745+ static int usascii_encindex , utf8_encindex ;
746+
747+ static int enc_utf8_compatible_p (int enc_idx )
761748{
762- if (enc == rb_usascii_encoding () ) return 1 ;
763- if (enc == rb_utf8_encoding () ) return 1 ;
749+ if (enc_idx == usascii_encindex ) return 1 ;
750+ if (enc_idx == utf8_encindex ) return 1 ;
764751 return 0 ;
765752}
766753
767754static void generate_json_string (FBuffer * buffer , VALUE Vstate , JSON_Generator_State * state , VALUE obj )
768755{
769756 fbuffer_append_char (buffer , '"' );
770- if (!enc_utf8_compatible_p (rb_enc_get (obj ))) {
757+ if (!enc_utf8_compatible_p (RB_ENCODING_GET (obj ))) {
771758 obj = rb_str_export_to_enc (obj , rb_utf8_encoding ());
772759 }
773760 convert_UTF8_to_JSON (buffer , obj , state -> ascii_only , state -> script_safe );
@@ -827,35 +814,56 @@ static void generate_json_float(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
827814static void generate_json (FBuffer * buffer , VALUE Vstate , JSON_Generator_State * state , VALUE obj )
828815{
829816 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 ) {
817+ if (obj == Qnil ) {
838818 generate_json_null (buffer , Vstate , state , obj );
839819 } else if (obj == Qfalse ) {
840820 generate_json_false (buffer , Vstate , state , obj );
841821 } else if (obj == Qtrue ) {
842822 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 );
823+ } else if (RB_SPECIAL_CONST_P (obj )) {
824+ if (RB_FIXNUM_P (obj )) {
825+ generate_json_fixnum (buffer , Vstate , state , obj );
826+ } else if (RB_FLONUM_P (obj )) {
827+ generate_json_float (buffer , Vstate , state , obj );
828+ } else {
829+ goto general ;
830+ }
855831 } else {
856- tmp = rb_funcall (obj , i_to_s , 0 );
857- Check_Type (tmp , T_STRING );
858- generate_json_string (buffer , Vstate , state , tmp );
832+ VALUE klass = RBASIC_CLASS (obj );
833+ switch (RB_BUILTIN_TYPE (obj )) {
834+ case T_BIGNUM :
835+ generate_json_bignum (buffer , Vstate , state , obj );
836+ break ;
837+ case T_HASH :
838+ if (klass != rb_cHash ) goto general ;
839+ generate_json_object (buffer , Vstate , state , obj );
840+ break ;
841+ case T_ARRAY :
842+ if (klass != rb_cArray ) goto general ;
843+ generate_json_array (buffer , Vstate , state , obj );
844+ break ;
845+ case T_STRING :
846+ if (klass != rb_cString ) goto general ;
847+ generate_json_string (buffer , Vstate , state , obj );
848+ break ;
849+ case T_FLOAT :
850+ if (klass != rb_cFloat ) goto general ;
851+ generate_json_float (buffer , Vstate , state , obj );
852+ break ;
853+ default :
854+ general :
855+ if (state -> strict ) {
856+ rb_raise (eGeneratorError , "%" PRIsVALUE " not allowed in JSON" , RB_OBJ_STRING (CLASS_OF (obj )));
857+ } else if (rb_respond_to (obj , i_to_json )) {
858+ tmp = rb_funcall (obj , i_to_json , 1 , Vstate );
859+ Check_Type (tmp , T_STRING );
860+ fbuffer_append_str (buffer , tmp );
861+ } else {
862+ tmp = rb_funcall (obj , i_to_s , 0 );
863+ Check_Type (tmp , T_STRING );
864+ generate_json_string (buffer , Vstate , state , tmp );
865+ }
866+ }
859867 }
860868}
861869
@@ -865,28 +873,6 @@ static FBuffer *cState_prepare_buffer(VALUE self)
865873 GET_STATE (self );
866874 buffer = fbuffer_alloc (state -> buffer_initial_length );
867875
868- if (state -> object_delim ) {
869- fbuffer_clear (state -> object_delim );
870- } else {
871- state -> object_delim = fbuffer_alloc (16 );
872- }
873- fbuffer_append_char (state -> object_delim , ',' );
874- if (state -> object_delim2 ) {
875- fbuffer_clear (state -> object_delim2 );
876- } else {
877- state -> object_delim2 = fbuffer_alloc (16 );
878- }
879- if (state -> space_before ) fbuffer_append (state -> object_delim2 , state -> space_before , state -> space_before_len );
880- fbuffer_append_char (state -> object_delim2 , ':' );
881- if (state -> space ) fbuffer_append (state -> object_delim2 , state -> space , state -> space_len );
882-
883- if (state -> array_delim ) {
884- fbuffer_clear (state -> array_delim );
885- } else {
886- state -> array_delim = fbuffer_alloc (16 );
887- }
888- fbuffer_append_char (state -> array_delim , ',' );
889- if (state -> array_nl ) fbuffer_append (state -> array_delim , state -> array_nl , state -> array_nl_len );
890876 return buffer ;
891877}
892878
@@ -999,9 +985,6 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
999985 objState -> space_before = fstrndup (origState -> space_before , origState -> space_before_len );
1000986 objState -> object_nl = fstrndup (origState -> object_nl , origState -> object_nl_len );
1001987 objState -> array_nl = fstrndup (origState -> array_nl , origState -> array_nl_len );
1002- if (origState -> array_delim ) objState -> array_delim = fbuffer_dup (origState -> array_delim );
1003- if (origState -> object_delim ) objState -> object_delim = fbuffer_dup (origState -> object_delim );
1004- if (origState -> object_delim2 ) objState -> object_delim2 = fbuffer_dup (origState -> object_delim2 );
1005988 return obj ;
1006989}
1007990
@@ -1498,4 +1481,7 @@ void Init_generator(void)
14981481 i_match = rb_intern ("match" );
14991482 i_keys = rb_intern ("keys" );
15001483 i_dup = rb_intern ("dup" );
1484+
1485+ usascii_encindex = rb_usascii_encindex ();
1486+ utf8_encindex = rb_utf8_encindex ();
15011487}
0 commit comments