json 2.12.0 → 2.13.2
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 +23 -0
- data/README.md +13 -0
- data/ext/json/ext/fbuffer/fbuffer.h +38 -4
- data/ext/json/ext/generator/extconf.rb +2 -25
- data/ext/json/ext/generator/generator.c +80 -107
- data/ext/json/ext/parser/extconf.rb +5 -1
- data/ext/json/ext/parser/parser.c +214 -66
- data/ext/json/ext/simd/conf.rb +24 -0
- data/ext/json/ext/simd/simd.h +188 -0
- data/ext/json/ext/vendor/fpconv.c +5 -5
- data/json.gemspec +2 -3
- data/lib/json/common.rb +23 -22
- data/lib/json/ext.rb +2 -2
- data/lib/json/version.rb +1 -1
- data/lib/json.rb +33 -0
- metadata +4 -3
- data/ext/json/ext/generator/simd.h +0 -112
@@ -20,6 +20,8 @@ typedef unsigned char _Bool;
|
|
20
20
|
#endif
|
21
21
|
#endif
|
22
22
|
|
23
|
+
#include "../simd/simd.h"
|
24
|
+
|
23
25
|
#ifndef RB_UNLIKELY
|
24
26
|
#define RB_UNLIKELY(expr) expr
|
25
27
|
#endif
|
@@ -35,7 +37,7 @@ static ID i_chr, i_aset, i_aref,
|
|
35
37
|
i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
|
36
38
|
|
37
39
|
static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
|
38
|
-
sym_decimal_class, sym_on_load;
|
40
|
+
sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
|
39
41
|
|
40
42
|
static int binary_encindex;
|
41
43
|
static int utf8_encindex;
|
@@ -363,10 +365,17 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
|
363
365
|
return len;
|
364
366
|
}
|
365
367
|
|
368
|
+
enum duplicate_key_action {
|
369
|
+
JSON_DEPRECATED = 0,
|
370
|
+
JSON_IGNORE,
|
371
|
+
JSON_RAISE,
|
372
|
+
};
|
373
|
+
|
366
374
|
typedef struct JSON_ParserStruct {
|
367
375
|
VALUE on_load_proc;
|
368
376
|
VALUE decimal_class;
|
369
377
|
ID decimal_method_id;
|
378
|
+
enum duplicate_key_action on_duplicate_key;
|
370
379
|
int max_nesting;
|
371
380
|
bool allow_nan;
|
372
381
|
bool allow_trailing_comma;
|
@@ -386,15 +395,8 @@ typedef struct JSON_ParserStateStruct {
|
|
386
395
|
int current_nesting;
|
387
396
|
} JSON_ParserState;
|
388
397
|
|
389
|
-
|
390
|
-
#define PARSE_ERROR_FRAGMENT_LEN 32
|
391
|
-
#ifdef RBIMPL_ATTR_NORETURN
|
392
|
-
RBIMPL_ATTR_NORETURN()
|
393
|
-
#endif
|
394
|
-
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
398
|
+
static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
|
395
399
|
{
|
396
|
-
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
|
397
|
-
|
398
400
|
const char *cursor = state->cursor;
|
399
401
|
long column = 0;
|
400
402
|
long line = 1;
|
@@ -411,23 +413,58 @@ static void raise_parse_error(const char *format, JSON_ParserState *state)
|
|
411
413
|
line++;
|
412
414
|
}
|
413
415
|
}
|
416
|
+
*line_out = line;
|
417
|
+
*column_out = column;
|
418
|
+
}
|
414
419
|
|
415
|
-
|
416
|
-
|
420
|
+
static void emit_parse_warning(const char *message, JSON_ParserState *state)
|
421
|
+
{
|
422
|
+
long line, column;
|
423
|
+
cursor_position(state, &line, &column);
|
417
424
|
|
418
|
-
|
419
|
-
|
425
|
+
VALUE warning = rb_sprintf("%s at line %ld column %ld", message, line, column);
|
426
|
+
rb_funcall(mJSON, rb_intern("deprecation_warning"), 1, warning);
|
427
|
+
}
|
420
428
|
|
421
|
-
|
422
|
-
len--;
|
423
|
-
}
|
429
|
+
#define PARSE_ERROR_FRAGMENT_LEN 32
|
424
430
|
|
425
|
-
|
426
|
-
|
431
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
432
|
+
RBIMPL_ATTR_NORETURN()
|
433
|
+
#endif
|
434
|
+
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
435
|
+
{
|
436
|
+
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
|
437
|
+
long line, column;
|
438
|
+
cursor_position(state, &line, &column);
|
439
|
+
|
440
|
+
const char *ptr = "EOF";
|
441
|
+
if (state->cursor && state->cursor < state->end) {
|
442
|
+
ptr = state->cursor;
|
443
|
+
size_t len = 0;
|
444
|
+
while (len < PARSE_ERROR_FRAGMENT_LEN) {
|
445
|
+
char ch = ptr[len];
|
446
|
+
if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
|
447
|
+
break;
|
448
|
+
}
|
449
|
+
len++;
|
427
450
|
}
|
428
451
|
|
429
|
-
|
430
|
-
|
452
|
+
if (len) {
|
453
|
+
buffer[0] = '\'';
|
454
|
+
MEMCPY(buffer + 1, ptr, char, len);
|
455
|
+
|
456
|
+
while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
|
457
|
+
len--;
|
458
|
+
}
|
459
|
+
|
460
|
+
if (buffer[len] >= 0xC0) { // multibyte character start
|
461
|
+
len--;
|
462
|
+
}
|
463
|
+
|
464
|
+
buffer[len + 1] = '\'';
|
465
|
+
buffer[len + 2] = '\0';
|
466
|
+
ptr = (const char *)buffer;
|
467
|
+
}
|
431
468
|
}
|
432
469
|
|
433
470
|
VALUE msg = rb_sprintf(format, ptr);
|
@@ -473,16 +510,16 @@ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p
|
|
473
510
|
signed char b;
|
474
511
|
uint32_t result = 0;
|
475
512
|
b = digit_values[p[0]];
|
476
|
-
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at
|
513
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
477
514
|
result = (result << 4) | (unsigned char)b;
|
478
515
|
b = digit_values[p[1]];
|
479
|
-
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at
|
516
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
480
517
|
result = (result << 4) | (unsigned char)b;
|
481
518
|
b = digit_values[p[2]];
|
482
|
-
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at
|
519
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
483
520
|
result = (result << 4) | (unsigned char)b;
|
484
521
|
b = digit_values[p[3]];
|
485
|
-
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at
|
522
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
|
486
523
|
result = (result << 4) | (unsigned char)b;
|
487
524
|
return result;
|
488
525
|
}
|
@@ -505,7 +542,7 @@ static void
|
|
505
542
|
json_eat_comments(JSON_ParserState *state)
|
506
543
|
{
|
507
544
|
if (state->cursor + 1 < state->end) {
|
508
|
-
switch(state->cursor[1]) {
|
545
|
+
switch (state->cursor[1]) {
|
509
546
|
case '/': {
|
510
547
|
state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
|
511
548
|
if (!state->cursor) {
|
@@ -532,11 +569,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
532
569
|
break;
|
533
570
|
}
|
534
571
|
default:
|
535
|
-
raise_parse_error("unexpected token
|
572
|
+
raise_parse_error("unexpected token %s", state);
|
536
573
|
break;
|
537
574
|
}
|
538
575
|
} else {
|
539
|
-
raise_parse_error("unexpected token
|
576
|
+
raise_parse_error("unexpected token %s", state);
|
540
577
|
}
|
541
578
|
}
|
542
579
|
|
@@ -655,7 +692,7 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
655
692
|
break;
|
656
693
|
case 'u':
|
657
694
|
if (pe > stringEnd - 5) {
|
658
|
-
raise_parse_error_at("incomplete unicode character escape sequence at
|
695
|
+
raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
|
659
696
|
} else {
|
660
697
|
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
661
698
|
pe += 3;
|
@@ -672,7 +709,7 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
672
709
|
if ((ch & 0xFC00) == 0xD800) {
|
673
710
|
pe++;
|
674
711
|
if (pe > stringEnd - 6) {
|
675
|
-
raise_parse_error_at("incomplete surrogate pair at
|
712
|
+
raise_parse_error_at("incomplete surrogate pair at %s", state, p);
|
676
713
|
}
|
677
714
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
678
715
|
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
@@ -795,10 +832,67 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
|
|
795
832
|
return array;
|
796
833
|
}
|
797
834
|
|
798
|
-
static
|
835
|
+
static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
|
836
|
+
{
|
837
|
+
VALUE set = rb_hash_new_capa(count / 2);
|
838
|
+
for (size_t index = 0; index < count; index += 2) {
|
839
|
+
size_t before = RHASH_SIZE(set);
|
840
|
+
VALUE key = pairs[index];
|
841
|
+
rb_hash_aset(set, key, Qtrue);
|
842
|
+
if (RHASH_SIZE(set) == before) {
|
843
|
+
if (RB_SYMBOL_P(key)) {
|
844
|
+
return rb_sym2str(key);
|
845
|
+
}
|
846
|
+
return key;
|
847
|
+
}
|
848
|
+
}
|
849
|
+
return Qfalse;
|
850
|
+
}
|
851
|
+
|
852
|
+
static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
|
853
|
+
{
|
854
|
+
VALUE message = rb_sprintf(
|
855
|
+
"detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
|
856
|
+
rb_inspect(duplicate_key)
|
857
|
+
);
|
858
|
+
|
859
|
+
emit_parse_warning(RSTRING_PTR(message), state);
|
860
|
+
RB_GC_GUARD(message);
|
861
|
+
}
|
862
|
+
|
863
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
864
|
+
RBIMPL_ATTR_NORETURN()
|
865
|
+
#endif
|
866
|
+
static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
|
867
|
+
{
|
868
|
+
VALUE message = rb_sprintf(
|
869
|
+
"duplicate key %"PRIsVALUE,
|
870
|
+
rb_inspect(duplicate_key)
|
871
|
+
);
|
872
|
+
|
873
|
+
raise_parse_error(RSTRING_PTR(message), state);
|
874
|
+
RB_GC_GUARD(message);
|
875
|
+
}
|
876
|
+
|
877
|
+
static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
|
799
878
|
{
|
800
|
-
|
801
|
-
|
879
|
+
size_t entries_count = count / 2;
|
880
|
+
VALUE object = rb_hash_new_capa(entries_count);
|
881
|
+
const VALUE *pairs = rvalue_stack_peek(state->stack, count);
|
882
|
+
rb_hash_bulk_insert(count, pairs, object);
|
883
|
+
|
884
|
+
if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
|
885
|
+
switch (config->on_duplicate_key) {
|
886
|
+
case JSON_IGNORE:
|
887
|
+
break;
|
888
|
+
case JSON_DEPRECATED:
|
889
|
+
emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
|
890
|
+
break;
|
891
|
+
case JSON_RAISE:
|
892
|
+
raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
|
893
|
+
break;
|
894
|
+
}
|
895
|
+
}
|
802
896
|
|
803
897
|
rvalue_stack_pop(state->stack, count);
|
804
898
|
|
@@ -832,7 +926,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
|
|
832
926
|
return value;
|
833
927
|
}
|
834
928
|
|
835
|
-
static const bool
|
929
|
+
static const bool string_scan_table[256] = {
|
836
930
|
// ASCII Control Characters
|
837
931
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
838
932
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
@@ -845,32 +939,71 @@ static const bool string_scan[256] = {
|
|
845
939
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
846
940
|
};
|
847
941
|
|
942
|
+
#if (defined(__GNUC__ ) || defined(__clang__))
|
943
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
944
|
+
#else
|
945
|
+
#define FORCE_INLINE
|
946
|
+
#endif
|
947
|
+
|
948
|
+
#ifdef HAVE_SIMD
|
949
|
+
static SIMD_Implementation simd_impl = SIMD_NONE;
|
950
|
+
#endif /* HAVE_SIMD */
|
951
|
+
|
952
|
+
static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
|
953
|
+
{
|
954
|
+
#ifdef HAVE_SIMD
|
955
|
+
#if defined(HAVE_SIMD_NEON)
|
956
|
+
|
957
|
+
uint64_t mask = 0;
|
958
|
+
if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
|
959
|
+
state->cursor += trailing_zeros64(mask) >> 2;
|
960
|
+
return 1;
|
961
|
+
}
|
962
|
+
|
963
|
+
#elif defined(HAVE_SIMD_SSE2)
|
964
|
+
if (simd_impl == SIMD_SSE2) {
|
965
|
+
int mask = 0;
|
966
|
+
if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
|
967
|
+
state->cursor += trailing_zeros(mask);
|
968
|
+
return 1;
|
969
|
+
}
|
970
|
+
}
|
971
|
+
#endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
|
972
|
+
#endif /* HAVE_SIMD */
|
973
|
+
|
974
|
+
while (state->cursor < state->end) {
|
975
|
+
if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
|
976
|
+
return 1;
|
977
|
+
}
|
978
|
+
*state->cursor++;
|
979
|
+
}
|
980
|
+
return 0;
|
981
|
+
}
|
982
|
+
|
848
983
|
static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
|
849
984
|
{
|
850
985
|
state->cursor++;
|
851
986
|
const char *start = state->cursor;
|
852
987
|
bool escaped = false;
|
853
988
|
|
854
|
-
while (state
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
if ((unsigned char)*state->cursor < 0x20) {
|
866
|
-
raise_parse_error("invalid ASCII control character in string: %s", state);
|
867
|
-
}
|
868
|
-
break;
|
869
|
-
}
|
870
|
-
default:
|
989
|
+
while (RB_UNLIKELY(string_scan(state))) {
|
990
|
+
switch (*state->cursor) {
|
991
|
+
case '"': {
|
992
|
+
VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
|
993
|
+
state->cursor++;
|
994
|
+
return json_push_value(state, config, string);
|
995
|
+
}
|
996
|
+
case '\\': {
|
997
|
+
state->cursor++;
|
998
|
+
escaped = true;
|
999
|
+
if ((unsigned char)*state->cursor < 0x20) {
|
871
1000
|
raise_parse_error("invalid ASCII control character in string: %s", state);
|
872
|
-
|
1001
|
+
}
|
1002
|
+
break;
|
873
1003
|
}
|
1004
|
+
default:
|
1005
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
1006
|
+
break;
|
874
1007
|
}
|
875
1008
|
|
876
1009
|
state->cursor++;
|
@@ -894,7 +1027,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
894
1027
|
return json_push_value(state, config, Qnil);
|
895
1028
|
}
|
896
1029
|
|
897
|
-
raise_parse_error("unexpected token
|
1030
|
+
raise_parse_error("unexpected token %s", state);
|
898
1031
|
break;
|
899
1032
|
case 't':
|
900
1033
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
@@ -902,7 +1035,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
902
1035
|
return json_push_value(state, config, Qtrue);
|
903
1036
|
}
|
904
1037
|
|
905
|
-
raise_parse_error("unexpected token
|
1038
|
+
raise_parse_error("unexpected token %s", state);
|
906
1039
|
break;
|
907
1040
|
case 'f':
|
908
1041
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -911,7 +1044,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
911
1044
|
return json_push_value(state, config, Qfalse);
|
912
1045
|
}
|
913
1046
|
|
914
|
-
raise_parse_error("unexpected token
|
1047
|
+
raise_parse_error("unexpected token %s", state);
|
915
1048
|
break;
|
916
1049
|
case 'N':
|
917
1050
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -920,7 +1053,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
920
1053
|
return json_push_value(state, config, CNaN);
|
921
1054
|
}
|
922
1055
|
|
923
|
-
raise_parse_error("unexpected token
|
1056
|
+
raise_parse_error("unexpected token %s", state);
|
924
1057
|
break;
|
925
1058
|
case 'I':
|
926
1059
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
@@ -928,7 +1061,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
928
1061
|
return json_push_value(state, config, CInfinity);
|
929
1062
|
}
|
930
1063
|
|
931
|
-
raise_parse_error("unexpected token
|
1064
|
+
raise_parse_error("unexpected token %s", state);
|
932
1065
|
break;
|
933
1066
|
case '-':
|
934
1067
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -937,7 +1070,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
937
1070
|
state->cursor += 9;
|
938
1071
|
return json_push_value(state, config, CMinusInfinity);
|
939
1072
|
} else {
|
940
|
-
raise_parse_error("unexpected token
|
1073
|
+
raise_parse_error("unexpected token %s", state);
|
941
1074
|
}
|
942
1075
|
}
|
943
1076
|
// Fallthrough
|
@@ -1048,6 +1181,8 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1048
1181
|
break;
|
1049
1182
|
}
|
1050
1183
|
case '{': {
|
1184
|
+
const char *object_start_cursor = state->cursor;
|
1185
|
+
|
1051
1186
|
state->cursor++;
|
1052
1187
|
json_eat_whitespace(state);
|
1053
1188
|
long stack_head = state->stack->head;
|
@@ -1062,7 +1197,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1062
1197
|
}
|
1063
1198
|
|
1064
1199
|
if (*state->cursor != '"') {
|
1065
|
-
raise_parse_error("expected object key, got
|
1200
|
+
raise_parse_error("expected object key, got %s", state);
|
1066
1201
|
}
|
1067
1202
|
json_parse_string(state, config, true);
|
1068
1203
|
|
@@ -1082,8 +1217,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1082
1217
|
if (*state->cursor == '}') {
|
1083
1218
|
state->cursor++;
|
1084
1219
|
state->current_nesting--;
|
1085
|
-
|
1086
|
-
|
1220
|
+
size_t count = state->stack->head - stack_head;
|
1221
|
+
|
1222
|
+
// Temporary rewind cursor in case an error is raised
|
1223
|
+
const char *final_cursor = state->cursor;
|
1224
|
+
state->cursor = object_start_cursor;
|
1225
|
+
VALUE object = json_decode_object(state, config, count);
|
1226
|
+
state->cursor = final_cursor;
|
1227
|
+
|
1228
|
+
return json_push_value(state, config, object);
|
1087
1229
|
}
|
1088
1230
|
|
1089
1231
|
if (*state->cursor == ',') {
|
@@ -1097,13 +1239,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1097
1239
|
}
|
1098
1240
|
|
1099
1241
|
if (*state->cursor != '"') {
|
1100
|
-
raise_parse_error("expected object key, got:
|
1242
|
+
raise_parse_error("expected object key, got: %s", state);
|
1101
1243
|
}
|
1102
1244
|
json_parse_string(state, config, true);
|
1103
1245
|
|
1104
1246
|
json_eat_whitespace(state);
|
1105
1247
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1106
|
-
raise_parse_error("expected ':' after object key, got:
|
1248
|
+
raise_parse_error("expected ':' after object key, got: %s", state);
|
1107
1249
|
}
|
1108
1250
|
state->cursor++;
|
1109
1251
|
|
@@ -1113,24 +1255,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1113
1255
|
}
|
1114
1256
|
}
|
1115
1257
|
|
1116
|
-
raise_parse_error("expected ',' or '}' after object value, got:
|
1258
|
+
raise_parse_error("expected ',' or '}' after object value, got: %s", state);
|
1117
1259
|
}
|
1118
1260
|
break;
|
1119
1261
|
}
|
1120
1262
|
|
1121
1263
|
default:
|
1122
|
-
raise_parse_error("unexpected character:
|
1264
|
+
raise_parse_error("unexpected character: %s", state);
|
1123
1265
|
break;
|
1124
1266
|
}
|
1125
1267
|
|
1126
|
-
raise_parse_error("unreacheable:
|
1268
|
+
raise_parse_error("unreacheable: %s", state);
|
1127
1269
|
}
|
1128
1270
|
|
1129
1271
|
static void json_ensure_eof(JSON_ParserState *state)
|
1130
1272
|
{
|
1131
1273
|
json_eat_whitespace(state);
|
1132
1274
|
if (state->cursor != state->end) {
|
1133
|
-
raise_parse_error("unexpected token at end of stream
|
1275
|
+
raise_parse_error("unexpected token at end of stream %s", state);
|
1134
1276
|
}
|
1135
1277
|
}
|
1136
1278
|
|
@@ -1172,6 +1314,7 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
|
|
1172
1314
|
else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
|
1173
1315
|
else if (key == sym_freeze) { config->freeze = RTEST(val); }
|
1174
1316
|
else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
|
1317
|
+
else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
|
1175
1318
|
else if (key == sym_decimal_class) {
|
1176
1319
|
if (RTEST(val)) {
|
1177
1320
|
if (rb_respond_to(val, i_try_convert)) {
|
@@ -1388,6 +1531,7 @@ void Init_parser(void)
|
|
1388
1531
|
sym_freeze = ID2SYM(rb_intern("freeze"));
|
1389
1532
|
sym_on_load = ID2SYM(rb_intern("on_load"));
|
1390
1533
|
sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
|
1534
|
+
sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
|
1391
1535
|
|
1392
1536
|
i_chr = rb_intern("chr");
|
1393
1537
|
i_aset = rb_intern("[]=");
|
@@ -1401,4 +1545,8 @@ void Init_parser(void)
|
|
1401
1545
|
binary_encindex = rb_ascii8bit_encindex();
|
1402
1546
|
utf8_encindex = rb_utf8_encindex();
|
1403
1547
|
enc_utf8 = rb_utf8_encoding();
|
1548
|
+
|
1549
|
+
#ifdef HAVE_SIMD
|
1550
|
+
simd_impl = find_simd_implementation();
|
1551
|
+
#endif
|
1404
1552
|
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
case RbConfig::CONFIG['host_cpu']
|
2
|
+
when /^(arm|aarch64)/
|
3
|
+
# Try to compile a small program using NEON instructions
|
4
|
+
header, type, init, extra = 'arm_neon.h', 'uint8x16_t', 'vdupq_n_u8(32)', nil
|
5
|
+
when /^(x86_64|x64)/
|
6
|
+
header, type, init, extra = 'x86intrin.h', '__m128i', '_mm_set1_epi8(32)', 'if (__builtin_cpu_supports("sse2")) { printf("OK"); }'
|
7
|
+
end
|
8
|
+
if header
|
9
|
+
if have_header(header) && try_compile(<<~SRC, '-Werror=implicit-function-declaration')
|
10
|
+
#{cpp_include(header)}
|
11
|
+
int main(int argc, char **argv) {
|
12
|
+
#{type} test = #{init};
|
13
|
+
#{extra}
|
14
|
+
if (argc > 100000) printf("%p", &test);
|
15
|
+
return 0;
|
16
|
+
}
|
17
|
+
SRC
|
18
|
+
$defs.push("-DJSON_ENABLE_SIMD")
|
19
|
+
else
|
20
|
+
puts "Disable SIMD"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
have_header('cpuid.h')
|