json 2.18.0 → 2.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +35 -1
- data/ext/json/ext/fbuffer/fbuffer.h +23 -19
- data/ext/json/ext/generator/extconf.rb +2 -0
- data/ext/json/ext/generator/generator.c +101 -325
- data/ext/json/ext/json.h +19 -0
- data/ext/json/ext/parser/extconf.rb +4 -0
- data/ext/json/ext/parser/parser.c +165 -135
- data/ext/json/ext/simd/simd.h +28 -11
- data/ext/json/ext/vendor/fpconv.c +1 -1
- data/lib/json/common.rb +41 -10
- data/lib/json/ext/generator/state.rb +1 -1
- data/lib/json/truffle_ruby/generator.rb +21 -9
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +35 -2
- metadata +2 -2
|
@@ -63,6 +63,8 @@ struct generate_json_data {
|
|
|
63
63
|
long depth;
|
|
64
64
|
};
|
|
65
65
|
|
|
66
|
+
static SIMD_Implementation simd_impl;
|
|
67
|
+
|
|
66
68
|
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
|
67
69
|
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
|
|
68
70
|
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
@@ -72,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
|
|
|
72
74
|
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
73
75
|
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
74
76
|
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
75
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
76
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
77
|
-
#endif
|
|
78
77
|
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
79
78
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
80
79
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
@@ -155,8 +154,6 @@ static const unsigned char escape_table_basic[256] = {
|
|
|
155
154
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
156
155
|
};
|
|
157
156
|
|
|
158
|
-
static unsigned char (*search_escape_basic_impl)(search_state *);
|
|
159
|
-
|
|
160
157
|
static inline unsigned char search_escape_basic(search_state *search)
|
|
161
158
|
{
|
|
162
159
|
while (search->ptr < search->end) {
|
|
@@ -212,11 +209,39 @@ ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
|
|
|
212
209
|
* Everything else (should be UTF-8) is just passed through and
|
|
213
210
|
* appended to the result.
|
|
214
211
|
*/
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
#if defined(HAVE_SIMD_NEON)
|
|
215
|
+
static inline unsigned char search_escape_basic_neon(search_state *search);
|
|
216
|
+
#elif defined(HAVE_SIMD_SSE2)
|
|
217
|
+
static inline unsigned char search_escape_basic_sse2(search_state *search);
|
|
218
|
+
#endif
|
|
219
|
+
|
|
220
|
+
static inline unsigned char search_escape_basic(search_state *search);
|
|
221
|
+
|
|
215
222
|
static inline void convert_UTF8_to_JSON(search_state *search)
|
|
216
223
|
{
|
|
217
|
-
|
|
224
|
+
#ifdef HAVE_SIMD
|
|
225
|
+
#if defined(HAVE_SIMD_NEON)
|
|
226
|
+
while (search_escape_basic_neon(search)) {
|
|
227
|
+
escape_UTF8_char_basic(search);
|
|
228
|
+
}
|
|
229
|
+
#elif defined(HAVE_SIMD_SSE2)
|
|
230
|
+
if (simd_impl == SIMD_SSE2) {
|
|
231
|
+
while (search_escape_basic_sse2(search)) {
|
|
232
|
+
escape_UTF8_char_basic(search);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
while (search_escape_basic(search)) {
|
|
218
237
|
escape_UTF8_char_basic(search);
|
|
219
238
|
}
|
|
239
|
+
#endif
|
|
240
|
+
#else
|
|
241
|
+
while (search_escape_basic(search)) {
|
|
242
|
+
escape_UTF8_char_basic(search);
|
|
243
|
+
}
|
|
244
|
+
#endif /* HAVE_SIMD */
|
|
220
245
|
}
|
|
221
246
|
|
|
222
247
|
static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
|
|
@@ -260,6 +285,8 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
|
|
|
260
285
|
|
|
261
286
|
ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
|
|
262
287
|
{
|
|
288
|
+
RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
|
|
289
|
+
|
|
263
290
|
// Flush the buffer so everything up until the last 'len' characters are unflushed.
|
|
264
291
|
search_flush(search);
|
|
265
292
|
|
|
@@ -269,12 +296,18 @@ ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned
|
|
|
269
296
|
char *s = (buf->ptr + buf->len);
|
|
270
297
|
|
|
271
298
|
// Pad the buffer with dummy characters that won't need escaping.
|
|
272
|
-
// This seem
|
|
273
|
-
|
|
299
|
+
// This seem wasteful at first sight, but memset of vector length is very fast.
|
|
300
|
+
// This is a space as it can be directly represented as an immediate on AArch64.
|
|
301
|
+
memset(s, ' ', vec_len);
|
|
274
302
|
|
|
275
303
|
// Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
|
|
276
304
|
// to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
|
|
277
|
-
|
|
305
|
+
if (vec_len == 16) {
|
|
306
|
+
RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD);
|
|
307
|
+
json_fast_memcpy16(s, search->ptr, len);
|
|
308
|
+
} else {
|
|
309
|
+
MEMCPY(s, search->ptr, char, len);
|
|
310
|
+
}
|
|
278
311
|
|
|
279
312
|
return s;
|
|
280
313
|
}
|
|
@@ -667,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
|
|
|
667
700
|
}
|
|
668
701
|
}
|
|
669
702
|
|
|
670
|
-
/*
|
|
671
|
-
* Document-module: JSON::Ext::Generator
|
|
672
|
-
*
|
|
673
|
-
* This is the JSON generator implemented as a C extension. It can be
|
|
674
|
-
* configured to be used by setting
|
|
675
|
-
*
|
|
676
|
-
* JSON.generator = JSON::Ext::Generator
|
|
677
|
-
*
|
|
678
|
-
* with the method generator= in JSON.
|
|
679
|
-
*
|
|
680
|
-
*/
|
|
681
|
-
|
|
682
|
-
/* Explanation of the following: that's the only way to not pollute
|
|
683
|
-
* standard library's docs with GeneratorMethods::<ClassName> which
|
|
684
|
-
* are uninformative and take a large place in a list of classes
|
|
685
|
-
*/
|
|
686
|
-
|
|
687
|
-
/*
|
|
688
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
|
689
|
-
* :nodoc:
|
|
690
|
-
*/
|
|
691
|
-
|
|
692
|
-
/*
|
|
693
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
|
694
|
-
* :nodoc:
|
|
695
|
-
*/
|
|
696
|
-
|
|
697
|
-
/*
|
|
698
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
|
699
|
-
* :nodoc:
|
|
700
|
-
*/
|
|
701
|
-
|
|
702
|
-
/*
|
|
703
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
|
704
|
-
* :nodoc:
|
|
705
|
-
*/
|
|
706
|
-
|
|
707
|
-
/*
|
|
708
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
|
709
|
-
* :nodoc:
|
|
710
|
-
*/
|
|
711
|
-
|
|
712
|
-
/*
|
|
713
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
|
714
|
-
* :nodoc:
|
|
715
|
-
*/
|
|
716
|
-
|
|
717
|
-
/*
|
|
718
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
|
719
|
-
* :nodoc:
|
|
720
|
-
*/
|
|
721
|
-
|
|
722
|
-
/*
|
|
723
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
|
724
|
-
* :nodoc:
|
|
725
|
-
*/
|
|
726
|
-
|
|
727
|
-
/*
|
|
728
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
|
729
|
-
* :nodoc:
|
|
730
|
-
*/
|
|
731
|
-
|
|
732
|
-
/*
|
|
733
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
|
734
|
-
* :nodoc:
|
|
735
|
-
*/
|
|
736
|
-
|
|
737
|
-
/*
|
|
738
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
|
739
|
-
* :nodoc:
|
|
740
|
-
*/
|
|
741
|
-
|
|
742
|
-
/*
|
|
743
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
|
744
|
-
* :nodoc:
|
|
745
|
-
*/
|
|
746
|
-
|
|
747
|
-
/*
|
|
748
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
|
749
|
-
* :nodoc:
|
|
750
|
-
*/
|
|
751
|
-
|
|
752
|
-
/*
|
|
753
|
-
* call-seq: to_json(state = nil)
|
|
754
|
-
*
|
|
755
|
-
* Returns a JSON string containing a JSON object, that is generated from
|
|
756
|
-
* this Hash instance.
|
|
757
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
758
|
-
* produced JSON string output further.
|
|
759
|
-
*/
|
|
760
|
-
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
761
|
-
{
|
|
762
|
-
rb_check_arity(argc, 0, 1);
|
|
763
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
764
|
-
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
/*
|
|
768
|
-
* call-seq: to_json(state = nil)
|
|
769
|
-
*
|
|
770
|
-
* Returns a JSON string containing a JSON array, that is generated from
|
|
771
|
-
* this Array instance.
|
|
772
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
773
|
-
* produced JSON string output further.
|
|
774
|
-
*/
|
|
775
|
-
static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
|
|
776
|
-
{
|
|
777
|
-
rb_check_arity(argc, 0, 1);
|
|
778
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
779
|
-
return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
783
|
-
/*
|
|
784
|
-
* call-seq: to_json(*)
|
|
785
|
-
*
|
|
786
|
-
* Returns a JSON string representation for this Integer number.
|
|
787
|
-
*/
|
|
788
|
-
static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
|
|
789
|
-
{
|
|
790
|
-
rb_check_arity(argc, 0, 1);
|
|
791
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
792
|
-
return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
#else
|
|
796
|
-
/*
|
|
797
|
-
* call-seq: to_json(*)
|
|
798
|
-
*
|
|
799
|
-
* Returns a JSON string representation for this Integer number.
|
|
800
|
-
*/
|
|
801
|
-
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
802
|
-
{
|
|
803
|
-
rb_check_arity(argc, 0, 1);
|
|
804
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
805
|
-
return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
/*
|
|
809
|
-
* call-seq: to_json(*)
|
|
810
|
-
*
|
|
811
|
-
* Returns a JSON string representation for this Integer number.
|
|
812
|
-
*/
|
|
813
|
-
static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
|
|
814
|
-
{
|
|
815
|
-
rb_check_arity(argc, 0, 1);
|
|
816
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
817
|
-
return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
|
|
818
|
-
}
|
|
819
|
-
#endif
|
|
820
|
-
|
|
821
|
-
/*
|
|
822
|
-
* call-seq: to_json(*)
|
|
823
|
-
*
|
|
824
|
-
* Returns a JSON string representation for this Float number.
|
|
825
|
-
*/
|
|
826
|
-
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
827
|
-
{
|
|
828
|
-
rb_check_arity(argc, 0, 1);
|
|
829
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
830
|
-
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
/*
|
|
834
|
-
* call-seq: to_json(*)
|
|
835
|
-
*
|
|
836
|
-
* This string should be encoded with UTF-8 A call to this method
|
|
837
|
-
* returns a JSON string encoded with UTF16 big endian characters as
|
|
838
|
-
* \u????.
|
|
839
|
-
*/
|
|
840
|
-
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
|
841
|
-
{
|
|
842
|
-
rb_check_arity(argc, 0, 1);
|
|
843
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
844
|
-
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
/*
|
|
848
|
-
* call-seq: to_json(*)
|
|
849
|
-
*
|
|
850
|
-
* Returns a JSON string for true: 'true'.
|
|
851
|
-
*/
|
|
852
|
-
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
853
|
-
{
|
|
854
|
-
rb_check_arity(argc, 0, 1);
|
|
855
|
-
return rb_utf8_str_new("true", 4);
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
/*
|
|
859
|
-
* call-seq: to_json(*)
|
|
860
|
-
*
|
|
861
|
-
* Returns a JSON string for false: 'false'.
|
|
862
|
-
*/
|
|
863
|
-
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
864
|
-
{
|
|
865
|
-
rb_check_arity(argc, 0, 1);
|
|
866
|
-
return rb_utf8_str_new("false", 5);
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
/*
|
|
870
|
-
* call-seq: to_json(*)
|
|
871
|
-
*
|
|
872
|
-
* Returns a JSON string for nil: 'null'.
|
|
873
|
-
*/
|
|
874
|
-
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
875
|
-
{
|
|
876
|
-
rb_check_arity(argc, 0, 1);
|
|
877
|
-
return rb_utf8_str_new("null", 4);
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/*
|
|
881
|
-
* call-seq: to_json(*)
|
|
882
|
-
*
|
|
883
|
-
* Converts this object to a string (calling #to_s), converts
|
|
884
|
-
* it to a JSON string, and returns the result. This is a fallback, if no
|
|
885
|
-
* special method #to_json was defined for some object.
|
|
886
|
-
*/
|
|
887
|
-
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
888
|
-
{
|
|
889
|
-
VALUE state;
|
|
890
|
-
VALUE string = rb_funcall(self, i_to_s, 0);
|
|
891
|
-
rb_scan_args(argc, argv, "01", &state);
|
|
892
|
-
Check_Type(string, T_STRING);
|
|
893
|
-
state = cState_from_state_s(cState, state);
|
|
894
|
-
return cState_partial_generate(state, string, generate_json_string, Qfalse);
|
|
895
|
-
}
|
|
896
|
-
|
|
897
703
|
static void State_mark(void *ptr)
|
|
898
704
|
{
|
|
899
705
|
JSON_Generator_State *state = ptr;
|
|
@@ -916,27 +722,20 @@ static void State_compact(void *ptr)
|
|
|
916
722
|
state->as_json = rb_gc_location(state->as_json);
|
|
917
723
|
}
|
|
918
724
|
|
|
919
|
-
static void State_free(void *ptr)
|
|
920
|
-
{
|
|
921
|
-
JSON_Generator_State *state = ptr;
|
|
922
|
-
ruby_xfree(state);
|
|
923
|
-
}
|
|
924
|
-
|
|
925
725
|
static size_t State_memsize(const void *ptr)
|
|
926
726
|
{
|
|
927
727
|
return sizeof(JSON_Generator_State);
|
|
928
728
|
}
|
|
929
729
|
|
|
930
730
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
931
|
-
"JSON/Generator/State",
|
|
932
|
-
{
|
|
731
|
+
.wrap_struct_name = "JSON/Generator/State",
|
|
732
|
+
.function = {
|
|
933
733
|
.dmark = State_mark,
|
|
934
|
-
.dfree =
|
|
734
|
+
.dfree = RUBY_DEFAULT_FREE,
|
|
935
735
|
.dsize = State_memsize,
|
|
936
736
|
.dcompact = State_compact,
|
|
937
737
|
},
|
|
938
|
-
|
|
939
|
-
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
738
|
+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
|
|
940
739
|
};
|
|
941
740
|
|
|
942
741
|
static void state_init(JSON_Generator_State *state)
|
|
@@ -1091,6 +890,7 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
|
|
|
1091
890
|
search.matches_mask = 0;
|
|
1092
891
|
search.has_matches = false;
|
|
1093
892
|
search.chunk_base = NULL;
|
|
893
|
+
search.chunk_end = NULL;
|
|
1094
894
|
#endif /* HAVE_SIMD */
|
|
1095
895
|
|
|
1096
896
|
switch (rb_enc_str_coderange(obj)) {
|
|
@@ -1337,18 +1137,8 @@ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1337
1137
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1338
1138
|
{
|
|
1339
1139
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
|
1340
|
-
fbuffer_append_str(buffer, tmp);
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
1344
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1345
|
-
{
|
|
1346
|
-
if (FIXNUM_P(obj))
|
|
1347
|
-
generate_json_fixnum(buffer, data, obj);
|
|
1348
|
-
else
|
|
1349
|
-
generate_json_bignum(buffer, data, obj);
|
|
1140
|
+
fbuffer_append_str(buffer, StringValue(tmp));
|
|
1350
1141
|
}
|
|
1351
|
-
#endif
|
|
1352
1142
|
|
|
1353
1143
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1354
1144
|
{
|
|
@@ -1393,7 +1183,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
|
|
|
1393
1183
|
fbuffer_append_str(buffer, fragment);
|
|
1394
1184
|
}
|
|
1395
1185
|
|
|
1396
|
-
static void
|
|
1186
|
+
static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
|
|
1397
1187
|
{
|
|
1398
1188
|
bool as_json_called = false;
|
|
1399
1189
|
start:
|
|
@@ -1420,15 +1210,15 @@ start:
|
|
|
1420
1210
|
generate_json_bignum(buffer, data, obj);
|
|
1421
1211
|
break;
|
|
1422
1212
|
case T_HASH:
|
|
1423
|
-
if (klass != rb_cHash) goto general;
|
|
1213
|
+
if (fallback && klass != rb_cHash) goto general;
|
|
1424
1214
|
generate_json_object(buffer, data, obj);
|
|
1425
1215
|
break;
|
|
1426
1216
|
case T_ARRAY:
|
|
1427
|
-
if (klass != rb_cArray) goto general;
|
|
1217
|
+
if (fallback && klass != rb_cArray) goto general;
|
|
1428
1218
|
generate_json_array(buffer, data, obj);
|
|
1429
1219
|
break;
|
|
1430
1220
|
case T_STRING:
|
|
1431
|
-
if (klass != rb_cString) goto general;
|
|
1221
|
+
if (fallback && klass != rb_cString) goto general;
|
|
1432
1222
|
|
|
1433
1223
|
if (RB_LIKELY(valid_json_string_p(obj))) {
|
|
1434
1224
|
raw_generate_json_string(buffer, data, obj);
|
|
@@ -1444,7 +1234,7 @@ start:
|
|
|
1444
1234
|
generate_json_symbol(buffer, data, obj);
|
|
1445
1235
|
break;
|
|
1446
1236
|
case T_FLOAT:
|
|
1447
|
-
if (klass != rb_cFloat) goto general;
|
|
1237
|
+
if (fallback && klass != rb_cFloat) goto general;
|
|
1448
1238
|
generate_json_float(buffer, data, obj);
|
|
1449
1239
|
break;
|
|
1450
1240
|
case T_STRUCT:
|
|
@@ -1468,6 +1258,16 @@ start:
|
|
|
1468
1258
|
}
|
|
1469
1259
|
}
|
|
1470
1260
|
|
|
1261
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1262
|
+
{
|
|
1263
|
+
generate_json_general(buffer, data, obj, true);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1267
|
+
{
|
|
1268
|
+
generate_json_general(buffer, data, obj, false);
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1471
1271
|
static VALUE generate_json_try(VALUE d)
|
|
1472
1272
|
{
|
|
1473
1273
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
@@ -1485,7 +1285,7 @@ static VALUE generate_json_ensure(VALUE d)
|
|
|
1485
1285
|
return Qundef;
|
|
1486
1286
|
}
|
|
1487
1287
|
|
|
1488
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1288
|
+
static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1489
1289
|
{
|
|
1490
1290
|
GET_STATE(self);
|
|
1491
1291
|
|
|
@@ -1522,6 +1322,15 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
|
|
1522
1322
|
return cState_partial_generate(self, obj, generate_json, io);
|
|
1523
1323
|
}
|
|
1524
1324
|
|
|
1325
|
+
/* :nodoc: */
|
|
1326
|
+
static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
|
|
1327
|
+
{
|
|
1328
|
+
rb_check_arity(argc, 1, 2);
|
|
1329
|
+
VALUE obj = argv[0];
|
|
1330
|
+
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1331
|
+
return cState_partial_generate(self, obj, generate_json_no_fallback, io);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1525
1334
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
1526
1335
|
{
|
|
1527
1336
|
rb_warn("The json gem extension was loaded with the stdlib ruby code. You should upgrade rubygems with `gem update --system`");
|
|
@@ -1759,6 +1568,17 @@ static long long_config(VALUE num)
|
|
|
1759
1568
|
return RTEST(num) ? FIX2LONG(num) : 0;
|
|
1760
1569
|
}
|
|
1761
1570
|
|
|
1571
|
+
// depth must never be negative; reject early with a clear error.
|
|
1572
|
+
static long depth_config(VALUE num)
|
|
1573
|
+
{
|
|
1574
|
+
if (!RTEST(num)) return 0;
|
|
1575
|
+
long d = NUM2LONG(num);
|
|
1576
|
+
if (RB_UNLIKELY(d < 0)) {
|
|
1577
|
+
rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
|
|
1578
|
+
}
|
|
1579
|
+
return d;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1762
1582
|
/*
|
|
1763
1583
|
* call-seq: max_nesting=(depth)
|
|
1764
1584
|
*
|
|
@@ -1915,7 +1735,7 @@ static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
|
1915
1735
|
{
|
|
1916
1736
|
rb_check_frozen(self);
|
|
1917
1737
|
GET_STATE(self);
|
|
1918
|
-
state->depth =
|
|
1738
|
+
state->depth = depth_config(depth);
|
|
1919
1739
|
return Qnil;
|
|
1920
1740
|
}
|
|
1921
1741
|
|
|
@@ -1980,7 +1800,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1980
1800
|
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
|
1981
1801
|
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
|
1982
1802
|
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
|
1983
|
-
else if (key == sym_depth) { state->depth =
|
|
1803
|
+
else if (key == sym_depth) { state->depth = depth_config(val); }
|
|
1984
1804
|
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
|
1985
1805
|
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
|
1986
1806
|
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
|
@@ -2020,7 +1840,7 @@ static VALUE cState_configure(VALUE self, VALUE opts)
|
|
|
2020
1840
|
return self;
|
|
2021
1841
|
}
|
|
2022
1842
|
|
|
2023
|
-
static VALUE
|
|
1843
|
+
static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
|
|
2024
1844
|
{
|
|
2025
1845
|
JSON_Generator_State state = {0};
|
|
2026
1846
|
state_init(&state);
|
|
@@ -2038,14 +1858,21 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
|
2038
1858
|
.state = &state,
|
|
2039
1859
|
.depth = state.depth,
|
|
2040
1860
|
.obj = obj,
|
|
2041
|
-
.func =
|
|
1861
|
+
.func = func,
|
|
2042
1862
|
};
|
|
2043
1863
|
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
2044
1864
|
}
|
|
2045
1865
|
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
1866
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1867
|
+
{
|
|
1868
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json);
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1872
|
+
{
|
|
1873
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
|
|
1874
|
+
}
|
|
1875
|
+
|
|
2049
1876
|
void Init_generator(void)
|
|
2050
1877
|
{
|
|
2051
1878
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
@@ -2110,46 +1937,12 @@ void Init_generator(void)
|
|
|
2110
1937
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
2111
1938
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2112
1939
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
1940
|
+
rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
|
|
2113
1941
|
|
|
2114
1942
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2115
1943
|
|
|
2116
1944
|
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
|
|
2117
|
-
|
|
2118
|
-
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
|
2119
|
-
|
|
2120
|
-
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
|
2121
|
-
rb_define_method(mObject, "to_json", mObject_to_json, -1);
|
|
2122
|
-
|
|
2123
|
-
VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
|
|
2124
|
-
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
2125
|
-
|
|
2126
|
-
VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
2127
|
-
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
|
2128
|
-
|
|
2129
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
2130
|
-
VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
|
2131
|
-
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
|
2132
|
-
#else
|
|
2133
|
-
VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
2134
|
-
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
2135
|
-
|
|
2136
|
-
VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
2137
|
-
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
2138
|
-
#endif
|
|
2139
|
-
VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
2140
|
-
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
2141
|
-
|
|
2142
|
-
VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
2143
|
-
rb_define_method(mString, "to_json", mString_to_json, -1);
|
|
2144
|
-
|
|
2145
|
-
VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
|
|
2146
|
-
rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
|
|
2147
|
-
|
|
2148
|
-
VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
|
|
2149
|
-
rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
|
|
2150
|
-
|
|
2151
|
-
VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
2152
|
-
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1945
|
+
rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
|
|
2153
1946
|
|
|
2154
1947
|
rb_global_variable(&Encoding_UTF_8);
|
|
2155
1948
|
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
|
|
@@ -2181,22 +1974,5 @@ void Init_generator(void)
|
|
|
2181
1974
|
|
|
2182
1975
|
rb_require("json/ext/generator/state");
|
|
2183
1976
|
|
|
2184
|
-
|
|
2185
|
-
switch (find_simd_implementation()) {
|
|
2186
|
-
#ifdef HAVE_SIMD
|
|
2187
|
-
#ifdef HAVE_SIMD_NEON
|
|
2188
|
-
case SIMD_NEON:
|
|
2189
|
-
search_escape_basic_impl = search_escape_basic_neon;
|
|
2190
|
-
break;
|
|
2191
|
-
#endif /* HAVE_SIMD_NEON */
|
|
2192
|
-
#ifdef HAVE_SIMD_SSE2
|
|
2193
|
-
case SIMD_SSE2:
|
|
2194
|
-
search_escape_basic_impl = search_escape_basic_sse2;
|
|
2195
|
-
break;
|
|
2196
|
-
#endif /* HAVE_SIMD_SSE2 */
|
|
2197
|
-
#endif /* HAVE_SIMD */
|
|
2198
|
-
default:
|
|
2199
|
-
search_escape_basic_impl = search_escape_basic;
|
|
2200
|
-
break;
|
|
2201
|
-
}
|
|
1977
|
+
simd_impl = find_simd_implementation();
|
|
2202
1978
|
}
|
data/ext/json/ext/json.h
CHANGED
|
@@ -5,6 +5,10 @@
|
|
|
5
5
|
#include "ruby/encoding.h"
|
|
6
6
|
#include <stdint.h>
|
|
7
7
|
|
|
8
|
+
#ifndef RBIMPL_ASSERT_OR_ASSUME
|
|
9
|
+
# define RBIMPL_ASSERT_OR_ASSUME(x)
|
|
10
|
+
#endif
|
|
11
|
+
|
|
8
12
|
#if defined(RUBY_DEBUG) && RUBY_DEBUG
|
|
9
13
|
# define JSON_ASSERT RUBY_ASSERT
|
|
10
14
|
#else
|
|
@@ -50,9 +54,24 @@ typedef unsigned char _Bool;
|
|
|
50
54
|
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
51
55
|
#endif
|
|
52
56
|
|
|
57
|
+
#ifdef RUBY_TYPED_EMBEDDABLE
|
|
58
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
59
|
+
#else
|
|
60
|
+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
|
|
61
|
+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
|
|
62
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
63
|
+
# else
|
|
64
|
+
# define RUBY_TYPED_EMBEDDABLE 0
|
|
65
|
+
# endif
|
|
66
|
+
#endif
|
|
67
|
+
|
|
53
68
|
#ifndef NORETURN
|
|
69
|
+
#if defined(__has_attribute) && __has_attribute(noreturn)
|
|
70
|
+
#define NORETURN(x) __attribute__((noreturn)) x
|
|
71
|
+
#else
|
|
54
72
|
#define NORETURN(x) x
|
|
55
73
|
#endif
|
|
74
|
+
#endif
|
|
56
75
|
|
|
57
76
|
#ifndef NOINLINE
|
|
58
77
|
#if defined(__has_attribute) && __has_attribute(noinline)
|
|
@@ -7,6 +7,10 @@ have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
|
|
|
7
7
|
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
|
|
8
8
|
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
|
|
9
9
|
|
|
10
|
+
if RUBY_ENGINE == "ruby"
|
|
11
|
+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
append_cflags("-std=c99")
|
|
11
15
|
|
|
12
16
|
if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
|