json 2.18.1 → 2.19.7
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 +45 -0
- data/ext/json/ext/fbuffer/fbuffer.h +27 -16
- data/ext/json/ext/generator/extconf.rb +2 -0
- data/ext/json/ext/generator/generator.c +89 -316
- data/ext/json/ext/json.h +15 -0
- data/ext/json/ext/parser/extconf.rb +4 -0
- data/ext/json/ext/parser/parser.c +172 -101
- data/ext/json/ext/simd/simd.h +0 -10
- 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 +14 -2
- metadata +2 -2
|
@@ -7,8 +7,9 @@ static VALUE CNaN, CInfinity, CMinusInfinity;
|
|
|
7
7
|
|
|
8
8
|
static ID i_new, i_try_convert, i_uminus, i_encode;
|
|
9
9
|
|
|
10
|
-
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
|
|
11
|
-
sym_decimal_class, sym_on_load,
|
|
10
|
+
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_allow_control_characters,
|
|
11
|
+
sym_allow_invalid_escape, sym_symbolize_names, sym_freeze, sym_decimal_class, sym_on_load,
|
|
12
|
+
sym_allow_duplicate_key;
|
|
12
13
|
|
|
13
14
|
static int binary_encindex;
|
|
14
15
|
static int utf8_encindex;
|
|
@@ -240,17 +241,27 @@ static void rvalue_stack_mark(void *ptr)
|
|
|
240
241
|
{
|
|
241
242
|
rvalue_stack *stack = (rvalue_stack *)ptr;
|
|
242
243
|
long index;
|
|
243
|
-
|
|
244
|
-
|
|
244
|
+
if (stack && stack->ptr) {
|
|
245
|
+
for (index = 0; index < stack->head; index++) {
|
|
246
|
+
rb_gc_mark(stack->ptr[index]);
|
|
247
|
+
}
|
|
245
248
|
}
|
|
246
249
|
}
|
|
247
250
|
|
|
251
|
+
static void rvalue_stack_free_buffer(rvalue_stack *stack)
|
|
252
|
+
{
|
|
253
|
+
ruby_xfree(stack->ptr);
|
|
254
|
+
stack->ptr = NULL;
|
|
255
|
+
}
|
|
256
|
+
|
|
248
257
|
static void rvalue_stack_free(void *ptr)
|
|
249
258
|
{
|
|
250
259
|
rvalue_stack *stack = (rvalue_stack *)ptr;
|
|
251
260
|
if (stack) {
|
|
252
|
-
|
|
261
|
+
rvalue_stack_free_buffer(stack);
|
|
262
|
+
#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
253
263
|
ruby_xfree(stack);
|
|
264
|
+
#endif
|
|
254
265
|
}
|
|
255
266
|
}
|
|
256
267
|
|
|
@@ -261,14 +272,13 @@ static size_t rvalue_stack_memsize(const void *ptr)
|
|
|
261
272
|
}
|
|
262
273
|
|
|
263
274
|
static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
|
|
264
|
-
"JSON::Ext::Parser/rvalue_stack",
|
|
265
|
-
{
|
|
275
|
+
.wrap_struct_name = "JSON::Ext::Parser/rvalue_stack",
|
|
276
|
+
.function = {
|
|
266
277
|
.dmark = rvalue_stack_mark,
|
|
267
278
|
.dfree = rvalue_stack_free,
|
|
268
279
|
.dsize = rvalue_stack_memsize,
|
|
269
280
|
},
|
|
270
|
-
|
|
271
|
-
RUBY_TYPED_FREE_IMMEDIATELY,
|
|
281
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
|
|
272
282
|
};
|
|
273
283
|
|
|
274
284
|
static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref)
|
|
@@ -290,8 +300,12 @@ static void rvalue_stack_eagerly_release(VALUE handle)
|
|
|
290
300
|
if (handle) {
|
|
291
301
|
rvalue_stack *stack;
|
|
292
302
|
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
|
|
293
|
-
|
|
303
|
+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
|
|
304
|
+
rvalue_stack_free_buffer(stack);
|
|
305
|
+
#else
|
|
294
306
|
rvalue_stack_free(stack);
|
|
307
|
+
RTYPEDDATA_DATA(handle) = NULL;
|
|
308
|
+
#endif
|
|
295
309
|
}
|
|
296
310
|
}
|
|
297
311
|
|
|
@@ -336,12 +350,13 @@ typedef struct JSON_ParserStruct {
|
|
|
336
350
|
bool allow_nan;
|
|
337
351
|
bool allow_trailing_comma;
|
|
338
352
|
bool allow_control_characters;
|
|
353
|
+
bool allow_invalid_escape;
|
|
339
354
|
bool symbolize_names;
|
|
340
355
|
bool freeze;
|
|
341
356
|
} JSON_ParserConfig;
|
|
342
357
|
|
|
343
358
|
typedef struct JSON_ParserStateStruct {
|
|
344
|
-
VALUE stack_handle;
|
|
359
|
+
VALUE *stack_handle;
|
|
345
360
|
const char *start;
|
|
346
361
|
const char *cursor;
|
|
347
362
|
const char *end;
|
|
@@ -349,6 +364,7 @@ typedef struct JSON_ParserStateStruct {
|
|
|
349
364
|
rvalue_cache name_cache;
|
|
350
365
|
int in_array;
|
|
351
366
|
int current_nesting;
|
|
367
|
+
unsigned int emitted_deprecations;
|
|
352
368
|
} JSON_ParserState;
|
|
353
369
|
|
|
354
370
|
static inline size_t rest(JSON_ParserState *state) {
|
|
@@ -400,14 +416,9 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
|
|
|
400
416
|
|
|
401
417
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
|
402
418
|
|
|
403
|
-
|
|
404
|
-
RBIMPL_ATTR_NORETURN()
|
|
405
|
-
#endif
|
|
406
|
-
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
419
|
+
static VALUE build_parse_error_message(const char *format, JSON_ParserState *state, long line, long column)
|
|
407
420
|
{
|
|
408
421
|
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
|
409
|
-
long line, column;
|
|
410
|
-
cursor_position(state, &line, &column);
|
|
411
422
|
|
|
412
423
|
const char *ptr = "EOF";
|
|
413
424
|
if (state->cursor && state->cursor < state->end) {
|
|
@@ -439,20 +450,28 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
|
439
450
|
}
|
|
440
451
|
}
|
|
441
452
|
|
|
442
|
-
VALUE
|
|
443
|
-
|
|
444
|
-
|
|
453
|
+
VALUE message = rb_enc_sprintf(enc_utf8, format, ptr);
|
|
454
|
+
rb_str_catf(message, " at line %ld column %ld", line, column);
|
|
455
|
+
return message;
|
|
456
|
+
}
|
|
445
457
|
|
|
458
|
+
static VALUE parse_error_new(VALUE message, long line, long column)
|
|
459
|
+
{
|
|
446
460
|
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
|
447
461
|
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
|
448
462
|
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
|
449
|
-
|
|
463
|
+
return exc;
|
|
450
464
|
}
|
|
451
465
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
466
|
+
NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
467
|
+
{
|
|
468
|
+
long line, column;
|
|
469
|
+
cursor_position(state, &line, &column);
|
|
470
|
+
VALUE message = build_parse_error_message(format, state, line, column);
|
|
471
|
+
rb_exc_raise(parse_error_new(message, line, column));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
|
456
475
|
{
|
|
457
476
|
state->cursor = at;
|
|
458
477
|
raise_parse_error(format, state);
|
|
@@ -752,6 +771,10 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
|
|
|
752
771
|
}
|
|
753
772
|
raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
|
|
754
773
|
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
if (config->allow_invalid_escape) {
|
|
777
|
+
APPEND_CHAR(*pe);
|
|
755
778
|
} else {
|
|
756
779
|
raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
|
|
757
780
|
}
|
|
@@ -776,20 +799,39 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
|
|
|
776
799
|
}
|
|
777
800
|
|
|
778
801
|
#define MAX_FAST_INTEGER_SIZE 18
|
|
802
|
+
#define MAX_NUMBER_STACK_BUFFER 128
|
|
803
|
+
|
|
804
|
+
typedef VALUE (*json_number_decode_func_t)(const char *ptr);
|
|
805
|
+
|
|
806
|
+
static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
|
|
807
|
+
{
|
|
808
|
+
if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
|
|
809
|
+
char buffer[MAX_NUMBER_STACK_BUFFER];
|
|
810
|
+
MEMCPY(buffer, start, char, len);
|
|
811
|
+
buffer[len] = '\0';
|
|
812
|
+
return func(buffer);
|
|
813
|
+
} else {
|
|
814
|
+
VALUE buffer_v = rb_str_tmp_new(len);
|
|
815
|
+
char *buffer = RSTRING_PTR(buffer_v);
|
|
816
|
+
MEMCPY(buffer, start, char, len);
|
|
817
|
+
buffer[len] = '\0';
|
|
818
|
+
VALUE number = func(buffer);
|
|
819
|
+
RB_GC_GUARD(buffer_v);
|
|
820
|
+
return number;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
779
823
|
|
|
780
|
-
static VALUE
|
|
824
|
+
static VALUE json_decode_inum(const char *buffer)
|
|
781
825
|
{
|
|
782
|
-
|
|
783
|
-
char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1);
|
|
784
|
-
MEMCPY(buffer, start, char, len);
|
|
785
|
-
buffer[len] = '\0';
|
|
786
|
-
VALUE number = rb_cstr2inum(buffer, 10);
|
|
787
|
-
RB_ALLOCV_END(buffer_v);
|
|
788
|
-
return number;
|
|
826
|
+
return rb_cstr2inum(buffer, 10);
|
|
789
827
|
}
|
|
790
828
|
|
|
791
|
-
static
|
|
792
|
-
|
|
829
|
+
NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
|
|
830
|
+
{
|
|
831
|
+
return json_decode_large_number(start, len, json_decode_inum);
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
|
|
793
835
|
{
|
|
794
836
|
if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
|
|
795
837
|
if (negative) {
|
|
@@ -801,28 +843,20 @@ json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const
|
|
|
801
843
|
return json_decode_large_integer(start, end - start);
|
|
802
844
|
}
|
|
803
845
|
|
|
804
|
-
static VALUE
|
|
846
|
+
static VALUE json_decode_dnum(const char *buffer)
|
|
805
847
|
{
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
MEMCPY(buffer, start, char, len);
|
|
809
|
-
buffer[len] = '\0';
|
|
810
|
-
return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
|
|
811
|
-
}
|
|
848
|
+
return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
|
|
849
|
+
}
|
|
812
850
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
buffer[len] = '\0';
|
|
817
|
-
VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1));
|
|
818
|
-
RB_ALLOCV_END(buffer_v);
|
|
819
|
-
return number;
|
|
851
|
+
NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
|
|
852
|
+
{
|
|
853
|
+
return json_decode_large_number(start, len, json_decode_dnum);
|
|
820
854
|
}
|
|
821
855
|
|
|
822
856
|
/* Ruby JSON optimized float decoder using vendored Ryu algorithm
|
|
823
857
|
* Accepts pre-extracted mantissa and exponent from first-pass validation
|
|
824
858
|
*/
|
|
825
|
-
static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits,
|
|
859
|
+
static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative,
|
|
826
860
|
const char *start, const char *end)
|
|
827
861
|
{
|
|
828
862
|
if (RB_UNLIKELY(config->decimal_class)) {
|
|
@@ -830,13 +864,21 @@ static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantis
|
|
|
830
864
|
return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
|
|
831
865
|
}
|
|
832
866
|
|
|
867
|
+
if (RB_UNLIKELY(exponent > INT32_MAX)) {
|
|
868
|
+
return negative ? CMinusInfinity : CInfinity;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
if (RB_UNLIKELY(exponent < INT32_MIN)) {
|
|
872
|
+
return rb_float_new(negative ? -0.0 : 0.0);
|
|
873
|
+
}
|
|
874
|
+
|
|
833
875
|
// Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
|
|
834
876
|
// Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
|
|
835
877
|
if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
|
|
836
878
|
return json_decode_large_float(start, end - start);
|
|
837
879
|
}
|
|
838
880
|
|
|
839
|
-
return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, exponent, negative));
|
|
881
|
+
return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative));
|
|
840
882
|
}
|
|
841
883
|
|
|
842
884
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
|
@@ -868,7 +910,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
|
|
|
868
910
|
return Qfalse;
|
|
869
911
|
}
|
|
870
912
|
|
|
871
|
-
static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
|
913
|
+
NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
|
872
914
|
{
|
|
873
915
|
VALUE message = rb_sprintf(
|
|
874
916
|
"detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
|
|
@@ -879,18 +921,17 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_
|
|
|
879
921
|
RB_GC_GUARD(message);
|
|
880
922
|
}
|
|
881
923
|
|
|
882
|
-
|
|
883
|
-
RBIMPL_ATTR_NORETURN()
|
|
884
|
-
#endif
|
|
885
|
-
static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
|
924
|
+
NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
|
886
925
|
{
|
|
887
926
|
VALUE message = rb_sprintf(
|
|
888
927
|
"duplicate key %"PRIsVALUE,
|
|
889
928
|
rb_inspect(duplicate_key)
|
|
890
929
|
);
|
|
891
930
|
|
|
892
|
-
|
|
893
|
-
|
|
931
|
+
long line, column;
|
|
932
|
+
cursor_position(state, &line, &column);
|
|
933
|
+
rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
|
|
934
|
+
rb_exc_raise(parse_error_new(message, line, column));
|
|
894
935
|
}
|
|
895
936
|
|
|
896
937
|
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
|
|
@@ -905,7 +946,12 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
|
|
|
905
946
|
case JSON_IGNORE:
|
|
906
947
|
break;
|
|
907
948
|
case JSON_DEPRECATED:
|
|
908
|
-
|
|
949
|
+
// Only emit the first few deprecations to avoid spamming.
|
|
950
|
+
if (state->emitted_deprecations < 5) {
|
|
951
|
+
emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
|
|
952
|
+
state->emitted_deprecations++;
|
|
953
|
+
}
|
|
954
|
+
|
|
909
955
|
break;
|
|
910
956
|
case JSON_RAISE:
|
|
911
957
|
raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
|
|
@@ -927,7 +973,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
|
|
|
927
973
|
if (RB_UNLIKELY(config->on_load_proc)) {
|
|
928
974
|
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
|
929
975
|
}
|
|
930
|
-
rvalue_stack_push(state->stack, value,
|
|
976
|
+
rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
|
|
931
977
|
return value;
|
|
932
978
|
}
|
|
933
979
|
|
|
@@ -1112,7 +1158,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
|
|
|
1112
1158
|
const char first_digit = *state->cursor;
|
|
1113
1159
|
|
|
1114
1160
|
// Variables for Ryu optimization - extract digits during parsing
|
|
1115
|
-
|
|
1161
|
+
int64_t exponent = 0;
|
|
1116
1162
|
int decimal_point_pos = -1;
|
|
1117
1163
|
uint64_t mantissa = 0;
|
|
1118
1164
|
|
|
@@ -1156,7 +1202,11 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
|
|
|
1156
1202
|
raise_parse_error_at("invalid number: %s", state, start);
|
|
1157
1203
|
}
|
|
1158
1204
|
|
|
1159
|
-
|
|
1205
|
+
if (RB_UNLIKELY(exponent_digits >= 20 || abs_exponent > (uint64_t)INT64_MAX)) {
|
|
1206
|
+
exponent = negative_exponent ? INT64_MIN : INT64_MAX;
|
|
1207
|
+
} else {
|
|
1208
|
+
exponent = negative_exponent ? -(int64_t)abs_exponent : (int64_t)abs_exponent;
|
|
1209
|
+
}
|
|
1160
1210
|
}
|
|
1161
1211
|
|
|
1162
1212
|
if (integer) {
|
|
@@ -1411,39 +1461,56 @@ static void json_ensure_eof(JSON_ParserState *state)
|
|
|
1411
1461
|
|
|
1412
1462
|
static VALUE convert_encoding(VALUE source)
|
|
1413
1463
|
{
|
|
1414
|
-
|
|
1464
|
+
StringValue(source);
|
|
1465
|
+
int encindex = RB_ENCODING_GET(source);
|
|
1466
|
+
|
|
1467
|
+
if (RB_LIKELY(encindex == utf8_encindex)) {
|
|
1468
|
+
return source;
|
|
1469
|
+
}
|
|
1415
1470
|
|
|
1416
|
-
|
|
1471
|
+
if (encindex == binary_encindex) {
|
|
1472
|
+
// For historical reason, we silently reinterpret binary strings as UTF-8
|
|
1473
|
+
return rb_enc_associate_index(rb_str_dup(source), utf8_encindex);
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
source = rb_funcall(source, i_encode, 1, Encoding_UTF_8);
|
|
1477
|
+
StringValue(source);
|
|
1417
1478
|
return source;
|
|
1418
|
-
|
|
1479
|
+
}
|
|
1419
1480
|
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1481
|
+
struct parser_config_init_args {
|
|
1482
|
+
JSON_ParserConfig *config;
|
|
1483
|
+
VALUE self;
|
|
1484
|
+
};
|
|
1424
1485
|
|
|
1425
|
-
|
|
1486
|
+
static void parser_config_wb_write(VALUE self, VALUE *dest, VALUE val)
|
|
1487
|
+
{
|
|
1488
|
+
*dest = val;
|
|
1489
|
+
if (self) RB_OBJ_WRITTEN(self, Qundef, val);
|
|
1426
1490
|
}
|
|
1427
1491
|
|
|
1428
1492
|
static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1429
1493
|
{
|
|
1430
|
-
|
|
1494
|
+
struct parser_config_init_args *args = (struct parser_config_init_args *)data;
|
|
1495
|
+
JSON_ParserConfig *config = args->config;
|
|
1496
|
+
VALUE self = args->self;
|
|
1431
1497
|
|
|
1432
1498
|
if (key == sym_max_nesting) { config->max_nesting = RTEST(val) ? FIX2INT(val) : 0; }
|
|
1433
1499
|
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
|
|
1434
1500
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
|
1435
1501
|
else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
|
|
1502
|
+
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
|
|
1436
1503
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
|
1437
1504
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
|
1438
|
-
else if (key == sym_on_load) { config->on_load_proc
|
|
1505
|
+
else if (key == sym_on_load) { parser_config_wb_write(self, &config->on_load_proc, RTEST(val) ? val : Qfalse); }
|
|
1439
1506
|
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
|
1440
1507
|
else if (key == sym_decimal_class) {
|
|
1441
1508
|
if (RTEST(val)) {
|
|
1442
1509
|
if (rb_respond_to(val, i_try_convert)) {
|
|
1443
|
-
config->decimal_class
|
|
1510
|
+
parser_config_wb_write(self, &config->decimal_class, val);
|
|
1444
1511
|
config->decimal_method_id = i_try_convert;
|
|
1445
1512
|
} else if (rb_respond_to(val, i_new)) {
|
|
1446
|
-
config->decimal_class
|
|
1513
|
+
parser_config_wb_write(self, &config->decimal_class, val);
|
|
1447
1514
|
config->decimal_method_id = i_new;
|
|
1448
1515
|
} else if (RB_TYPE_P(val, T_CLASS)) {
|
|
1449
1516
|
VALUE name = rb_class_name(val);
|
|
@@ -1452,7 +1519,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1452
1519
|
if (last_colon) {
|
|
1453
1520
|
const char *mod_path_end = last_colon - 1;
|
|
1454
1521
|
VALUE mod_path = rb_str_substr(name, 0, mod_path_end - name_cstr);
|
|
1455
|
-
config->decimal_class
|
|
1522
|
+
parser_config_wb_write(self, &config->decimal_class, rb_path_to_class(mod_path));
|
|
1456
1523
|
|
|
1457
1524
|
const char *method_name_beg = last_colon + 1;
|
|
1458
1525
|
long before_len = method_name_beg - name_cstr;
|
|
@@ -1460,7 +1527,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1460
1527
|
VALUE method_name = rb_str_substr(name, before_len, len);
|
|
1461
1528
|
config->decimal_method_id = SYM2ID(rb_str_intern(method_name));
|
|
1462
1529
|
} else {
|
|
1463
|
-
config->decimal_class
|
|
1530
|
+
parser_config_wb_write(self, &config->decimal_class, rb_mKernel);
|
|
1464
1531
|
config->decimal_method_id = SYM2ID(rb_str_intern(name));
|
|
1465
1532
|
}
|
|
1466
1533
|
}
|
|
@@ -1470,16 +1537,21 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1470
1537
|
return ST_CONTINUE;
|
|
1471
1538
|
}
|
|
1472
1539
|
|
|
1473
|
-
static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
|
|
1540
|
+
static void parser_config_init(JSON_ParserConfig *config, VALUE opts, VALUE self)
|
|
1474
1541
|
{
|
|
1475
1542
|
config->max_nesting = 100;
|
|
1476
1543
|
|
|
1544
|
+
struct parser_config_init_args args = {
|
|
1545
|
+
.config = config,
|
|
1546
|
+
.self = self,
|
|
1547
|
+
};
|
|
1548
|
+
|
|
1477
1549
|
if (!NIL_P(opts)) {
|
|
1478
1550
|
Check_Type(opts, T_HASH);
|
|
1479
1551
|
if (RHASH_SIZE(opts) > 0) {
|
|
1480
1552
|
// We assume in most cases few keys are set so it's faster to go over
|
|
1481
1553
|
// the provided keys than to check all possible keys.
|
|
1482
|
-
rb_hash_foreach(opts, parser_config_init_i, (VALUE)
|
|
1554
|
+
rb_hash_foreach(opts, parser_config_init_i, (VALUE)&args);
|
|
1483
1555
|
}
|
|
1484
1556
|
|
|
1485
1557
|
}
|
|
@@ -1513,17 +1585,21 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
|
|
|
1513
1585
|
rb_check_frozen(self);
|
|
1514
1586
|
GET_PARSER_CONFIG;
|
|
1515
1587
|
|
|
1516
|
-
parser_config_init(config, opts);
|
|
1517
|
-
|
|
1518
|
-
RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
|
|
1588
|
+
parser_config_init(config, opts, self);
|
|
1519
1589
|
|
|
1520
1590
|
return self;
|
|
1521
1591
|
}
|
|
1522
1592
|
|
|
1523
|
-
static VALUE cParser_parse(JSON_ParserConfig *config, VALUE
|
|
1593
|
+
static VALUE cParser_parse(JSON_ParserConfig *config, VALUE src)
|
|
1524
1594
|
{
|
|
1525
|
-
Vsource = convert_encoding(
|
|
1526
|
-
|
|
1595
|
+
VALUE Vsource = convert_encoding(src);
|
|
1596
|
+
|
|
1597
|
+
// Ensure the string isn't mutated under us.
|
|
1598
|
+
// The classic API to use is `rb_str_locktmp`, but then we'd
|
|
1599
|
+
// need to use `rb_protect` to make sure we always unlock.
|
|
1600
|
+
if (Vsource == src) {
|
|
1601
|
+
Vsource = rb_str_new_frozen(Vsource);
|
|
1602
|
+
}
|
|
1527
1603
|
|
|
1528
1604
|
VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA];
|
|
1529
1605
|
rvalue_stack stack = {
|
|
@@ -1534,13 +1610,16 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1534
1610
|
|
|
1535
1611
|
long len;
|
|
1536
1612
|
const char *start;
|
|
1613
|
+
|
|
1537
1614
|
RSTRING_GETMEM(Vsource, start, len);
|
|
1538
1615
|
|
|
1616
|
+
VALUE stack_handle = 0;
|
|
1539
1617
|
JSON_ParserState _state = {
|
|
1540
1618
|
.start = start,
|
|
1541
1619
|
.cursor = start,
|
|
1542
1620
|
.end = start + len,
|
|
1543
1621
|
.stack = &stack,
|
|
1622
|
+
.stack_handle = &stack_handle,
|
|
1544
1623
|
};
|
|
1545
1624
|
JSON_ParserState *state = &_state;
|
|
1546
1625
|
|
|
@@ -1548,8 +1627,9 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1548
1627
|
|
|
1549
1628
|
// This may be skipped in case of exception, but
|
|
1550
1629
|
// it won't cause a leak.
|
|
1551
|
-
rvalue_stack_eagerly_release(
|
|
1552
|
-
|
|
1630
|
+
rvalue_stack_eagerly_release(stack_handle);
|
|
1631
|
+
RB_GC_GUARD(stack_handle);
|
|
1632
|
+
RB_GC_GUARD(Vsource);
|
|
1553
1633
|
json_ensure_eof(state);
|
|
1554
1634
|
|
|
1555
1635
|
return result;
|
|
@@ -1570,12 +1650,9 @@ static VALUE cParserConfig_parse(VALUE self, VALUE Vsource)
|
|
|
1570
1650
|
|
|
1571
1651
|
static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
|
|
1572
1652
|
{
|
|
1573
|
-
Vsource = convert_encoding(StringValue(Vsource));
|
|
1574
|
-
StringValue(Vsource);
|
|
1575
|
-
|
|
1576
1653
|
JSON_ParserConfig _config = {0};
|
|
1577
1654
|
JSON_ParserConfig *config = &_config;
|
|
1578
|
-
parser_config_init(config, opts);
|
|
1655
|
+
parser_config_init(config, opts, false);
|
|
1579
1656
|
|
|
1580
1657
|
return cParser_parse(config, Vsource);
|
|
1581
1658
|
}
|
|
@@ -1587,26 +1664,19 @@ static void JSON_ParserConfig_mark(void *ptr)
|
|
|
1587
1664
|
rb_gc_mark(config->decimal_class);
|
|
1588
1665
|
}
|
|
1589
1666
|
|
|
1590
|
-
static void JSON_ParserConfig_free(void *ptr)
|
|
1591
|
-
{
|
|
1592
|
-
JSON_ParserConfig *config = ptr;
|
|
1593
|
-
ruby_xfree(config);
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
1667
|
static size_t JSON_ParserConfig_memsize(const void *ptr)
|
|
1597
1668
|
{
|
|
1598
1669
|
return sizeof(JSON_ParserConfig);
|
|
1599
1670
|
}
|
|
1600
1671
|
|
|
1601
1672
|
static const rb_data_type_t JSON_ParserConfig_type = {
|
|
1602
|
-
"JSON::Ext::Parser/ParserConfig",
|
|
1603
|
-
{
|
|
1673
|
+
.wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
|
|
1674
|
+
.function = {
|
|
1604
1675
|
JSON_ParserConfig_mark,
|
|
1605
|
-
|
|
1676
|
+
RUBY_DEFAULT_FREE,
|
|
1606
1677
|
JSON_ParserConfig_memsize,
|
|
1607
1678
|
},
|
|
1608
|
-
|
|
1609
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
1679
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
|
|
1610
1680
|
};
|
|
1611
1681
|
|
|
1612
1682
|
static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
@@ -1651,6 +1721,7 @@ void Init_parser(void)
|
|
|
1651
1721
|
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
|
1652
1722
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
|
1653
1723
|
sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
|
|
1724
|
+
sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
|
|
1654
1725
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
|
1655
1726
|
sym_freeze = ID2SYM(rb_intern("freeze"));
|
|
1656
1727
|
sym_on_load = ID2SYM(rb_intern("on_load"));
|
data/ext/json/ext/simd/simd.h
CHANGED
|
@@ -133,16 +133,6 @@ ALWAYS_INLINE(static) int string_scan_simd_neon(const char **ptr, const char *en
|
|
|
133
133
|
return 0;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
|
-
static inline uint8x16x4_t load_uint8x16_4(const unsigned char *table)
|
|
137
|
-
{
|
|
138
|
-
uint8x16x4_t tab;
|
|
139
|
-
tab.val[0] = vld1q_u8(table);
|
|
140
|
-
tab.val[1] = vld1q_u8(table+16);
|
|
141
|
-
tab.val[2] = vld1q_u8(table+32);
|
|
142
|
-
tab.val[3] = vld1q_u8(table+48);
|
|
143
|
-
return tab;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
136
|
#endif /* ARM Neon Support.*/
|
|
147
137
|
|
|
148
138
|
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
data/lib/json/common.rb
CHANGED
|
@@ -156,15 +156,17 @@ module JSON
|
|
|
156
156
|
def generator=(generator) # :nodoc:
|
|
157
157
|
old, $VERBOSE = $VERBOSE, nil
|
|
158
158
|
@generator = generator
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
159
|
+
if generator.const_defined?(:GeneratorMethods)
|
|
160
|
+
generator_methods = generator::GeneratorMethods
|
|
161
|
+
for const in generator_methods.constants
|
|
162
|
+
klass = const_get(const)
|
|
163
|
+
modul = generator_methods.const_get(const)
|
|
164
|
+
klass.class_eval do
|
|
165
|
+
instance_methods(false).each do |m|
|
|
166
|
+
m.to_s == 'to_json' and remove_method m
|
|
167
|
+
end
|
|
168
|
+
include modul
|
|
166
169
|
end
|
|
167
|
-
include modul
|
|
168
170
|
end
|
|
169
171
|
end
|
|
170
172
|
self.state = generator::State
|
|
@@ -878,7 +880,7 @@ module JSON
|
|
|
878
880
|
end
|
|
879
881
|
end
|
|
880
882
|
|
|
881
|
-
if opts[:allow_blank] && (source.nil? || source.empty?)
|
|
883
|
+
if opts[:allow_blank] && (source.nil? || (String === source && source.empty?))
|
|
882
884
|
source = 'null'
|
|
883
885
|
end
|
|
884
886
|
|
|
@@ -1036,7 +1038,8 @@ module JSON
|
|
|
1036
1038
|
# JSON.new(options = nil, &block)
|
|
1037
1039
|
#
|
|
1038
1040
|
# Argument +options+, if given, contains a \Hash of options for both parsing and generating.
|
|
1039
|
-
# See {Parsing Options}[
|
|
1041
|
+
# See {Parsing Options}[rdoc-ref:JSON@Parsing+Options],
|
|
1042
|
+
# and {Generating Options}[rdoc-ref:JSON@Generating+Options].
|
|
1040
1043
|
#
|
|
1041
1044
|
# For generation, the <tt>strict: true</tt> option is always set. When a Ruby object with no native \JSON counterpart is
|
|
1042
1045
|
# encountered, the block provided to the initialize method is invoked, and must return a Ruby object that has a native
|
|
@@ -1095,6 +1098,30 @@ module JSON
|
|
|
1095
1098
|
load(File.read(path, encoding: Encoding::UTF_8))
|
|
1096
1099
|
end
|
|
1097
1100
|
end
|
|
1101
|
+
|
|
1102
|
+
module GeneratorMethods
|
|
1103
|
+
# call-seq: to_json(*)
|
|
1104
|
+
#
|
|
1105
|
+
# Converts this object into a JSON string.
|
|
1106
|
+
# If this object doesn't directly maps to a JSON native type,
|
|
1107
|
+
# first convert it to a string (calling #to_s), then converts
|
|
1108
|
+
# it to a JSON string, and returns the result.
|
|
1109
|
+
# This is a fallback, if no special method #to_json was defined for some object.
|
|
1110
|
+
def to_json(state = nil, *)
|
|
1111
|
+
obj = case self
|
|
1112
|
+
when nil, false, true, Integer, Float, Array, Hash
|
|
1113
|
+
self
|
|
1114
|
+
else
|
|
1115
|
+
"#{self}"
|
|
1116
|
+
end
|
|
1117
|
+
|
|
1118
|
+
if state.nil?
|
|
1119
|
+
JSON::State._generate_no_fallback(obj, nil, nil)
|
|
1120
|
+
else
|
|
1121
|
+
JSON::State.from_state(state)._generate_no_fallback(obj)
|
|
1122
|
+
end
|
|
1123
|
+
end
|
|
1124
|
+
end
|
|
1098
1125
|
end
|
|
1099
1126
|
|
|
1100
1127
|
module ::Kernel
|
|
@@ -1140,3 +1167,7 @@ module ::Kernel
|
|
|
1140
1167
|
JSON[object, opts]
|
|
1141
1168
|
end
|
|
1142
1169
|
end
|
|
1170
|
+
|
|
1171
|
+
class Object
|
|
1172
|
+
include JSON::GeneratorMethods
|
|
1173
|
+
end
|
|
@@ -9,7 +9,7 @@ module JSON
|
|
|
9
9
|
# Instantiates a new State object, configured by _opts_.
|
|
10
10
|
#
|
|
11
11
|
# Argument +opts+, if given, contains a \Hash of options for the generation.
|
|
12
|
-
# See {Generating Options}[
|
|
12
|
+
# See {Generating Options}[rdoc-ref:JSON@Generating+Options].
|
|
13
13
|
def initialize(opts = nil)
|
|
14
14
|
if opts && !opts.empty?
|
|
15
15
|
configure(opts)
|