json 2.18.1 → 2.19.5
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 +33 -0
- data/ext/json/ext/fbuffer/fbuffer.h +17 -15
- data/ext/json/ext/generator/extconf.rb +2 -0
- data/ext/json/ext/generator/generator.c +78 -310
- data/ext/json/ext/json.h +15 -0
- data/ext/json/ext/parser/extconf.rb +4 -0
- data/ext/json/ext/parser/parser.c +118 -75
- 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
|
+
}
|
|
823
|
+
|
|
824
|
+
static VALUE json_decode_inum(const char *buffer)
|
|
825
|
+
{
|
|
826
|
+
return rb_cstr2inum(buffer, 10);
|
|
827
|
+
}
|
|
779
828
|
|
|
780
|
-
static VALUE json_decode_large_integer(const char *start, long len)
|
|
829
|
+
NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
|
|
781
830
|
{
|
|
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;
|
|
831
|
+
return json_decode_large_number(start, len, json_decode_inum);
|
|
789
832
|
}
|
|
790
833
|
|
|
791
|
-
static inline VALUE
|
|
792
|
-
json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
|
|
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,7 @@ 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
|
-
exponent = negative_exponent ? -
|
|
1205
|
+
exponent = negative_exponent ? -abs_exponent : abs_exponent;
|
|
1160
1206
|
}
|
|
1161
1207
|
|
|
1162
1208
|
if (integer) {
|
|
@@ -1433,6 +1479,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1433
1479
|
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
|
|
1434
1480
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
|
1435
1481
|
else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
|
|
1482
|
+
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
|
|
1436
1483
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
|
1437
1484
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
|
1438
1485
|
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
|
@@ -1536,11 +1583,13 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1536
1583
|
const char *start;
|
|
1537
1584
|
RSTRING_GETMEM(Vsource, start, len);
|
|
1538
1585
|
|
|
1586
|
+
VALUE stack_handle = 0;
|
|
1539
1587
|
JSON_ParserState _state = {
|
|
1540
1588
|
.start = start,
|
|
1541
1589
|
.cursor = start,
|
|
1542
1590
|
.end = start + len,
|
|
1543
1591
|
.stack = &stack,
|
|
1592
|
+
.stack_handle = &stack_handle,
|
|
1544
1593
|
};
|
|
1545
1594
|
JSON_ParserState *state = &_state;
|
|
1546
1595
|
|
|
@@ -1548,8 +1597,8 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1548
1597
|
|
|
1549
1598
|
// This may be skipped in case of exception, but
|
|
1550
1599
|
// it won't cause a leak.
|
|
1551
|
-
rvalue_stack_eagerly_release(
|
|
1552
|
-
|
|
1600
|
+
rvalue_stack_eagerly_release(stack_handle);
|
|
1601
|
+
RB_GC_GUARD(stack_handle);
|
|
1553
1602
|
json_ensure_eof(state);
|
|
1554
1603
|
|
|
1555
1604
|
return result;
|
|
@@ -1587,26 +1636,19 @@ static void JSON_ParserConfig_mark(void *ptr)
|
|
|
1587
1636
|
rb_gc_mark(config->decimal_class);
|
|
1588
1637
|
}
|
|
1589
1638
|
|
|
1590
|
-
static void JSON_ParserConfig_free(void *ptr)
|
|
1591
|
-
{
|
|
1592
|
-
JSON_ParserConfig *config = ptr;
|
|
1593
|
-
ruby_xfree(config);
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
1639
|
static size_t JSON_ParserConfig_memsize(const void *ptr)
|
|
1597
1640
|
{
|
|
1598
1641
|
return sizeof(JSON_ParserConfig);
|
|
1599
1642
|
}
|
|
1600
1643
|
|
|
1601
1644
|
static const rb_data_type_t JSON_ParserConfig_type = {
|
|
1602
|
-
"JSON::Ext::Parser/ParserConfig",
|
|
1603
|
-
{
|
|
1645
|
+
.wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
|
|
1646
|
+
.function = {
|
|
1604
1647
|
JSON_ParserConfig_mark,
|
|
1605
|
-
|
|
1648
|
+
RUBY_DEFAULT_FREE,
|
|
1606
1649
|
JSON_ParserConfig_memsize,
|
|
1607
1650
|
},
|
|
1608
|
-
|
|
1609
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
1651
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
|
|
1610
1652
|
};
|
|
1611
1653
|
|
|
1612
1654
|
static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
@@ -1651,6 +1693,7 @@ void Init_parser(void)
|
|
|
1651
1693
|
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
|
1652
1694
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
|
1653
1695
|
sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
|
|
1696
|
+
sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
|
|
1654
1697
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
|
1655
1698
|
sym_freeze = ID2SYM(rb_intern("freeze"));
|
|
1656
1699
|
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)
|
|
@@ -48,7 +48,7 @@ module JSON
|
|
|
48
48
|
SCRIPT_SAFE_ESCAPE_PATTERN = /[\/"\\\x0-\x1f\u2028-\u2029]/
|
|
49
49
|
|
|
50
50
|
def self.native_type?(value) # :nodoc:
|
|
51
|
-
(false == value || true == value || nil == value || String === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
|
51
|
+
(false == value || true == value || nil == value || String === value || Symbol === value || Array === value || Hash === value || Integer === value || Float === value || Fragment === value)
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
def self.native_key?(key) # :nodoc:
|
|
@@ -211,7 +211,14 @@ module JSON
|
|
|
211
211
|
|
|
212
212
|
# This integer returns the current depth data structure nesting in the
|
|
213
213
|
# generated JSON.
|
|
214
|
-
|
|
214
|
+
attr_reader :depth
|
|
215
|
+
|
|
216
|
+
def depth=(depth)
|
|
217
|
+
if depth.negative?
|
|
218
|
+
raise ArgumentError, "depth must be >= 0 (got #{depth})"
|
|
219
|
+
end
|
|
220
|
+
@depth = depth
|
|
221
|
+
end
|
|
215
222
|
|
|
216
223
|
def check_max_nesting # :nodoc:
|
|
217
224
|
return if @max_nesting.zero?
|
|
@@ -260,6 +267,11 @@ module JSON
|
|
|
260
267
|
else
|
|
261
268
|
raise TypeError, "can't convert #{opts.class} into Hash"
|
|
262
269
|
end
|
|
270
|
+
|
|
271
|
+
if opts[:depth]&.negative?
|
|
272
|
+
raise ArgumentError, "depth must be >= 0 (got #{opts[:depth]})"
|
|
273
|
+
end
|
|
274
|
+
|
|
263
275
|
opts.each do |key, value|
|
|
264
276
|
instance_variable_set "@#{key}", value
|
|
265
277
|
end
|
|
@@ -505,11 +517,11 @@ module JSON
|
|
|
505
517
|
|
|
506
518
|
if empty?
|
|
507
519
|
state.depth -= 1
|
|
508
|
-
return '{}'
|
|
520
|
+
return +'{}'
|
|
509
521
|
end
|
|
510
522
|
|
|
511
523
|
delim = ",#{state.object_nl}"
|
|
512
|
-
result =
|
|
524
|
+
result = "{#{state.object_nl}"
|
|
513
525
|
first = true
|
|
514
526
|
key_type = nil
|
|
515
527
|
indent = !state.object_nl.empty?
|
|
@@ -546,7 +558,7 @@ module JSON
|
|
|
546
558
|
raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String"
|
|
547
559
|
end
|
|
548
560
|
|
|
549
|
-
result =
|
|
561
|
+
result = "#{result}#{key_json}#{state.space_before}:#{state.space}"
|
|
550
562
|
if state.strict? && !Generator.native_type?(value)
|
|
551
563
|
if state.as_json
|
|
552
564
|
value = state.as_json.call(value, false)
|
|
@@ -597,7 +609,7 @@ module JSON
|
|
|
597
609
|
|
|
598
610
|
if empty?
|
|
599
611
|
state.depth -= 1
|
|
600
|
-
return '[]'
|
|
612
|
+
return +'[]'
|
|
601
613
|
end
|
|
602
614
|
|
|
603
615
|
result = '['.dup
|
|
@@ -722,17 +734,17 @@ module JSON
|
|
|
722
734
|
|
|
723
735
|
module TrueClass
|
|
724
736
|
# Returns a JSON string for true: 'true'.
|
|
725
|
-
def to_json(*) 'true' end
|
|
737
|
+
def to_json(*) +'true' end
|
|
726
738
|
end
|
|
727
739
|
|
|
728
740
|
module FalseClass
|
|
729
741
|
# Returns a JSON string for false: 'false'.
|
|
730
|
-
def to_json(*) 'false' end
|
|
742
|
+
def to_json(*) +'false' end
|
|
731
743
|
end
|
|
732
744
|
|
|
733
745
|
module NilClass
|
|
734
746
|
# Returns a JSON string for nil: 'null'.
|
|
735
|
-
def to_json(*) 'null' end
|
|
747
|
+
def to_json(*) +'null' end
|
|
736
748
|
end
|
|
737
749
|
end
|
|
738
750
|
end
|
data/lib/json/version.rb
CHANGED
data/lib/json.rb
CHANGED
|
@@ -194,6 +194,18 @@ require 'json/common'
|
|
|
194
194
|
# When enabled:
|
|
195
195
|
# JSON.parse(%{"Hello\nWorld"}, allow_control_characters: true) # => "Hello\nWorld"
|
|
196
196
|
#
|
|
197
|
+
# ---
|
|
198
|
+
#
|
|
199
|
+
# Option +allow_invalid_escape+ (boolean) specifies whether to ignore backslahes that are followed
|
|
200
|
+
# by an invalid escape character in strings;
|
|
201
|
+
# defaults to +false+.
|
|
202
|
+
#
|
|
203
|
+
# With the default, +false+:
|
|
204
|
+
# JSON.parse('"Hell\o"') # invalid escape character in string (JSON::ParserError)
|
|
205
|
+
#
|
|
206
|
+
# When enabled:
|
|
207
|
+
# JSON.parse('"Hell\o"', allow_invalid_escape: true) # => "Hello"
|
|
208
|
+
#
|
|
197
209
|
# ====== Output Options
|
|
198
210
|
#
|
|
199
211
|
# Option +freeze+ (boolean) specifies whether the returned objects will be frozen;
|
|
@@ -323,8 +335,8 @@ require 'json/common'
|
|
|
323
335
|
# JSON.generate(JSON::MinusInfinity)
|
|
324
336
|
#
|
|
325
337
|
# Allow:
|
|
326
|
-
# ruby = [Float::
|
|
327
|
-
# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,-Infinity]'
|
|
338
|
+
# ruby = [Float::NAN, Float::INFINITY, JSON::NaN, JSON::Infinity, JSON::MinusInfinity]
|
|
339
|
+
# JSON.generate(ruby, allow_nan: true) # => '[NaN,Infinity,NaN,Infinity,-Infinity]'
|
|
328
340
|
#
|
|
329
341
|
# ---
|
|
330
342
|
#
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: json
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.19.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Florian Frank
|
|
@@ -84,7 +84,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
84
84
|
- !ruby/object:Gem::Version
|
|
85
85
|
version: '0'
|
|
86
86
|
requirements: []
|
|
87
|
-
rubygems_version: 4.
|
|
87
|
+
rubygems_version: 4.0.6
|
|
88
88
|
specification_version: 4
|
|
89
89
|
summary: JSON Implementation for Ruby
|
|
90
90
|
test_files: []
|