json 2.18.1 → 2.19.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +29 -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 +57 -303
- data/ext/json/ext/json.h +15 -0
- data/ext/json/ext/parser/extconf.rb +4 -0
- data/ext/json/ext/parser/parser.c +111 -74
- 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
data/ext/json/ext/json.h
CHANGED
|
@@ -54,9 +54,24 @@ typedef unsigned char _Bool;
|
|
|
54
54
|
# define RUBY_TYPED_FROZEN_SHAREABLE 0
|
|
55
55
|
#endif
|
|
56
56
|
|
|
57
|
+
#ifdef RUBY_TYPED_EMBEDDABLE
|
|
58
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
59
|
+
#else
|
|
60
|
+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
|
|
61
|
+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
|
|
62
|
+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
|
|
63
|
+
# else
|
|
64
|
+
# define RUBY_TYPED_EMBEDDABLE 0
|
|
65
|
+
# endif
|
|
66
|
+
#endif
|
|
67
|
+
|
|
57
68
|
#ifndef NORETURN
|
|
69
|
+
#if defined(__has_attribute) && __has_attribute(noreturn)
|
|
70
|
+
#define NORETURN(x) __attribute__((noreturn)) x
|
|
71
|
+
#else
|
|
58
72
|
#define NORETURN(x) x
|
|
59
73
|
#endif
|
|
74
|
+
#endif
|
|
60
75
|
|
|
61
76
|
#ifndef NOINLINE
|
|
62
77
|
#if defined(__has_attribute) && __has_attribute(noinline)
|
|
@@ -7,6 +7,10 @@ have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
|
|
|
7
7
|
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
|
|
8
8
|
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
|
|
9
9
|
|
|
10
|
+
if RUBY_ENGINE == "ruby"
|
|
11
|
+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
|
|
12
|
+
end
|
|
13
|
+
|
|
10
14
|
append_cflags("-std=c99")
|
|
11
15
|
|
|
12
16
|
if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])
|
|
@@ -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;
|
|
@@ -400,14 +415,9 @@ static void emit_parse_warning(const char *message, JSON_ParserState *state)
|
|
|
400
415
|
|
|
401
416
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
|
402
417
|
|
|
403
|
-
|
|
404
|
-
RBIMPL_ATTR_NORETURN()
|
|
405
|
-
#endif
|
|
406
|
-
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
418
|
+
static VALUE build_parse_error_message(const char *format, JSON_ParserState *state, long line, long column)
|
|
407
419
|
{
|
|
408
420
|
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
|
409
|
-
long line, column;
|
|
410
|
-
cursor_position(state, &line, &column);
|
|
411
421
|
|
|
412
422
|
const char *ptr = "EOF";
|
|
413
423
|
if (state->cursor && state->cursor < state->end) {
|
|
@@ -439,20 +449,28 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
|
439
449
|
}
|
|
440
450
|
}
|
|
441
451
|
|
|
442
|
-
VALUE
|
|
443
|
-
|
|
444
|
-
|
|
452
|
+
VALUE message = rb_enc_sprintf(enc_utf8, format, ptr);
|
|
453
|
+
rb_str_catf(message, " at line %ld column %ld", line, column);
|
|
454
|
+
return message;
|
|
455
|
+
}
|
|
445
456
|
|
|
457
|
+
static VALUE parse_error_new(VALUE message, long line, long column)
|
|
458
|
+
{
|
|
446
459
|
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
|
447
460
|
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
|
448
461
|
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
|
449
|
-
|
|
462
|
+
return exc;
|
|
450
463
|
}
|
|
451
464
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
465
|
+
NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
466
|
+
{
|
|
467
|
+
long line, column;
|
|
468
|
+
cursor_position(state, &line, &column);
|
|
469
|
+
VALUE message = build_parse_error_message(format, state, line, column);
|
|
470
|
+
rb_exc_raise(parse_error_new(message, line, column));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
NORETURN(static) void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
|
456
474
|
{
|
|
457
475
|
state->cursor = at;
|
|
458
476
|
raise_parse_error(format, state);
|
|
@@ -752,6 +770,10 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
|
|
|
752
770
|
}
|
|
753
771
|
raise_parse_error_at("invalid ASCII control character in string: %s", state, pe - 1);
|
|
754
772
|
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
if (config->allow_invalid_escape) {
|
|
776
|
+
APPEND_CHAR(*pe);
|
|
755
777
|
} else {
|
|
756
778
|
raise_parse_error_at("invalid escape character in string: %s", state, pe - 1);
|
|
757
779
|
}
|
|
@@ -776,20 +798,39 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser
|
|
|
776
798
|
}
|
|
777
799
|
|
|
778
800
|
#define MAX_FAST_INTEGER_SIZE 18
|
|
801
|
+
#define MAX_NUMBER_STACK_BUFFER 128
|
|
802
|
+
|
|
803
|
+
typedef VALUE (*json_number_decode_func_t)(const char *ptr);
|
|
804
|
+
|
|
805
|
+
static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func)
|
|
806
|
+
{
|
|
807
|
+
if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) {
|
|
808
|
+
char buffer[MAX_NUMBER_STACK_BUFFER];
|
|
809
|
+
MEMCPY(buffer, start, char, len);
|
|
810
|
+
buffer[len] = '\0';
|
|
811
|
+
return func(buffer);
|
|
812
|
+
} else {
|
|
813
|
+
VALUE buffer_v = rb_str_tmp_new(len);
|
|
814
|
+
char *buffer = RSTRING_PTR(buffer_v);
|
|
815
|
+
MEMCPY(buffer, start, char, len);
|
|
816
|
+
buffer[len] = '\0';
|
|
817
|
+
VALUE number = func(buffer);
|
|
818
|
+
RB_GC_GUARD(buffer_v);
|
|
819
|
+
return number;
|
|
820
|
+
}
|
|
821
|
+
}
|
|
779
822
|
|
|
780
|
-
static VALUE
|
|
823
|
+
static VALUE json_decode_inum(const char *buffer)
|
|
781
824
|
{
|
|
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;
|
|
825
|
+
return rb_cstr2inum(buffer, 10);
|
|
789
826
|
}
|
|
790
827
|
|
|
791
|
-
static
|
|
792
|
-
|
|
828
|
+
NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len)
|
|
829
|
+
{
|
|
830
|
+
return json_decode_large_number(start, len, json_decode_inum);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end)
|
|
793
834
|
{
|
|
794
835
|
if (RB_LIKELY(mantissa_digits < MAX_FAST_INTEGER_SIZE)) {
|
|
795
836
|
if (negative) {
|
|
@@ -801,28 +842,20 @@ json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const
|
|
|
801
842
|
return json_decode_large_integer(start, end - start);
|
|
802
843
|
}
|
|
803
844
|
|
|
804
|
-
static VALUE
|
|
845
|
+
static VALUE json_decode_dnum(const char *buffer)
|
|
805
846
|
{
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
MEMCPY(buffer, start, char, len);
|
|
809
|
-
buffer[len] = '\0';
|
|
810
|
-
return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
|
|
811
|
-
}
|
|
847
|
+
return DBL2NUM(rb_cstr_to_dbl(buffer, 1));
|
|
848
|
+
}
|
|
812
849
|
|
|
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;
|
|
850
|
+
NOINLINE(static) VALUE json_decode_large_float(const char *start, long len)
|
|
851
|
+
{
|
|
852
|
+
return json_decode_large_number(start, len, json_decode_dnum);
|
|
820
853
|
}
|
|
821
854
|
|
|
822
855
|
/* Ruby JSON optimized float decoder using vendored Ryu algorithm
|
|
823
856
|
* Accepts pre-extracted mantissa and exponent from first-pass validation
|
|
824
857
|
*/
|
|
825
|
-
static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits,
|
|
858
|
+
static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantissa, int mantissa_digits, int64_t exponent, bool negative,
|
|
826
859
|
const char *start, const char *end)
|
|
827
860
|
{
|
|
828
861
|
if (RB_UNLIKELY(config->decimal_class)) {
|
|
@@ -830,13 +863,21 @@ static inline VALUE json_decode_float(JSON_ParserConfig *config, uint64_t mantis
|
|
|
830
863
|
return rb_funcallv(config->decimal_class, config->decimal_method_id, 1, &text);
|
|
831
864
|
}
|
|
832
865
|
|
|
866
|
+
if (RB_UNLIKELY(exponent > INT32_MAX)) {
|
|
867
|
+
return negative ? CMinusInfinity : CInfinity;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
if (RB_UNLIKELY(exponent < INT32_MIN)) {
|
|
871
|
+
return rb_float_new(negative ? -0.0 : 0.0);
|
|
872
|
+
}
|
|
873
|
+
|
|
833
874
|
// Fall back to rb_cstr_to_dbl for potential subnormals (rare edge case)
|
|
834
875
|
// Ryu has rounding issues with subnormals around 1e-310 (< 2.225e-308)
|
|
835
876
|
if (RB_UNLIKELY(mantissa_digits > 17 || mantissa_digits + exponent < -307)) {
|
|
836
877
|
return json_decode_large_float(start, end - start);
|
|
837
878
|
}
|
|
838
879
|
|
|
839
|
-
return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, exponent, negative));
|
|
880
|
+
return DBL2NUM(ryu_s2d_from_parts(mantissa, mantissa_digits, (int32_t)exponent, negative));
|
|
840
881
|
}
|
|
841
882
|
|
|
842
883
|
static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
|
|
@@ -868,7 +909,7 @@ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
|
|
|
868
909
|
return Qfalse;
|
|
869
910
|
}
|
|
870
911
|
|
|
871
|
-
static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
|
912
|
+
NOINLINE(static) void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
|
872
913
|
{
|
|
873
914
|
VALUE message = rb_sprintf(
|
|
874
915
|
"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 +920,17 @@ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_
|
|
|
879
920
|
RB_GC_GUARD(message);
|
|
880
921
|
}
|
|
881
922
|
|
|
882
|
-
|
|
883
|
-
RBIMPL_ATTR_NORETURN()
|
|
884
|
-
#endif
|
|
885
|
-
static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
|
923
|
+
NORETURN(static) void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
|
886
924
|
{
|
|
887
925
|
VALUE message = rb_sprintf(
|
|
888
926
|
"duplicate key %"PRIsVALUE,
|
|
889
927
|
rb_inspect(duplicate_key)
|
|
890
928
|
);
|
|
891
929
|
|
|
892
|
-
|
|
893
|
-
|
|
930
|
+
long line, column;
|
|
931
|
+
cursor_position(state, &line, &column);
|
|
932
|
+
rb_str_concat(message, build_parse_error_message("", state, line, column)) ;
|
|
933
|
+
rb_exc_raise(parse_error_new(message, line, column));
|
|
894
934
|
}
|
|
895
935
|
|
|
896
936
|
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
|
|
@@ -927,7 +967,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
|
|
|
927
967
|
if (RB_UNLIKELY(config->on_load_proc)) {
|
|
928
968
|
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
|
|
929
969
|
}
|
|
930
|
-
rvalue_stack_push(state->stack, value,
|
|
970
|
+
rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
|
|
931
971
|
return value;
|
|
932
972
|
}
|
|
933
973
|
|
|
@@ -1112,7 +1152,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
|
|
|
1112
1152
|
const char first_digit = *state->cursor;
|
|
1113
1153
|
|
|
1114
1154
|
// Variables for Ryu optimization - extract digits during parsing
|
|
1115
|
-
|
|
1155
|
+
int64_t exponent = 0;
|
|
1116
1156
|
int decimal_point_pos = -1;
|
|
1117
1157
|
uint64_t mantissa = 0;
|
|
1118
1158
|
|
|
@@ -1156,7 +1196,7 @@ static inline VALUE json_parse_number(JSON_ParserState *state, JSON_ParserConfig
|
|
|
1156
1196
|
raise_parse_error_at("invalid number: %s", state, start);
|
|
1157
1197
|
}
|
|
1158
1198
|
|
|
1159
|
-
exponent = negative_exponent ? -
|
|
1199
|
+
exponent = negative_exponent ? -abs_exponent : abs_exponent;
|
|
1160
1200
|
}
|
|
1161
1201
|
|
|
1162
1202
|
if (integer) {
|
|
@@ -1433,6 +1473,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
|
1433
1473
|
else if (key == sym_allow_nan) { config->allow_nan = RTEST(val); }
|
|
1434
1474
|
else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
|
|
1435
1475
|
else if (key == sym_allow_control_characters) { config->allow_control_characters = RTEST(val); }
|
|
1476
|
+
else if (key == sym_allow_invalid_escape) { config->allow_invalid_escape = RTEST(val); }
|
|
1436
1477
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
|
1437
1478
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
|
1438
1479
|
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
|
@@ -1536,11 +1577,13 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1536
1577
|
const char *start;
|
|
1537
1578
|
RSTRING_GETMEM(Vsource, start, len);
|
|
1538
1579
|
|
|
1580
|
+
VALUE stack_handle = 0;
|
|
1539
1581
|
JSON_ParserState _state = {
|
|
1540
1582
|
.start = start,
|
|
1541
1583
|
.cursor = start,
|
|
1542
1584
|
.end = start + len,
|
|
1543
1585
|
.stack = &stack,
|
|
1586
|
+
.stack_handle = &stack_handle,
|
|
1544
1587
|
};
|
|
1545
1588
|
JSON_ParserState *state = &_state;
|
|
1546
1589
|
|
|
@@ -1548,8 +1591,8 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
|
1548
1591
|
|
|
1549
1592
|
// This may be skipped in case of exception, but
|
|
1550
1593
|
// it won't cause a leak.
|
|
1551
|
-
rvalue_stack_eagerly_release(
|
|
1552
|
-
|
|
1594
|
+
rvalue_stack_eagerly_release(stack_handle);
|
|
1595
|
+
RB_GC_GUARD(stack_handle);
|
|
1553
1596
|
json_ensure_eof(state);
|
|
1554
1597
|
|
|
1555
1598
|
return result;
|
|
@@ -1587,26 +1630,19 @@ static void JSON_ParserConfig_mark(void *ptr)
|
|
|
1587
1630
|
rb_gc_mark(config->decimal_class);
|
|
1588
1631
|
}
|
|
1589
1632
|
|
|
1590
|
-
static void JSON_ParserConfig_free(void *ptr)
|
|
1591
|
-
{
|
|
1592
|
-
JSON_ParserConfig *config = ptr;
|
|
1593
|
-
ruby_xfree(config);
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
1633
|
static size_t JSON_ParserConfig_memsize(const void *ptr)
|
|
1597
1634
|
{
|
|
1598
1635
|
return sizeof(JSON_ParserConfig);
|
|
1599
1636
|
}
|
|
1600
1637
|
|
|
1601
1638
|
static const rb_data_type_t JSON_ParserConfig_type = {
|
|
1602
|
-
"JSON::Ext::Parser/ParserConfig",
|
|
1603
|
-
{
|
|
1639
|
+
.wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
|
|
1640
|
+
.function = {
|
|
1604
1641
|
JSON_ParserConfig_mark,
|
|
1605
|
-
|
|
1642
|
+
RUBY_DEFAULT_FREE,
|
|
1606
1643
|
JSON_ParserConfig_memsize,
|
|
1607
1644
|
},
|
|
1608
|
-
|
|
1609
|
-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
|
|
1645
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
|
|
1610
1646
|
};
|
|
1611
1647
|
|
|
1612
1648
|
static VALUE cJSON_parser_s_allocate(VALUE klass)
|
|
@@ -1651,6 +1687,7 @@ void Init_parser(void)
|
|
|
1651
1687
|
sym_allow_nan = ID2SYM(rb_intern("allow_nan"));
|
|
1652
1688
|
sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
|
|
1653
1689
|
sym_allow_control_characters = ID2SYM(rb_intern("allow_control_characters"));
|
|
1690
|
+
sym_allow_invalid_escape = ID2SYM(rb_intern("allow_invalid_escape"));
|
|
1654
1691
|
sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
|
|
1655
1692
|
sym_freeze = ID2SYM(rb_intern("freeze"));
|
|
1656
1693
|
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.4
|
|
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: []
|