json 2.14.1 → 2.19.3
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 +68 -1
- data/LEGAL +12 -0
- data/README.md +19 -1
- data/ext/json/ext/fbuffer/fbuffer.h +32 -77
- data/ext/json/ext/generator/extconf.rb +1 -1
- data/ext/json/ext/generator/generator.c +295 -471
- data/ext/json/ext/json.h +105 -0
- data/ext/json/ext/parser/extconf.rb +2 -1
- data/ext/json/ext/parser/parser.c +617 -477
- data/ext/json/ext/simd/simd.h +42 -22
- data/ext/json/ext/vendor/fpconv.c +13 -12
- data/ext/json/ext/vendor/ryu.h +819 -0
- data/lib/json/common.rb +69 -26
- data/lib/json/ext/generator/state.rb +5 -1
- data/lib/json/truffle_ruby/generator.rb +86 -34
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +33 -0
- metadata +4 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#include "
|
|
1
|
+
#include "../json.h"
|
|
2
2
|
#include "../fbuffer/fbuffer.h"
|
|
3
3
|
#include "../vendor/fpconv.c"
|
|
4
4
|
|
|
@@ -29,19 +29,16 @@ typedef struct JSON_Generator_StateStruct {
|
|
|
29
29
|
|
|
30
30
|
enum duplicate_key_action on_duplicate_key;
|
|
31
31
|
|
|
32
|
+
bool as_json_single_arg;
|
|
32
33
|
bool allow_nan;
|
|
33
34
|
bool ascii_only;
|
|
34
35
|
bool script_safe;
|
|
35
36
|
bool strict;
|
|
36
37
|
} JSON_Generator_State;
|
|
37
38
|
|
|
38
|
-
#ifndef RB_UNLIKELY
|
|
39
|
-
#define RB_UNLIKELY(cond) (cond)
|
|
40
|
-
#endif
|
|
41
|
-
|
|
42
39
|
static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
|
|
43
40
|
|
|
44
|
-
static ID i_to_s, i_to_json, i_new,
|
|
41
|
+
static ID i_to_s, i_to_json, i_new, i_encode;
|
|
45
42
|
static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
|
|
46
43
|
sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
|
|
47
44
|
|
|
@@ -63,8 +60,11 @@ struct generate_json_data {
|
|
|
63
60
|
JSON_Generator_State *state;
|
|
64
61
|
VALUE obj;
|
|
65
62
|
generator_func func;
|
|
63
|
+
long depth;
|
|
66
64
|
};
|
|
67
65
|
|
|
66
|
+
static SIMD_Implementation simd_impl;
|
|
67
|
+
|
|
68
68
|
static VALUE cState_from_state_s(VALUE self, VALUE opts);
|
|
69
69
|
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
|
|
70
70
|
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
@@ -74,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
|
|
|
74
74
|
static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
75
75
|
static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
76
76
|
static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
77
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
78
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
79
|
-
#endif
|
|
80
77
|
static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
81
78
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
82
79
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
|
|
@@ -84,23 +81,18 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
|
|
|
84
81
|
|
|
85
82
|
static int usascii_encindex, utf8_encindex, binary_encindex;
|
|
86
83
|
|
|
87
|
-
|
|
88
|
-
RBIMPL_ATTR_NORETURN()
|
|
89
|
-
#endif
|
|
90
|
-
static void raise_generator_error_str(VALUE invalid_object, VALUE str)
|
|
84
|
+
NORETURN(static void) raise_generator_error_str(VALUE invalid_object, VALUE str)
|
|
91
85
|
{
|
|
86
|
+
rb_enc_associate_index(str, utf8_encindex);
|
|
92
87
|
VALUE exc = rb_exc_new_str(eGeneratorError, str);
|
|
93
88
|
rb_ivar_set(exc, rb_intern("@invalid_object"), invalid_object);
|
|
94
89
|
rb_exc_raise(exc);
|
|
95
90
|
}
|
|
96
91
|
|
|
97
|
-
#ifdef RBIMPL_ATTR_NORETURN
|
|
98
|
-
RBIMPL_ATTR_NORETURN()
|
|
99
|
-
#endif
|
|
100
92
|
#ifdef RBIMPL_ATTR_FORMAT
|
|
101
93
|
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
|
|
102
94
|
#endif
|
|
103
|
-
static void raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
|
95
|
+
NORETURN(static void) raise_generator_error(VALUE invalid_object, const char *fmt, ...)
|
|
104
96
|
{
|
|
105
97
|
va_list args;
|
|
106
98
|
va_start(args, fmt);
|
|
@@ -135,13 +127,7 @@ typedef struct _search_state {
|
|
|
135
127
|
#endif /* HAVE_SIMD */
|
|
136
128
|
} search_state;
|
|
137
129
|
|
|
138
|
-
|
|
139
|
-
#define FORCE_INLINE __attribute__((always_inline))
|
|
140
|
-
#else
|
|
141
|
-
#define FORCE_INLINE
|
|
142
|
-
#endif
|
|
143
|
-
|
|
144
|
-
static inline FORCE_INLINE void search_flush(search_state *search)
|
|
130
|
+
ALWAYS_INLINE(static) void search_flush(search_state *search)
|
|
145
131
|
{
|
|
146
132
|
// Do not remove this conditional without profiling, specifically escape-heavy text.
|
|
147
133
|
// escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
|
|
@@ -168,8 +154,6 @@ static const unsigned char escape_table_basic[256] = {
|
|
|
168
154
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
169
155
|
};
|
|
170
156
|
|
|
171
|
-
static unsigned char (*search_escape_basic_impl)(search_state *);
|
|
172
|
-
|
|
173
157
|
static inline unsigned char search_escape_basic(search_state *search)
|
|
174
158
|
{
|
|
175
159
|
while (search->ptr < search->end) {
|
|
@@ -184,7 +168,7 @@ static inline unsigned char search_escape_basic(search_state *search)
|
|
|
184
168
|
return 0;
|
|
185
169
|
}
|
|
186
170
|
|
|
187
|
-
static
|
|
171
|
+
ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
|
|
188
172
|
{
|
|
189
173
|
const unsigned char ch = (unsigned char)*search->ptr;
|
|
190
174
|
switch (ch) {
|
|
@@ -225,11 +209,39 @@ static inline FORCE_INLINE void escape_UTF8_char_basic(search_state *search)
|
|
|
225
209
|
* Everything else (should be UTF-8) is just passed through and
|
|
226
210
|
* appended to the result.
|
|
227
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
|
+
|
|
228
222
|
static inline void convert_UTF8_to_JSON(search_state *search)
|
|
229
223
|
{
|
|
230
|
-
|
|
224
|
+
#ifdef HAVE_SIMD
|
|
225
|
+
#if defined(HAVE_SIMD_NEON)
|
|
226
|
+
while (search_escape_basic_neon(search)) {
|
|
231
227
|
escape_UTF8_char_basic(search);
|
|
232
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)) {
|
|
237
|
+
escape_UTF8_char_basic(search);
|
|
238
|
+
}
|
|
239
|
+
#endif
|
|
240
|
+
#else
|
|
241
|
+
while (search_escape_basic(search)) {
|
|
242
|
+
escape_UTF8_char_basic(search);
|
|
243
|
+
}
|
|
244
|
+
#endif /* HAVE_SIMD */
|
|
233
245
|
}
|
|
234
246
|
|
|
235
247
|
static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
|
|
@@ -271,8 +283,10 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
|
|
|
271
283
|
|
|
272
284
|
#ifdef HAVE_SIMD
|
|
273
285
|
|
|
274
|
-
static
|
|
286
|
+
ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
|
|
275
287
|
{
|
|
288
|
+
RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
|
|
289
|
+
|
|
276
290
|
// Flush the buffer so everything up until the last 'len' characters are unflushed.
|
|
277
291
|
search_flush(search);
|
|
278
292
|
|
|
@@ -282,19 +296,25 @@ static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsi
|
|
|
282
296
|
char *s = (buf->ptr + buf->len);
|
|
283
297
|
|
|
284
298
|
// Pad the buffer with dummy characters that won't need escaping.
|
|
285
|
-
// This seem
|
|
286
|
-
|
|
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);
|
|
287
302
|
|
|
288
303
|
// Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
|
|
289
304
|
// to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
|
|
290
|
-
|
|
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
|
+
}
|
|
291
311
|
|
|
292
312
|
return s;
|
|
293
313
|
}
|
|
294
314
|
|
|
295
315
|
#ifdef HAVE_SIMD_NEON
|
|
296
316
|
|
|
297
|
-
static
|
|
317
|
+
ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
|
|
298
318
|
{
|
|
299
319
|
uint64_t mask = search->matches_mask;
|
|
300
320
|
uint32_t index = trailing_zeros64(mask) >> 2;
|
|
@@ -408,7 +428,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
|
|
|
408
428
|
|
|
409
429
|
#ifdef HAVE_SIMD_SSE2
|
|
410
430
|
|
|
411
|
-
static
|
|
431
|
+
ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
|
|
412
432
|
{
|
|
413
433
|
int mask = search->matches_mask;
|
|
414
434
|
int index = trailing_zeros(mask);
|
|
@@ -432,7 +452,7 @@ static inline FORCE_INLINE unsigned char sse2_next_match(search_state *search)
|
|
|
432
452
|
#define TARGET_SSE2
|
|
433
453
|
#endif
|
|
434
454
|
|
|
435
|
-
static
|
|
455
|
+
ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
|
|
436
456
|
{
|
|
437
457
|
if (RB_UNLIKELY(search->has_matches)) {
|
|
438
458
|
// There are more matches if search->matches_mask > 0.
|
|
@@ -680,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
|
|
|
680
700
|
}
|
|
681
701
|
}
|
|
682
702
|
|
|
683
|
-
/*
|
|
684
|
-
* Document-module: JSON::Ext::Generator
|
|
685
|
-
*
|
|
686
|
-
* This is the JSON generator implemented as a C extension. It can be
|
|
687
|
-
* configured to be used by setting
|
|
688
|
-
*
|
|
689
|
-
* JSON.generator = JSON::Ext::Generator
|
|
690
|
-
*
|
|
691
|
-
* with the method generator= in JSON.
|
|
692
|
-
*
|
|
693
|
-
*/
|
|
694
|
-
|
|
695
|
-
/* Explanation of the following: that's the only way to not pollute
|
|
696
|
-
* standard library's docs with GeneratorMethods::<ClassName> which
|
|
697
|
-
* are uninformative and take a large place in a list of classes
|
|
698
|
-
*/
|
|
699
|
-
|
|
700
|
-
/*
|
|
701
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods
|
|
702
|
-
* :nodoc:
|
|
703
|
-
*/
|
|
704
|
-
|
|
705
|
-
/*
|
|
706
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Array
|
|
707
|
-
* :nodoc:
|
|
708
|
-
*/
|
|
709
|
-
|
|
710
|
-
/*
|
|
711
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
|
|
712
|
-
* :nodoc:
|
|
713
|
-
*/
|
|
714
|
-
|
|
715
|
-
/*
|
|
716
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
|
|
717
|
-
* :nodoc:
|
|
718
|
-
*/
|
|
719
|
-
|
|
720
|
-
/*
|
|
721
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
|
|
722
|
-
* :nodoc:
|
|
723
|
-
*/
|
|
724
|
-
|
|
725
|
-
/*
|
|
726
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Float
|
|
727
|
-
* :nodoc:
|
|
728
|
-
*/
|
|
729
|
-
|
|
730
|
-
/*
|
|
731
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
|
|
732
|
-
* :nodoc:
|
|
733
|
-
*/
|
|
734
|
-
|
|
735
|
-
/*
|
|
736
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
|
|
737
|
-
* :nodoc:
|
|
738
|
-
*/
|
|
739
|
-
|
|
740
|
-
/*
|
|
741
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
|
|
742
|
-
* :nodoc:
|
|
743
|
-
*/
|
|
744
|
-
|
|
745
|
-
/*
|
|
746
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::Object
|
|
747
|
-
* :nodoc:
|
|
748
|
-
*/
|
|
749
|
-
|
|
750
|
-
/*
|
|
751
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String
|
|
752
|
-
* :nodoc:
|
|
753
|
-
*/
|
|
754
|
-
|
|
755
|
-
/*
|
|
756
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
|
|
757
|
-
* :nodoc:
|
|
758
|
-
*/
|
|
759
|
-
|
|
760
|
-
/*
|
|
761
|
-
* Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
|
|
762
|
-
* :nodoc:
|
|
763
|
-
*/
|
|
764
|
-
|
|
765
|
-
/*
|
|
766
|
-
* call-seq: to_json(state = nil)
|
|
767
|
-
*
|
|
768
|
-
* Returns a JSON string containing a JSON object, that is generated from
|
|
769
|
-
* this Hash instance.
|
|
770
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
771
|
-
* produced JSON string output further.
|
|
772
|
-
*/
|
|
773
|
-
static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
|
|
774
|
-
{
|
|
775
|
-
rb_check_arity(argc, 0, 1);
|
|
776
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
777
|
-
return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
/*
|
|
781
|
-
* call-seq: to_json(state = nil)
|
|
782
|
-
*
|
|
783
|
-
* Returns a JSON string containing a JSON array, that is generated from
|
|
784
|
-
* this Array instance.
|
|
785
|
-
* _state_ is a JSON::State object, that can also be used to configure the
|
|
786
|
-
* produced JSON string output further.
|
|
787
|
-
*/
|
|
788
|
-
static VALUE mArray_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_array, Qfalse);
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
796
|
-
/*
|
|
797
|
-
* call-seq: to_json(*)
|
|
798
|
-
*
|
|
799
|
-
* Returns a JSON string representation for this Integer number.
|
|
800
|
-
*/
|
|
801
|
-
static VALUE mInteger_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_integer, Qfalse);
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
#else
|
|
809
|
-
/*
|
|
810
|
-
* call-seq: to_json(*)
|
|
811
|
-
*
|
|
812
|
-
* Returns a JSON string representation for this Integer number.
|
|
813
|
-
*/
|
|
814
|
-
static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
|
|
815
|
-
{
|
|
816
|
-
rb_check_arity(argc, 0, 1);
|
|
817
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
818
|
-
return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
/*
|
|
822
|
-
* call-seq: to_json(*)
|
|
823
|
-
*
|
|
824
|
-
* Returns a JSON string representation for this Integer number.
|
|
825
|
-
*/
|
|
826
|
-
static VALUE mBignum_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_bignum, Qfalse);
|
|
831
|
-
}
|
|
832
|
-
#endif
|
|
833
|
-
|
|
834
|
-
/*
|
|
835
|
-
* call-seq: to_json(*)
|
|
836
|
-
*
|
|
837
|
-
* Returns a JSON string representation for this Float number.
|
|
838
|
-
*/
|
|
839
|
-
static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
|
|
840
|
-
{
|
|
841
|
-
rb_check_arity(argc, 0, 1);
|
|
842
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
843
|
-
return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/*
|
|
847
|
-
* call-seq: to_json(*)
|
|
848
|
-
*
|
|
849
|
-
* This string should be encoded with UTF-8 A call to this method
|
|
850
|
-
* returns a JSON string encoded with UTF16 big endian characters as
|
|
851
|
-
* \u????.
|
|
852
|
-
*/
|
|
853
|
-
static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
|
|
854
|
-
{
|
|
855
|
-
rb_check_arity(argc, 0, 1);
|
|
856
|
-
VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
|
|
857
|
-
return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
/*
|
|
861
|
-
* call-seq: to_json(*)
|
|
862
|
-
*
|
|
863
|
-
* Returns a JSON string for true: 'true'.
|
|
864
|
-
*/
|
|
865
|
-
static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
866
|
-
{
|
|
867
|
-
rb_check_arity(argc, 0, 1);
|
|
868
|
-
return rb_utf8_str_new("true", 4);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
/*
|
|
872
|
-
* call-seq: to_json(*)
|
|
873
|
-
*
|
|
874
|
-
* Returns a JSON string for false: 'false'.
|
|
875
|
-
*/
|
|
876
|
-
static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
877
|
-
{
|
|
878
|
-
rb_check_arity(argc, 0, 1);
|
|
879
|
-
return rb_utf8_str_new("false", 5);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
/*
|
|
883
|
-
* call-seq: to_json(*)
|
|
884
|
-
*
|
|
885
|
-
* Returns a JSON string for nil: 'null'.
|
|
886
|
-
*/
|
|
887
|
-
static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
|
|
888
|
-
{
|
|
889
|
-
rb_check_arity(argc, 0, 1);
|
|
890
|
-
return rb_utf8_str_new("null", 4);
|
|
891
|
-
}
|
|
892
|
-
|
|
893
|
-
/*
|
|
894
|
-
* call-seq: to_json(*)
|
|
895
|
-
*
|
|
896
|
-
* Converts this object to a string (calling #to_s), converts
|
|
897
|
-
* it to a JSON string, and returns the result. This is a fallback, if no
|
|
898
|
-
* special method #to_json was defined for some object.
|
|
899
|
-
*/
|
|
900
|
-
static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
|
|
901
|
-
{
|
|
902
|
-
VALUE state;
|
|
903
|
-
VALUE string = rb_funcall(self, i_to_s, 0);
|
|
904
|
-
rb_scan_args(argc, argv, "01", &state);
|
|
905
|
-
Check_Type(string, T_STRING);
|
|
906
|
-
state = cState_from_state_s(cState, state);
|
|
907
|
-
return cState_partial_generate(state, string, generate_json_string, Qfalse);
|
|
908
|
-
}
|
|
909
|
-
|
|
910
703
|
static void State_mark(void *ptr)
|
|
911
704
|
{
|
|
912
705
|
JSON_Generator_State *state = ptr;
|
|
@@ -940,11 +733,6 @@ static size_t State_memsize(const void *ptr)
|
|
|
940
733
|
return sizeof(JSON_Generator_State);
|
|
941
734
|
}
|
|
942
735
|
|
|
943
|
-
#ifndef HAVE_RB_EXT_RACTOR_SAFE
|
|
944
|
-
# undef RUBY_TYPED_FROZEN_SHAREABLE
|
|
945
|
-
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
946
|
-
#endif
|
|
947
|
-
|
|
948
736
|
static const rb_data_type_t JSON_Generator_State_type = {
|
|
949
737
|
"JSON/Generator/State",
|
|
950
738
|
{
|
|
@@ -986,21 +774,24 @@ static void vstate_spill(struct generate_json_data *data)
|
|
|
986
774
|
RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
|
|
987
775
|
}
|
|
988
776
|
|
|
989
|
-
static inline VALUE
|
|
777
|
+
static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
|
|
990
778
|
{
|
|
991
779
|
if (RB_UNLIKELY(!data->vstate)) {
|
|
992
780
|
vstate_spill(data);
|
|
993
781
|
}
|
|
994
|
-
|
|
782
|
+
GET_STATE(data->vstate);
|
|
783
|
+
state->depth = data->depth;
|
|
784
|
+
VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
|
|
785
|
+
// no need to restore state->depth, vstate is just a temporary State
|
|
786
|
+
return tmp;
|
|
995
787
|
}
|
|
996
788
|
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
};
|
|
789
|
+
static VALUE
|
|
790
|
+
json_call_as_json(JSON_Generator_State *state, VALUE object, VALUE is_key)
|
|
791
|
+
{
|
|
792
|
+
VALUE proc_args[2] = {object, is_key};
|
|
793
|
+
return rb_proc_call_with_block(state->as_json, 2, proc_args, Qnil);
|
|
794
|
+
}
|
|
1004
795
|
|
|
1005
796
|
static VALUE
|
|
1006
797
|
convert_string_subclass(VALUE key)
|
|
@@ -1017,8 +808,131 @@ convert_string_subclass(VALUE key)
|
|
|
1017
808
|
return key_to_s;
|
|
1018
809
|
}
|
|
1019
810
|
|
|
1020
|
-
|
|
1021
|
-
|
|
811
|
+
static bool enc_utf8_compatible_p(int enc_idx)
|
|
812
|
+
{
|
|
813
|
+
if (enc_idx == usascii_encindex) return true;
|
|
814
|
+
if (enc_idx == utf8_encindex) return true;
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
static VALUE encode_json_string_try(VALUE str)
|
|
819
|
+
{
|
|
820
|
+
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
|
824
|
+
{
|
|
825
|
+
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
|
826
|
+
return Qundef;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
static inline bool valid_json_string_p(VALUE str)
|
|
830
|
+
{
|
|
831
|
+
int coderange = rb_enc_str_coderange(str);
|
|
832
|
+
|
|
833
|
+
if (RB_LIKELY(coderange == ENC_CODERANGE_7BIT)) {
|
|
834
|
+
return true;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
if (RB_LIKELY(coderange == ENC_CODERANGE_VALID)) {
|
|
838
|
+
return enc_utf8_compatible_p(RB_ENCODING_GET_INLINED(str));
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
return false;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
static inline VALUE ensure_valid_encoding(struct generate_json_data *data, VALUE str, bool as_json_called, bool is_key)
|
|
845
|
+
{
|
|
846
|
+
if (RB_LIKELY(valid_json_string_p(str))) {
|
|
847
|
+
return str;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
if (!as_json_called && data->state->strict && RTEST(data->state->as_json)) {
|
|
851
|
+
VALUE coerced_str = json_call_as_json(data->state, str, Qfalse);
|
|
852
|
+
if (coerced_str != str) {
|
|
853
|
+
if (RB_TYPE_P(coerced_str, T_STRING)) {
|
|
854
|
+
if (!valid_json_string_p(coerced_str)) {
|
|
855
|
+
raise_generator_error(str, "source sequence is illegal/malformed utf-8");
|
|
856
|
+
}
|
|
857
|
+
} else {
|
|
858
|
+
// as_json could return another type than T_STRING
|
|
859
|
+
if (is_key) {
|
|
860
|
+
raise_generator_error(coerced_str, "%"PRIsVALUE" not allowed as object key in JSON", CLASS_OF(coerced_str));
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
return coerced_str;
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
if (RB_ENCODING_GET_INLINED(str) == binary_encindex) {
|
|
869
|
+
VALUE utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
|
870
|
+
switch (rb_enc_str_coderange(utf8_string)) {
|
|
871
|
+
case ENC_CODERANGE_7BIT:
|
|
872
|
+
return utf8_string;
|
|
873
|
+
case ENC_CODERANGE_VALID:
|
|
874
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
|
875
|
+
// TODO: Raise in 3.0.0
|
|
876
|
+
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
|
877
|
+
return utf8_string;
|
|
878
|
+
break;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
return rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
886
|
+
{
|
|
887
|
+
fbuffer_append_char(buffer, '"');
|
|
888
|
+
|
|
889
|
+
long len;
|
|
890
|
+
search_state search;
|
|
891
|
+
search.buffer = buffer;
|
|
892
|
+
RSTRING_GETMEM(obj, search.ptr, len);
|
|
893
|
+
search.cursor = search.ptr;
|
|
894
|
+
search.end = search.ptr + len;
|
|
895
|
+
|
|
896
|
+
#ifdef HAVE_SIMD
|
|
897
|
+
search.matches_mask = 0;
|
|
898
|
+
search.has_matches = false;
|
|
899
|
+
search.chunk_base = NULL;
|
|
900
|
+
search.chunk_end = NULL;
|
|
901
|
+
#endif /* HAVE_SIMD */
|
|
902
|
+
|
|
903
|
+
switch (rb_enc_str_coderange(obj)) {
|
|
904
|
+
case ENC_CODERANGE_7BIT:
|
|
905
|
+
case ENC_CODERANGE_VALID:
|
|
906
|
+
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
907
|
+
convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
|
|
908
|
+
} else if (RB_UNLIKELY(data->state->script_safe)) {
|
|
909
|
+
convert_UTF8_to_script_safe_JSON(&search);
|
|
910
|
+
} else {
|
|
911
|
+
convert_UTF8_to_JSON(&search);
|
|
912
|
+
}
|
|
913
|
+
break;
|
|
914
|
+
default:
|
|
915
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
916
|
+
break;
|
|
917
|
+
}
|
|
918
|
+
fbuffer_append_char(buffer, '"');
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
922
|
+
{
|
|
923
|
+
obj = ensure_valid_encoding(data, obj, false, false);
|
|
924
|
+
raw_generate_json_string(buffer, data, obj);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
struct hash_foreach_arg {
|
|
928
|
+
VALUE hash;
|
|
929
|
+
struct generate_json_data *data;
|
|
930
|
+
int first_key_type;
|
|
931
|
+
bool first;
|
|
932
|
+
bool mixed_keys_encountered;
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
NOINLINE(static) void
|
|
1022
936
|
json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
|
|
1023
937
|
{
|
|
1024
938
|
if (arg->mixed_keys_encountered) {
|
|
@@ -1042,7 +956,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1042
956
|
FBuffer *buffer = data->buffer;
|
|
1043
957
|
JSON_Generator_State *state = data->state;
|
|
1044
958
|
|
|
1045
|
-
long depth =
|
|
959
|
+
long depth = data->depth;
|
|
1046
960
|
int key_type = rb_type(key);
|
|
1047
961
|
|
|
1048
962
|
if (arg->first) {
|
|
@@ -1086,7 +1000,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1086
1000
|
default:
|
|
1087
1001
|
if (data->state->strict) {
|
|
1088
1002
|
if (RTEST(data->state->as_json) && !as_json_called) {
|
|
1089
|
-
key =
|
|
1003
|
+
key = json_call_as_json(data->state, key, Qtrue);
|
|
1090
1004
|
key_type = rb_type(key);
|
|
1091
1005
|
as_json_called = true;
|
|
1092
1006
|
goto start;
|
|
@@ -1098,8 +1012,10 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1098
1012
|
break;
|
|
1099
1013
|
}
|
|
1100
1014
|
|
|
1015
|
+
key_to_s = ensure_valid_encoding(data, key_to_s, as_json_called, true);
|
|
1016
|
+
|
|
1101
1017
|
if (RB_LIKELY(RBASIC_CLASS(key_to_s) == rb_cString)) {
|
|
1102
|
-
|
|
1018
|
+
raw_generate_json_string(buffer, data, key_to_s);
|
|
1103
1019
|
} else {
|
|
1104
1020
|
generate_json(buffer, data, key_to_s);
|
|
1105
1021
|
}
|
|
@@ -1114,9 +1030,9 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1114
1030
|
static inline long increase_depth(struct generate_json_data *data)
|
|
1115
1031
|
{
|
|
1116
1032
|
JSON_Generator_State *state = data->state;
|
|
1117
|
-
long depth = ++
|
|
1033
|
+
long depth = ++data->depth;
|
|
1118
1034
|
if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
|
|
1119
|
-
rb_raise(eNestingError, "nesting of %ld is too deep", --
|
|
1035
|
+
rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
|
|
1120
1036
|
}
|
|
1121
1037
|
return depth;
|
|
1122
1038
|
}
|
|
@@ -1127,7 +1043,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1127
1043
|
|
|
1128
1044
|
if (RHASH_SIZE(obj) == 0) {
|
|
1129
1045
|
fbuffer_append(buffer, "{}", 2);
|
|
1130
|
-
--data->
|
|
1046
|
+
--data->depth;
|
|
1131
1047
|
return;
|
|
1132
1048
|
}
|
|
1133
1049
|
|
|
@@ -1140,7 +1056,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1140
1056
|
};
|
|
1141
1057
|
rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
|
|
1142
1058
|
|
|
1143
|
-
depth = --data->
|
|
1059
|
+
depth = --data->depth;
|
|
1144
1060
|
if (RB_UNLIKELY(data->state->object_nl)) {
|
|
1145
1061
|
fbuffer_append_str(buffer, data->state->object_nl);
|
|
1146
1062
|
if (RB_UNLIKELY(data->state->indent)) {
|
|
@@ -1156,7 +1072,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1156
1072
|
|
|
1157
1073
|
if (RARRAY_LEN(obj) == 0) {
|
|
1158
1074
|
fbuffer_append(buffer, "[]", 2);
|
|
1159
|
-
--data->
|
|
1075
|
+
--data->depth;
|
|
1160
1076
|
return;
|
|
1161
1077
|
}
|
|
1162
1078
|
|
|
@@ -1172,7 +1088,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1172
1088
|
}
|
|
1173
1089
|
generate_json(buffer, data, RARRAY_AREF(obj, i));
|
|
1174
1090
|
}
|
|
1175
|
-
data->
|
|
1091
|
+
data->depth = --depth;
|
|
1176
1092
|
if (RB_UNLIKELY(data->state->array_nl)) {
|
|
1177
1093
|
fbuffer_append_str(buffer, data->state->array_nl);
|
|
1178
1094
|
if (RB_UNLIKELY(data->state->indent)) {
|
|
@@ -1182,90 +1098,11 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
|
|
|
1182
1098
|
fbuffer_append_char(buffer, ']');
|
|
1183
1099
|
}
|
|
1184
1100
|
|
|
1185
|
-
static inline int enc_utf8_compatible_p(int enc_idx)
|
|
1186
|
-
{
|
|
1187
|
-
if (enc_idx == usascii_encindex) return 1;
|
|
1188
|
-
if (enc_idx == utf8_encindex) return 1;
|
|
1189
|
-
return 0;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
static VALUE encode_json_string_try(VALUE str)
|
|
1193
|
-
{
|
|
1194
|
-
return rb_funcall(str, i_encode, 1, Encoding_UTF_8);
|
|
1195
|
-
}
|
|
1196
|
-
|
|
1197
|
-
static VALUE encode_json_string_rescue(VALUE str, VALUE exception)
|
|
1198
|
-
{
|
|
1199
|
-
raise_generator_error_str(str, rb_funcall(exception, rb_intern("message"), 0));
|
|
1200
|
-
return Qundef;
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
static inline VALUE ensure_valid_encoding(VALUE str)
|
|
1204
|
-
{
|
|
1205
|
-
int encindex = RB_ENCODING_GET(str);
|
|
1206
|
-
VALUE utf8_string;
|
|
1207
|
-
if (RB_UNLIKELY(!enc_utf8_compatible_p(encindex))) {
|
|
1208
|
-
if (encindex == binary_encindex) {
|
|
1209
|
-
utf8_string = rb_enc_associate_index(rb_str_dup(str), utf8_encindex);
|
|
1210
|
-
switch (rb_enc_str_coderange(utf8_string)) {
|
|
1211
|
-
case ENC_CODERANGE_7BIT:
|
|
1212
|
-
return utf8_string;
|
|
1213
|
-
case ENC_CODERANGE_VALID:
|
|
1214
|
-
// For historical reason, we silently reinterpret binary strings as UTF-8 if it would work.
|
|
1215
|
-
// TODO: Raise in 3.0.0
|
|
1216
|
-
rb_warn("JSON.generate: UTF-8 string passed as BINARY, this will raise an encoding error in json 3.0");
|
|
1217
|
-
return utf8_string;
|
|
1218
|
-
break;
|
|
1219
|
-
}
|
|
1220
|
-
}
|
|
1221
|
-
|
|
1222
|
-
str = rb_rescue(encode_json_string_try, str, encode_json_string_rescue, str);
|
|
1223
|
-
}
|
|
1224
|
-
return str;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
static void generate_json_string(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1228
|
-
{
|
|
1229
|
-
obj = ensure_valid_encoding(obj);
|
|
1230
|
-
|
|
1231
|
-
fbuffer_append_char(buffer, '"');
|
|
1232
|
-
|
|
1233
|
-
long len;
|
|
1234
|
-
search_state search;
|
|
1235
|
-
search.buffer = buffer;
|
|
1236
|
-
RSTRING_GETMEM(obj, search.ptr, len);
|
|
1237
|
-
search.cursor = search.ptr;
|
|
1238
|
-
search.end = search.ptr + len;
|
|
1239
|
-
|
|
1240
|
-
#ifdef HAVE_SIMD
|
|
1241
|
-
search.matches_mask = 0;
|
|
1242
|
-
search.has_matches = false;
|
|
1243
|
-
search.chunk_base = NULL;
|
|
1244
|
-
#endif /* HAVE_SIMD */
|
|
1245
|
-
|
|
1246
|
-
switch (rb_enc_str_coderange(obj)) {
|
|
1247
|
-
case ENC_CODERANGE_7BIT:
|
|
1248
|
-
case ENC_CODERANGE_VALID:
|
|
1249
|
-
if (RB_UNLIKELY(data->state->ascii_only)) {
|
|
1250
|
-
convert_UTF8_to_ASCII_only_JSON(&search, data->state->script_safe ? script_safe_escape_table : ascii_only_escape_table);
|
|
1251
|
-
} else if (RB_UNLIKELY(data->state->script_safe)) {
|
|
1252
|
-
convert_UTF8_to_script_safe_JSON(&search);
|
|
1253
|
-
} else {
|
|
1254
|
-
convert_UTF8_to_JSON(&search);
|
|
1255
|
-
}
|
|
1256
|
-
break;
|
|
1257
|
-
default:
|
|
1258
|
-
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
1259
|
-
break;
|
|
1260
|
-
}
|
|
1261
|
-
fbuffer_append_char(buffer, '"');
|
|
1262
|
-
}
|
|
1263
|
-
|
|
1264
1101
|
static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1265
1102
|
{
|
|
1266
1103
|
VALUE tmp;
|
|
1267
1104
|
if (rb_respond_to(obj, i_to_json)) {
|
|
1268
|
-
tmp =
|
|
1105
|
+
tmp = json_call_to_json(data, obj);
|
|
1269
1106
|
Check_Type(tmp, T_STRING);
|
|
1270
1107
|
fbuffer_append_str(buffer, tmp);
|
|
1271
1108
|
} else {
|
|
@@ -1307,18 +1144,8 @@ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *dat
|
|
|
1307
1144
|
static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1308
1145
|
{
|
|
1309
1146
|
VALUE tmp = rb_funcall(obj, i_to_s, 0);
|
|
1310
|
-
fbuffer_append_str(buffer, tmp);
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
1314
|
-
static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1315
|
-
{
|
|
1316
|
-
if (FIXNUM_P(obj))
|
|
1317
|
-
generate_json_fixnum(buffer, data, obj);
|
|
1318
|
-
else
|
|
1319
|
-
generate_json_bignum(buffer, data, obj);
|
|
1147
|
+
fbuffer_append_str(buffer, StringValue(tmp));
|
|
1320
1148
|
}
|
|
1321
|
-
#endif
|
|
1322
1149
|
|
|
1323
1150
|
static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1324
1151
|
{
|
|
@@ -1328,11 +1155,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
|
1328
1155
|
/* for NaN and Infinity values we either raise an error or rely on Float#to_s. */
|
|
1329
1156
|
if (!allow_nan) {
|
|
1330
1157
|
if (data->state->strict && data->state->as_json) {
|
|
1331
|
-
VALUE casted_obj =
|
|
1158
|
+
VALUE casted_obj = json_call_as_json(data->state, obj, Qfalse);
|
|
1332
1159
|
if (casted_obj != obj) {
|
|
1333
1160
|
increase_depth(data);
|
|
1334
1161
|
generate_json(buffer, data, casted_obj);
|
|
1335
|
-
data->
|
|
1162
|
+
data->depth--;
|
|
1336
1163
|
return;
|
|
1337
1164
|
}
|
|
1338
1165
|
}
|
|
@@ -1345,12 +1172,11 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
|
|
|
1345
1172
|
}
|
|
1346
1173
|
|
|
1347
1174
|
/* This implementation writes directly into the buffer. We reserve
|
|
1348
|
-
* the
|
|
1175
|
+
* the 32 characters that fpconv_dtoa states as its maximum.
|
|
1349
1176
|
*/
|
|
1350
|
-
fbuffer_inc_capa(buffer,
|
|
1177
|
+
fbuffer_inc_capa(buffer, 32);
|
|
1351
1178
|
char* d = buffer->ptr + buffer->len;
|
|
1352
1179
|
int len = fpconv_dtoa(value, d);
|
|
1353
|
-
|
|
1354
1180
|
/* fpconv_dtoa converts a float to its shortest string representation,
|
|
1355
1181
|
* but it adds a ".0" if this is a plain integer.
|
|
1356
1182
|
*/
|
|
@@ -1364,7 +1190,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
|
|
|
1364
1190
|
fbuffer_append_str(buffer, fragment);
|
|
1365
1191
|
}
|
|
1366
1192
|
|
|
1367
|
-
static void
|
|
1193
|
+
static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
|
|
1368
1194
|
{
|
|
1369
1195
|
bool as_json_called = false;
|
|
1370
1196
|
start:
|
|
@@ -1391,22 +1217,31 @@ start:
|
|
|
1391
1217
|
generate_json_bignum(buffer, data, obj);
|
|
1392
1218
|
break;
|
|
1393
1219
|
case T_HASH:
|
|
1394
|
-
if (klass != rb_cHash) goto general;
|
|
1220
|
+
if (fallback && klass != rb_cHash) goto general;
|
|
1395
1221
|
generate_json_object(buffer, data, obj);
|
|
1396
1222
|
break;
|
|
1397
1223
|
case T_ARRAY:
|
|
1398
|
-
if (klass != rb_cArray) goto general;
|
|
1224
|
+
if (fallback && klass != rb_cArray) goto general;
|
|
1399
1225
|
generate_json_array(buffer, data, obj);
|
|
1400
1226
|
break;
|
|
1401
1227
|
case T_STRING:
|
|
1402
|
-
if (klass != rb_cString) goto general;
|
|
1403
|
-
|
|
1228
|
+
if (fallback && klass != rb_cString) goto general;
|
|
1229
|
+
|
|
1230
|
+
if (RB_LIKELY(valid_json_string_p(obj))) {
|
|
1231
|
+
raw_generate_json_string(buffer, data, obj);
|
|
1232
|
+
} else if (as_json_called) {
|
|
1233
|
+
raise_generator_error(obj, "source sequence is illegal/malformed utf-8");
|
|
1234
|
+
} else {
|
|
1235
|
+
obj = ensure_valid_encoding(data, obj, false, false);
|
|
1236
|
+
as_json_called = true;
|
|
1237
|
+
goto start;
|
|
1238
|
+
}
|
|
1404
1239
|
break;
|
|
1405
1240
|
case T_SYMBOL:
|
|
1406
1241
|
generate_json_symbol(buffer, data, obj);
|
|
1407
1242
|
break;
|
|
1408
1243
|
case T_FLOAT:
|
|
1409
|
-
if (klass != rb_cFloat) goto general;
|
|
1244
|
+
if (fallback && klass != rb_cFloat) goto general;
|
|
1410
1245
|
generate_json_float(buffer, data, obj);
|
|
1411
1246
|
break;
|
|
1412
1247
|
case T_STRUCT:
|
|
@@ -1417,7 +1252,7 @@ start:
|
|
|
1417
1252
|
general:
|
|
1418
1253
|
if (data->state->strict) {
|
|
1419
1254
|
if (RTEST(data->state->as_json) && !as_json_called) {
|
|
1420
|
-
obj =
|
|
1255
|
+
obj = json_call_as_json(data->state, obj, Qfalse);
|
|
1421
1256
|
as_json_called = true;
|
|
1422
1257
|
goto start;
|
|
1423
1258
|
} else {
|
|
@@ -1430,26 +1265,34 @@ start:
|
|
|
1430
1265
|
}
|
|
1431
1266
|
}
|
|
1432
1267
|
|
|
1268
|
+
static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1269
|
+
{
|
|
1270
|
+
generate_json_general(buffer, data, obj, true);
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
|
|
1274
|
+
{
|
|
1275
|
+
generate_json_general(buffer, data, obj, false);
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1433
1278
|
static VALUE generate_json_try(VALUE d)
|
|
1434
1279
|
{
|
|
1435
1280
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
1436
1281
|
|
|
1437
1282
|
data->func(data->buffer, data, data->obj);
|
|
1438
1283
|
|
|
1439
|
-
return
|
|
1284
|
+
return fbuffer_finalize(data->buffer);
|
|
1440
1285
|
}
|
|
1441
1286
|
|
|
1442
|
-
static VALUE
|
|
1287
|
+
static VALUE generate_json_ensure(VALUE d)
|
|
1443
1288
|
{
|
|
1444
1289
|
struct generate_json_data *data = (struct generate_json_data *)d;
|
|
1445
1290
|
fbuffer_free(data->buffer);
|
|
1446
1291
|
|
|
1447
|
-
rb_exc_raise(exc);
|
|
1448
|
-
|
|
1449
1292
|
return Qundef;
|
|
1450
1293
|
}
|
|
1451
1294
|
|
|
1452
|
-
static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1295
|
+
static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
|
|
1453
1296
|
{
|
|
1454
1297
|
GET_STATE(self);
|
|
1455
1298
|
|
|
@@ -1461,14 +1304,13 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
|
|
|
1461
1304
|
|
|
1462
1305
|
struct generate_json_data data = {
|
|
1463
1306
|
.buffer = &buffer,
|
|
1464
|
-
.vstate = self
|
|
1307
|
+
.vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
|
|
1465
1308
|
.state = state,
|
|
1309
|
+
.depth = state->depth,
|
|
1466
1310
|
.obj = obj,
|
|
1467
1311
|
.func = func
|
|
1468
1312
|
};
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
return fbuffer_finalize(&buffer);
|
|
1313
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
1472
1314
|
}
|
|
1473
1315
|
|
|
1474
1316
|
/* call-seq:
|
|
@@ -1484,10 +1326,16 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
|
|
|
1484
1326
|
rb_check_arity(argc, 1, 2);
|
|
1485
1327
|
VALUE obj = argv[0];
|
|
1486
1328
|
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1329
|
+
return cState_partial_generate(self, obj, generate_json, io);
|
|
1330
|
+
}
|
|
1331
|
+
|
|
1332
|
+
/* :nodoc: */
|
|
1333
|
+
static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
|
|
1334
|
+
{
|
|
1335
|
+
rb_check_arity(argc, 1, 2);
|
|
1336
|
+
VALUE obj = argv[0];
|
|
1337
|
+
VALUE io = argc > 1 ? argv[1] : Qnil;
|
|
1338
|
+
return cState_partial_generate(self, obj, generate_json_no_fallback, io);
|
|
1491
1339
|
}
|
|
1492
1340
|
|
|
1493
1341
|
static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
|
|
@@ -1568,6 +1416,7 @@ static VALUE string_config(VALUE config)
|
|
|
1568
1416
|
*/
|
|
1569
1417
|
static VALUE cState_indent_set(VALUE self, VALUE indent)
|
|
1570
1418
|
{
|
|
1419
|
+
rb_check_frozen(self);
|
|
1571
1420
|
GET_STATE(self);
|
|
1572
1421
|
RB_OBJ_WRITE(self, &state->indent, string_config(indent));
|
|
1573
1422
|
return Qnil;
|
|
@@ -1593,6 +1442,7 @@ static VALUE cState_space(VALUE self)
|
|
|
1593
1442
|
*/
|
|
1594
1443
|
static VALUE cState_space_set(VALUE self, VALUE space)
|
|
1595
1444
|
{
|
|
1445
|
+
rb_check_frozen(self);
|
|
1596
1446
|
GET_STATE(self);
|
|
1597
1447
|
RB_OBJ_WRITE(self, &state->space, string_config(space));
|
|
1598
1448
|
return Qnil;
|
|
@@ -1616,6 +1466,7 @@ static VALUE cState_space_before(VALUE self)
|
|
|
1616
1466
|
*/
|
|
1617
1467
|
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
|
|
1618
1468
|
{
|
|
1469
|
+
rb_check_frozen(self);
|
|
1619
1470
|
GET_STATE(self);
|
|
1620
1471
|
RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
|
|
1621
1472
|
return Qnil;
|
|
@@ -1641,6 +1492,7 @@ static VALUE cState_object_nl(VALUE self)
|
|
|
1641
1492
|
*/
|
|
1642
1493
|
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
|
|
1643
1494
|
{
|
|
1495
|
+
rb_check_frozen(self);
|
|
1644
1496
|
GET_STATE(self);
|
|
1645
1497
|
RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
|
|
1646
1498
|
return Qnil;
|
|
@@ -1664,6 +1516,7 @@ static VALUE cState_array_nl(VALUE self)
|
|
|
1664
1516
|
*/
|
|
1665
1517
|
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
|
|
1666
1518
|
{
|
|
1519
|
+
rb_check_frozen(self);
|
|
1667
1520
|
GET_STATE(self);
|
|
1668
1521
|
RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
|
|
1669
1522
|
return Qnil;
|
|
@@ -1687,6 +1540,7 @@ static VALUE cState_as_json(VALUE self)
|
|
|
1687
1540
|
*/
|
|
1688
1541
|
static VALUE cState_as_json_set(VALUE self, VALUE as_json)
|
|
1689
1542
|
{
|
|
1543
|
+
rb_check_frozen(self);
|
|
1690
1544
|
GET_STATE(self);
|
|
1691
1545
|
RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
|
|
1692
1546
|
return Qnil;
|
|
@@ -1721,6 +1575,17 @@ static long long_config(VALUE num)
|
|
|
1721
1575
|
return RTEST(num) ? FIX2LONG(num) : 0;
|
|
1722
1576
|
}
|
|
1723
1577
|
|
|
1578
|
+
// depth must never be negative; reject early with a clear error.
|
|
1579
|
+
static long depth_config(VALUE num)
|
|
1580
|
+
{
|
|
1581
|
+
if (!RTEST(num)) return 0;
|
|
1582
|
+
long d = NUM2LONG(num);
|
|
1583
|
+
if (RB_UNLIKELY(d < 0)) {
|
|
1584
|
+
rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
|
|
1585
|
+
}
|
|
1586
|
+
return d;
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1724
1589
|
/*
|
|
1725
1590
|
* call-seq: max_nesting=(depth)
|
|
1726
1591
|
*
|
|
@@ -1729,6 +1594,7 @@ static long long_config(VALUE num)
|
|
|
1729
1594
|
*/
|
|
1730
1595
|
static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
|
|
1731
1596
|
{
|
|
1597
|
+
rb_check_frozen(self);
|
|
1732
1598
|
GET_STATE(self);
|
|
1733
1599
|
state->max_nesting = long_config(depth);
|
|
1734
1600
|
return Qnil;
|
|
@@ -1754,6 +1620,7 @@ static VALUE cState_script_safe(VALUE self)
|
|
|
1754
1620
|
*/
|
|
1755
1621
|
static VALUE cState_script_safe_set(VALUE self, VALUE enable)
|
|
1756
1622
|
{
|
|
1623
|
+
rb_check_frozen(self);
|
|
1757
1624
|
GET_STATE(self);
|
|
1758
1625
|
state->script_safe = RTEST(enable);
|
|
1759
1626
|
return Qnil;
|
|
@@ -1785,6 +1652,7 @@ static VALUE cState_strict(VALUE self)
|
|
|
1785
1652
|
*/
|
|
1786
1653
|
static VALUE cState_strict_set(VALUE self, VALUE enable)
|
|
1787
1654
|
{
|
|
1655
|
+
rb_check_frozen(self);
|
|
1788
1656
|
GET_STATE(self);
|
|
1789
1657
|
state->strict = RTEST(enable);
|
|
1790
1658
|
return Qnil;
|
|
@@ -1809,6 +1677,7 @@ static VALUE cState_allow_nan_p(VALUE self)
|
|
|
1809
1677
|
*/
|
|
1810
1678
|
static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
|
|
1811
1679
|
{
|
|
1680
|
+
rb_check_frozen(self);
|
|
1812
1681
|
GET_STATE(self);
|
|
1813
1682
|
state->allow_nan = RTEST(enable);
|
|
1814
1683
|
return Qnil;
|
|
@@ -1833,6 +1702,7 @@ static VALUE cState_ascii_only_p(VALUE self)
|
|
|
1833
1702
|
*/
|
|
1834
1703
|
static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
|
|
1835
1704
|
{
|
|
1705
|
+
rb_check_frozen(self);
|
|
1836
1706
|
GET_STATE(self);
|
|
1837
1707
|
state->ascii_only = RTEST(enable);
|
|
1838
1708
|
return Qnil;
|
|
@@ -1870,8 +1740,9 @@ static VALUE cState_depth(VALUE self)
|
|
|
1870
1740
|
*/
|
|
1871
1741
|
static VALUE cState_depth_set(VALUE self, VALUE depth)
|
|
1872
1742
|
{
|
|
1743
|
+
rb_check_frozen(self);
|
|
1873
1744
|
GET_STATE(self);
|
|
1874
|
-
state->depth =
|
|
1745
|
+
state->depth = depth_config(depth);
|
|
1875
1746
|
return Qnil;
|
|
1876
1747
|
}
|
|
1877
1748
|
|
|
@@ -1903,6 +1774,7 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
|
|
|
1903
1774
|
*/
|
|
1904
1775
|
static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
|
|
1905
1776
|
{
|
|
1777
|
+
rb_check_frozen(self);
|
|
1906
1778
|
GET_STATE(self);
|
|
1907
1779
|
buffer_initial_length_set(state, buffer_initial_length);
|
|
1908
1780
|
return Qnil;
|
|
@@ -1935,7 +1807,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1935
1807
|
else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
|
|
1936
1808
|
else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
|
|
1937
1809
|
else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
|
|
1938
|
-
else if (key == sym_depth) { state->depth =
|
|
1810
|
+
else if (key == sym_depth) { state->depth = depth_config(val); }
|
|
1939
1811
|
else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
|
|
1940
1812
|
else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
|
|
1941
1813
|
else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
|
|
@@ -1943,6 +1815,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
|
|
|
1943
1815
|
else if (key == sym_allow_duplicate_key) { state->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
|
1944
1816
|
else if (key == sym_as_json) {
|
|
1945
1817
|
VALUE proc = RTEST(val) ? rb_convert_type(val, T_DATA, "Proc", "to_proc") : Qfalse;
|
|
1818
|
+
state->as_json_single_arg = proc && rb_proc_arity(proc) == 1;
|
|
1946
1819
|
state_write_value(data, &state->as_json, proc);
|
|
1947
1820
|
}
|
|
1948
1821
|
return ST_CONTINUE;
|
|
@@ -1968,12 +1841,13 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
|
|
|
1968
1841
|
|
|
1969
1842
|
static VALUE cState_configure(VALUE self, VALUE opts)
|
|
1970
1843
|
{
|
|
1844
|
+
rb_check_frozen(self);
|
|
1971
1845
|
GET_STATE(self);
|
|
1972
1846
|
configure_state(state, self, opts);
|
|
1973
1847
|
return self;
|
|
1974
1848
|
}
|
|
1975
1849
|
|
|
1976
|
-
static VALUE
|
|
1850
|
+
static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
|
|
1977
1851
|
{
|
|
1978
1852
|
JSON_Generator_State state = {0};
|
|
1979
1853
|
state_init(&state);
|
|
@@ -1989,17 +1863,23 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
|
1989
1863
|
.buffer = &buffer,
|
|
1990
1864
|
.vstate = Qfalse,
|
|
1991
1865
|
.state = &state,
|
|
1866
|
+
.depth = state.depth,
|
|
1992
1867
|
.obj = obj,
|
|
1993
|
-
.func =
|
|
1868
|
+
.func = func,
|
|
1994
1869
|
};
|
|
1995
|
-
|
|
1870
|
+
return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
|
|
1871
|
+
}
|
|
1996
1872
|
|
|
1997
|
-
|
|
1873
|
+
static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1874
|
+
{
|
|
1875
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json);
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
|
|
1879
|
+
{
|
|
1880
|
+
return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
|
|
1998
1881
|
}
|
|
1999
1882
|
|
|
2000
|
-
/*
|
|
2001
|
-
*
|
|
2002
|
-
*/
|
|
2003
1883
|
void Init_generator(void)
|
|
2004
1884
|
{
|
|
2005
1885
|
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
|
@@ -2064,47 +1944,12 @@ void Init_generator(void)
|
|
|
2064
1944
|
rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
|
|
2065
1945
|
rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
|
|
2066
1946
|
rb_define_method(cState, "generate", cState_generate, -1);
|
|
2067
|
-
|
|
1947
|
+
rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
|
|
2068
1948
|
|
|
2069
1949
|
rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
|
|
2070
1950
|
|
|
2071
1951
|
rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
|
|
2072
|
-
|
|
2073
|
-
VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
|
|
2074
|
-
|
|
2075
|
-
VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
|
|
2076
|
-
rb_define_method(mObject, "to_json", mObject_to_json, -1);
|
|
2077
|
-
|
|
2078
|
-
VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
|
|
2079
|
-
rb_define_method(mHash, "to_json", mHash_to_json, -1);
|
|
2080
|
-
|
|
2081
|
-
VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
|
|
2082
|
-
rb_define_method(mArray, "to_json", mArray_to_json, -1);
|
|
2083
|
-
|
|
2084
|
-
#ifdef RUBY_INTEGER_UNIFICATION
|
|
2085
|
-
VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
|
|
2086
|
-
rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
|
|
2087
|
-
#else
|
|
2088
|
-
VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
|
|
2089
|
-
rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
|
|
2090
|
-
|
|
2091
|
-
VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
|
|
2092
|
-
rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
|
|
2093
|
-
#endif
|
|
2094
|
-
VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
|
|
2095
|
-
rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
|
|
2096
|
-
|
|
2097
|
-
VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
|
|
2098
|
-
rb_define_method(mString, "to_json", mString_to_json, -1);
|
|
2099
|
-
|
|
2100
|
-
VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
|
|
2101
|
-
rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
|
|
2102
|
-
|
|
2103
|
-
VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
|
|
2104
|
-
rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
|
|
2105
|
-
|
|
2106
|
-
VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
|
|
2107
|
-
rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
|
|
1952
|
+
rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
|
|
2108
1953
|
|
|
2109
1954
|
rb_global_variable(&Encoding_UTF_8);
|
|
2110
1955
|
Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
|
|
@@ -2112,10 +1957,6 @@ void Init_generator(void)
|
|
|
2112
1957
|
i_to_s = rb_intern("to_s");
|
|
2113
1958
|
i_to_json = rb_intern("to_json");
|
|
2114
1959
|
i_new = rb_intern("new");
|
|
2115
|
-
i_pack = rb_intern("pack");
|
|
2116
|
-
i_unpack = rb_intern("unpack");
|
|
2117
|
-
i_create_id = rb_intern("create_id");
|
|
2118
|
-
i_extend = rb_intern("extend");
|
|
2119
1960
|
i_encode = rb_intern("encode");
|
|
2120
1961
|
|
|
2121
1962
|
sym_indent = ID2SYM(rb_intern("indent"));
|
|
@@ -2140,22 +1981,5 @@ void Init_generator(void)
|
|
|
2140
1981
|
|
|
2141
1982
|
rb_require("json/ext/generator/state");
|
|
2142
1983
|
|
|
2143
|
-
|
|
2144
|
-
switch (find_simd_implementation()) {
|
|
2145
|
-
#ifdef HAVE_SIMD
|
|
2146
|
-
#ifdef HAVE_SIMD_NEON
|
|
2147
|
-
case SIMD_NEON:
|
|
2148
|
-
search_escape_basic_impl = search_escape_basic_neon;
|
|
2149
|
-
break;
|
|
2150
|
-
#endif /* HAVE_SIMD_NEON */
|
|
2151
|
-
#ifdef HAVE_SIMD_SSE2
|
|
2152
|
-
case SIMD_SSE2:
|
|
2153
|
-
search_escape_basic_impl = search_escape_basic_sse2;
|
|
2154
|
-
break;
|
|
2155
|
-
#endif /* HAVE_SIMD_SSE2 */
|
|
2156
|
-
#endif /* HAVE_SIMD */
|
|
2157
|
-
default:
|
|
2158
|
-
search_escape_basic_impl = search_escape_basic;
|
|
2159
|
-
break;
|
|
2160
|
-
}
|
|
1984
|
+
simd_impl = find_simd_implementation();
|
|
2161
1985
|
}
|