json 2.11.2 → 2.12.0
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 +13 -0
- data/ext/json/ext/generator/extconf.rb +29 -0
- data/ext/json/ext/generator/generator.c +446 -97
- data/ext/json/ext/generator/simd.h +112 -0
- data/ext/json/ext/parser/parser.c +131 -92
- data/ext/json/ext/vendor/fpconv.c +5 -5
- data/lib/json/common.rb +3 -1
- data/lib/json/version.rb +1 -1
- metadata +3 -2
@@ -0,0 +1,112 @@
|
|
1
|
+
typedef enum {
|
2
|
+
SIMD_NONE,
|
3
|
+
SIMD_NEON,
|
4
|
+
SIMD_SSE2
|
5
|
+
} SIMD_Implementation;
|
6
|
+
|
7
|
+
#ifdef JSON_ENABLE_SIMD
|
8
|
+
|
9
|
+
#ifdef __clang__
|
10
|
+
#if __has_builtin(__builtin_ctzll)
|
11
|
+
#define HAVE_BUILTIN_CTZLL 1
|
12
|
+
#else
|
13
|
+
#define HAVE_BUILTIN_CTZLL 0
|
14
|
+
#endif
|
15
|
+
#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
|
16
|
+
#define HAVE_BUILTIN_CTZLL 1
|
17
|
+
#else
|
18
|
+
#define HAVE_BUILTIN_CTZLL 0
|
19
|
+
#endif
|
20
|
+
|
21
|
+
static inline uint32_t trailing_zeros64(uint64_t input) {
|
22
|
+
#if HAVE_BUILTIN_CTZLL
|
23
|
+
return __builtin_ctzll(input);
|
24
|
+
#else
|
25
|
+
uint32_t trailing_zeros = 0;
|
26
|
+
uint64_t temp = input;
|
27
|
+
while ((temp & 1) == 0 && temp > 0) {
|
28
|
+
trailing_zeros++;
|
29
|
+
temp >>= 1;
|
30
|
+
}
|
31
|
+
return trailing_zeros;
|
32
|
+
#endif
|
33
|
+
}
|
34
|
+
|
35
|
+
static inline int trailing_zeros(int input) {
|
36
|
+
#if HAVE_BUILTIN_CTZLL
|
37
|
+
return __builtin_ctz(input);
|
38
|
+
#else
|
39
|
+
int trailing_zeros = 0;
|
40
|
+
int temp = input;
|
41
|
+
while ((temp & 1) == 0 && temp > 0) {
|
42
|
+
trailing_zeros++;
|
43
|
+
temp >>= 1;
|
44
|
+
}
|
45
|
+
return trailing_zeros;
|
46
|
+
#endif
|
47
|
+
}
|
48
|
+
|
49
|
+
#define SIMD_MINIMUM_THRESHOLD 6
|
50
|
+
|
51
|
+
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__) || defined(_M_ARM64)
|
52
|
+
#include <arm_neon.h>
|
53
|
+
|
54
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
55
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
56
|
+
return SIMD_NEON;
|
57
|
+
}
|
58
|
+
|
59
|
+
#define HAVE_SIMD 1
|
60
|
+
#define HAVE_SIMD_NEON 1
|
61
|
+
|
62
|
+
uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
|
63
|
+
uint8x16x4_t tab;
|
64
|
+
tab.val[0] = vld1q_u8(table);
|
65
|
+
tab.val[1] = vld1q_u8(table+16);
|
66
|
+
tab.val[2] = vld1q_u8(table+32);
|
67
|
+
tab.val[3] = vld1q_u8(table+48);
|
68
|
+
return tab;
|
69
|
+
}
|
70
|
+
|
71
|
+
#endif /* ARM Neon Support.*/
|
72
|
+
|
73
|
+
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
74
|
+
|
75
|
+
#ifdef HAVE_X86INTRIN_H
|
76
|
+
#include <x86intrin.h>
|
77
|
+
|
78
|
+
#define HAVE_SIMD 1
|
79
|
+
#define HAVE_SIMD_SSE2 1
|
80
|
+
|
81
|
+
#ifdef HAVE_CPUID_H
|
82
|
+
#define FIND_SIMD_IMPLEMENTATION_DEFINED 1
|
83
|
+
|
84
|
+
#include <cpuid.h>
|
85
|
+
#endif /* HAVE_CPUID_H */
|
86
|
+
|
87
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
88
|
+
|
89
|
+
#if defined(__GNUC__ ) || defined(__clang__)
|
90
|
+
#ifdef __GNUC__
|
91
|
+
__builtin_cpu_init();
|
92
|
+
#endif /* __GNUC__ */
|
93
|
+
|
94
|
+
// TODO Revisit. I think the SSE version now only uses SSE2 instructions.
|
95
|
+
if (__builtin_cpu_supports("sse2")) {
|
96
|
+
return SIMD_SSE2;
|
97
|
+
}
|
98
|
+
#endif /* __GNUC__ || __clang__*/
|
99
|
+
|
100
|
+
return SIMD_NONE;
|
101
|
+
}
|
102
|
+
|
103
|
+
#endif /* HAVE_X86INTRIN_H */
|
104
|
+
#endif /* X86_64 Support */
|
105
|
+
|
106
|
+
#endif /* JSON_ENABLE_SIMD */
|
107
|
+
|
108
|
+
#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
|
109
|
+
static SIMD_Implementation find_simd_implementation(void) {
|
110
|
+
return SIMD_NONE;
|
111
|
+
}
|
112
|
+
#endif
|
@@ -337,19 +337,86 @@ static size_t strnlen(const char *s, size_t maxlen)
|
|
337
337
|
}
|
338
338
|
#endif
|
339
339
|
|
340
|
+
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
341
|
+
{
|
342
|
+
int len = 1;
|
343
|
+
if (ch <= 0x7F) {
|
344
|
+
buf[0] = (char) ch;
|
345
|
+
} else if (ch <= 0x07FF) {
|
346
|
+
buf[0] = (char) ((ch >> 6) | 0xC0);
|
347
|
+
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
348
|
+
len++;
|
349
|
+
} else if (ch <= 0xFFFF) {
|
350
|
+
buf[0] = (char) ((ch >> 12) | 0xE0);
|
351
|
+
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
352
|
+
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
353
|
+
len += 2;
|
354
|
+
} else if (ch <= 0x1fffff) {
|
355
|
+
buf[0] =(char) ((ch >> 18) | 0xF0);
|
356
|
+
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
357
|
+
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
358
|
+
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
359
|
+
len += 3;
|
360
|
+
} else {
|
361
|
+
buf[0] = '?';
|
362
|
+
}
|
363
|
+
return len;
|
364
|
+
}
|
365
|
+
|
366
|
+
typedef struct JSON_ParserStruct {
|
367
|
+
VALUE on_load_proc;
|
368
|
+
VALUE decimal_class;
|
369
|
+
ID decimal_method_id;
|
370
|
+
int max_nesting;
|
371
|
+
bool allow_nan;
|
372
|
+
bool allow_trailing_comma;
|
373
|
+
bool parsing_name;
|
374
|
+
bool symbolize_names;
|
375
|
+
bool freeze;
|
376
|
+
} JSON_ParserConfig;
|
377
|
+
|
378
|
+
typedef struct JSON_ParserStateStruct {
|
379
|
+
VALUE stack_handle;
|
380
|
+
const char *start;
|
381
|
+
const char *cursor;
|
382
|
+
const char *end;
|
383
|
+
rvalue_stack *stack;
|
384
|
+
rvalue_cache name_cache;
|
385
|
+
int in_array;
|
386
|
+
int current_nesting;
|
387
|
+
} JSON_ParserState;
|
388
|
+
|
389
|
+
|
340
390
|
#define PARSE_ERROR_FRAGMENT_LEN 32
|
341
391
|
#ifdef RBIMPL_ATTR_NORETURN
|
342
392
|
RBIMPL_ATTR_NORETURN()
|
343
393
|
#endif
|
344
|
-
static void raise_parse_error(const char *format,
|
394
|
+
static void raise_parse_error(const char *format, JSON_ParserState *state)
|
345
395
|
{
|
346
396
|
unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
|
347
397
|
|
348
|
-
|
349
|
-
|
398
|
+
const char *cursor = state->cursor;
|
399
|
+
long column = 0;
|
400
|
+
long line = 1;
|
401
|
+
|
402
|
+
while (cursor >= state->start) {
|
403
|
+
if (*cursor-- == '\n') {
|
404
|
+
break;
|
405
|
+
}
|
406
|
+
column++;
|
407
|
+
}
|
408
|
+
|
409
|
+
while (cursor >= state->start) {
|
410
|
+
if (*cursor-- == '\n') {
|
411
|
+
line++;
|
412
|
+
}
|
413
|
+
}
|
414
|
+
|
415
|
+
const char *ptr = state->cursor;
|
416
|
+
size_t len = ptr ? strnlen(ptr, PARSE_ERROR_FRAGMENT_LEN) : 0;
|
350
417
|
|
351
418
|
if (len == PARSE_ERROR_FRAGMENT_LEN) {
|
352
|
-
MEMCPY(buffer,
|
419
|
+
MEMCPY(buffer, ptr, char, PARSE_ERROR_FRAGMENT_LEN);
|
353
420
|
|
354
421
|
while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
|
355
422
|
len--;
|
@@ -363,7 +430,23 @@ static void raise_parse_error(const char *format, const char *start)
|
|
363
430
|
ptr = (const char *)buffer;
|
364
431
|
}
|
365
432
|
|
366
|
-
|
433
|
+
VALUE msg = rb_sprintf(format, ptr);
|
434
|
+
VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
|
435
|
+
RB_GC_GUARD(msg);
|
436
|
+
|
437
|
+
VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
|
438
|
+
rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
|
439
|
+
rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
|
440
|
+
rb_exc_raise(exc);
|
441
|
+
}
|
442
|
+
|
443
|
+
#ifdef RBIMPL_ATTR_NORETURN
|
444
|
+
RBIMPL_ATTR_NORETURN()
|
445
|
+
#endif
|
446
|
+
static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
|
447
|
+
{
|
448
|
+
state->cursor = at;
|
449
|
+
raise_parse_error(format, state);
|
367
450
|
}
|
368
451
|
|
369
452
|
/* unicode */
|
@@ -385,73 +468,25 @@ static const signed char digit_values[256] = {
|
|
385
468
|
-1, -1, -1, -1, -1, -1, -1
|
386
469
|
};
|
387
470
|
|
388
|
-
static uint32_t unescape_unicode(const unsigned char *p)
|
471
|
+
static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
|
389
472
|
{
|
390
473
|
signed char b;
|
391
474
|
uint32_t result = 0;
|
392
475
|
b = digit_values[p[0]];
|
393
|
-
if (b < 0)
|
476
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
394
477
|
result = (result << 4) | (unsigned char)b;
|
395
478
|
b = digit_values[p[1]];
|
396
|
-
if (b < 0)
|
479
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
397
480
|
result = (result << 4) | (unsigned char)b;
|
398
481
|
b = digit_values[p[2]];
|
399
|
-
if (b < 0)
|
482
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
400
483
|
result = (result << 4) | (unsigned char)b;
|
401
484
|
b = digit_values[p[3]];
|
402
|
-
if (b < 0)
|
485
|
+
if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, (char *)p - 2);
|
403
486
|
result = (result << 4) | (unsigned char)b;
|
404
487
|
return result;
|
405
488
|
}
|
406
489
|
|
407
|
-
static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
|
408
|
-
{
|
409
|
-
int len = 1;
|
410
|
-
if (ch <= 0x7F) {
|
411
|
-
buf[0] = (char) ch;
|
412
|
-
} else if (ch <= 0x07FF) {
|
413
|
-
buf[0] = (char) ((ch >> 6) | 0xC0);
|
414
|
-
buf[1] = (char) ((ch & 0x3F) | 0x80);
|
415
|
-
len++;
|
416
|
-
} else if (ch <= 0xFFFF) {
|
417
|
-
buf[0] = (char) ((ch >> 12) | 0xE0);
|
418
|
-
buf[1] = (char) (((ch >> 6) & 0x3F) | 0x80);
|
419
|
-
buf[2] = (char) ((ch & 0x3F) | 0x80);
|
420
|
-
len += 2;
|
421
|
-
} else if (ch <= 0x1fffff) {
|
422
|
-
buf[0] =(char) ((ch >> 18) | 0xF0);
|
423
|
-
buf[1] =(char) (((ch >> 12) & 0x3F) | 0x80);
|
424
|
-
buf[2] =(char) (((ch >> 6) & 0x3F) | 0x80);
|
425
|
-
buf[3] =(char) ((ch & 0x3F) | 0x80);
|
426
|
-
len += 3;
|
427
|
-
} else {
|
428
|
-
buf[0] = '?';
|
429
|
-
}
|
430
|
-
return len;
|
431
|
-
}
|
432
|
-
|
433
|
-
typedef struct JSON_ParserStruct {
|
434
|
-
VALUE on_load_proc;
|
435
|
-
VALUE decimal_class;
|
436
|
-
ID decimal_method_id;
|
437
|
-
int max_nesting;
|
438
|
-
bool allow_nan;
|
439
|
-
bool allow_trailing_comma;
|
440
|
-
bool parsing_name;
|
441
|
-
bool symbolize_names;
|
442
|
-
bool freeze;
|
443
|
-
} JSON_ParserConfig;
|
444
|
-
|
445
|
-
typedef struct JSON_ParserStateStruct {
|
446
|
-
VALUE stack_handle;
|
447
|
-
const char *cursor;
|
448
|
-
const char *end;
|
449
|
-
rvalue_stack *stack;
|
450
|
-
rvalue_cache name_cache;
|
451
|
-
int in_array;
|
452
|
-
int current_nesting;
|
453
|
-
} JSON_ParserState;
|
454
|
-
|
455
490
|
#define GET_PARSER_CONFIG \
|
456
491
|
JSON_ParserConfig *config; \
|
457
492
|
TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
|
@@ -485,8 +520,7 @@ json_eat_comments(JSON_ParserState *state)
|
|
485
520
|
while (true) {
|
486
521
|
state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
|
487
522
|
if (!state->cursor) {
|
488
|
-
|
489
|
-
raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
|
523
|
+
raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
|
490
524
|
} else {
|
491
525
|
state->cursor++;
|
492
526
|
if (state->cursor < state->end && *state->cursor == '/') {
|
@@ -498,11 +532,11 @@ json_eat_comments(JSON_ParserState *state)
|
|
498
532
|
break;
|
499
533
|
}
|
500
534
|
default:
|
501
|
-
raise_parse_error("unexpected token
|
535
|
+
raise_parse_error("unexpected token '%s'", state);
|
502
536
|
break;
|
503
537
|
}
|
504
538
|
} else {
|
505
|
-
raise_parse_error("unexpected token
|
539
|
+
raise_parse_error("unexpected token '%s'", state);
|
506
540
|
}
|
507
541
|
}
|
508
542
|
|
@@ -621,9 +655,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
621
655
|
break;
|
622
656
|
case 'u':
|
623
657
|
if (pe > stringEnd - 5) {
|
624
|
-
|
658
|
+
raise_parse_error_at("incomplete unicode character escape sequence at '%s'", state, p);
|
625
659
|
} else {
|
626
|
-
uint32_t ch = unescape_unicode((unsigned char *) ++pe);
|
660
|
+
uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
|
627
661
|
pe += 3;
|
628
662
|
/* To handle values above U+FFFF, we take a sequence of
|
629
663
|
* \uXXXX escapes in the U+D800..U+DBFF then
|
@@ -638,10 +672,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
|
|
638
672
|
if ((ch & 0xFC00) == 0xD800) {
|
639
673
|
pe++;
|
640
674
|
if (pe > stringEnd - 6) {
|
641
|
-
|
675
|
+
raise_parse_error_at("incomplete surrogate pair at '%s'", state, p);
|
642
676
|
}
|
643
677
|
if (pe[0] == '\\' && pe[1] == 'u') {
|
644
|
-
uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
|
678
|
+
uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
|
645
679
|
ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
|
646
680
|
| (sur & 0x3FF));
|
647
681
|
pe += 5;
|
@@ -829,12 +863,12 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
829
863
|
state->cursor++;
|
830
864
|
escaped = true;
|
831
865
|
if ((unsigned char)*state->cursor < 0x20) {
|
832
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
866
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
833
867
|
}
|
834
868
|
break;
|
835
869
|
}
|
836
870
|
default:
|
837
|
-
raise_parse_error("invalid ASCII control character in string: %s", state
|
871
|
+
raise_parse_error("invalid ASCII control character in string: %s", state);
|
838
872
|
break;
|
839
873
|
}
|
840
874
|
}
|
@@ -842,7 +876,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
|
|
842
876
|
state->cursor++;
|
843
877
|
}
|
844
878
|
|
845
|
-
raise_parse_error("unexpected end of input, expected closing \"", state
|
879
|
+
raise_parse_error("unexpected end of input, expected closing \"", state);
|
846
880
|
return Qfalse;
|
847
881
|
}
|
848
882
|
|
@@ -850,7 +884,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
850
884
|
{
|
851
885
|
json_eat_whitespace(state);
|
852
886
|
if (state->cursor >= state->end) {
|
853
|
-
raise_parse_error("unexpected end of input", state
|
887
|
+
raise_parse_error("unexpected end of input", state);
|
854
888
|
}
|
855
889
|
|
856
890
|
switch (*state->cursor) {
|
@@ -860,7 +894,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
860
894
|
return json_push_value(state, config, Qnil);
|
861
895
|
}
|
862
896
|
|
863
|
-
raise_parse_error("unexpected token
|
897
|
+
raise_parse_error("unexpected token '%s'", state);
|
864
898
|
break;
|
865
899
|
case 't':
|
866
900
|
if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
|
@@ -868,7 +902,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
868
902
|
return json_push_value(state, config, Qtrue);
|
869
903
|
}
|
870
904
|
|
871
|
-
raise_parse_error("unexpected token
|
905
|
+
raise_parse_error("unexpected token '%s'", state);
|
872
906
|
break;
|
873
907
|
case 'f':
|
874
908
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -877,7 +911,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
877
911
|
return json_push_value(state, config, Qfalse);
|
878
912
|
}
|
879
913
|
|
880
|
-
raise_parse_error("unexpected token
|
914
|
+
raise_parse_error("unexpected token '%s'", state);
|
881
915
|
break;
|
882
916
|
case 'N':
|
883
917
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -886,7 +920,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
886
920
|
return json_push_value(state, config, CNaN);
|
887
921
|
}
|
888
922
|
|
889
|
-
raise_parse_error("unexpected token
|
923
|
+
raise_parse_error("unexpected token '%s'", state);
|
890
924
|
break;
|
891
925
|
case 'I':
|
892
926
|
if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
|
@@ -894,7 +928,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
894
928
|
return json_push_value(state, config, CInfinity);
|
895
929
|
}
|
896
930
|
|
897
|
-
raise_parse_error("unexpected token
|
931
|
+
raise_parse_error("unexpected token '%s'", state);
|
898
932
|
break;
|
899
933
|
case '-':
|
900
934
|
// Note: memcmp with a small power of two compile to an integer comparison
|
@@ -903,7 +937,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
903
937
|
state->cursor += 9;
|
904
938
|
return json_push_value(state, config, CMinusInfinity);
|
905
939
|
} else {
|
906
|
-
raise_parse_error("unexpected token
|
940
|
+
raise_parse_error("unexpected token '%s'", state);
|
907
941
|
}
|
908
942
|
}
|
909
943
|
// Fallthrough
|
@@ -921,11 +955,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
921
955
|
long integer_length = state->cursor - start;
|
922
956
|
|
923
957
|
if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
|
924
|
-
|
958
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
925
959
|
} else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
|
926
|
-
|
960
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
927
961
|
} else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
|
928
|
-
|
962
|
+
raise_parse_error_at("invalid number: %s", state, start);
|
929
963
|
}
|
930
964
|
|
931
965
|
if ((state->cursor < state->end) && (*state->cursor == '.')) {
|
@@ -933,7 +967,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
933
967
|
state->cursor++;
|
934
968
|
|
935
969
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
936
|
-
raise_parse_error("invalid number: %s", state
|
970
|
+
raise_parse_error("invalid number: %s", state);
|
937
971
|
}
|
938
972
|
|
939
973
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -949,7 +983,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
949
983
|
}
|
950
984
|
|
951
985
|
if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
|
952
|
-
raise_parse_error("invalid number: %s", state
|
986
|
+
raise_parse_error("invalid number: %s", state);
|
953
987
|
}
|
954
988
|
|
955
989
|
while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
|
@@ -1009,7 +1043,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1009
1043
|
}
|
1010
1044
|
}
|
1011
1045
|
|
1012
|
-
raise_parse_error("expected ',' or ']' after array value", state
|
1046
|
+
raise_parse_error("expected ',' or ']' after array value", state);
|
1013
1047
|
}
|
1014
1048
|
break;
|
1015
1049
|
}
|
@@ -1028,13 +1062,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1028
1062
|
}
|
1029
1063
|
|
1030
1064
|
if (*state->cursor != '"') {
|
1031
|
-
raise_parse_error("expected object key, got '%s", state
|
1065
|
+
raise_parse_error("expected object key, got '%s", state);
|
1032
1066
|
}
|
1033
1067
|
json_parse_string(state, config, true);
|
1034
1068
|
|
1035
1069
|
json_eat_whitespace(state);
|
1036
1070
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1037
|
-
raise_parse_error("expected ':' after object key", state
|
1071
|
+
raise_parse_error("expected ':' after object key", state);
|
1038
1072
|
}
|
1039
1073
|
state->cursor++;
|
1040
1074
|
|
@@ -1063,13 +1097,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1063
1097
|
}
|
1064
1098
|
|
1065
1099
|
if (*state->cursor != '"') {
|
1066
|
-
raise_parse_error("expected object key, got: '%s'", state
|
1100
|
+
raise_parse_error("expected object key, got: '%s'", state);
|
1067
1101
|
}
|
1068
1102
|
json_parse_string(state, config, true);
|
1069
1103
|
|
1070
1104
|
json_eat_whitespace(state);
|
1071
1105
|
if ((state->cursor >= state->end) || (*state->cursor != ':')) {
|
1072
|
-
raise_parse_error("expected ':' after object key, got: '%s", state
|
1106
|
+
raise_parse_error("expected ':' after object key, got: '%s", state);
|
1073
1107
|
}
|
1074
1108
|
state->cursor++;
|
1075
1109
|
|
@@ -1079,24 +1113,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
|
|
1079
1113
|
}
|
1080
1114
|
}
|
1081
1115
|
|
1082
|
-
raise_parse_error("expected ',' or '}' after object value, got: '%s'", state
|
1116
|
+
raise_parse_error("expected ',' or '}' after object value, got: '%s'", state);
|
1083
1117
|
}
|
1084
1118
|
break;
|
1085
1119
|
}
|
1086
1120
|
|
1087
1121
|
default:
|
1088
|
-
raise_parse_error("unexpected character: '%s'", state
|
1122
|
+
raise_parse_error("unexpected character: '%s'", state);
|
1089
1123
|
break;
|
1090
1124
|
}
|
1091
1125
|
|
1092
|
-
raise_parse_error("unreacheable: '%s'", state
|
1126
|
+
raise_parse_error("unreacheable: '%s'", state);
|
1093
1127
|
}
|
1094
1128
|
|
1095
1129
|
static void json_ensure_eof(JSON_ParserState *state)
|
1096
1130
|
{
|
1097
1131
|
json_eat_whitespace(state);
|
1098
1132
|
if (state->cursor != state->end) {
|
1099
|
-
raise_parse_error("unexpected token at end of stream '%s'", state
|
1133
|
+
raise_parse_error("unexpected token at end of stream '%s'", state);
|
1100
1134
|
}
|
1101
1135
|
}
|
1102
1136
|
|
@@ -1232,9 +1266,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
|
|
1232
1266
|
.capa = RVALUE_STACK_INITIAL_CAPA,
|
1233
1267
|
};
|
1234
1268
|
|
1269
|
+
long len;
|
1270
|
+
const char *start;
|
1271
|
+
RSTRING_GETMEM(Vsource, start, len);
|
1272
|
+
|
1235
1273
|
JSON_ParserState _state = {
|
1236
|
-
.
|
1237
|
-
.
|
1274
|
+
.start = start,
|
1275
|
+
.cursor = start,
|
1276
|
+
.end = start + len,
|
1238
1277
|
.stack = &stack,
|
1239
1278
|
};
|
1240
1279
|
JSON_ParserState *state = &_state;
|
@@ -41,7 +41,7 @@ typedef struct Fp {
|
|
41
41
|
int exp;
|
42
42
|
} Fp;
|
43
43
|
|
44
|
-
static Fp powers_ten[] = {
|
44
|
+
static const Fp powers_ten[] = {
|
45
45
|
{ 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
|
46
46
|
{ 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
|
47
47
|
{ 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
|
@@ -123,7 +123,7 @@ static Fp find_cachedpow10(int exp, int* k)
|
|
123
123
|
#define absv(n) ((n) < 0 ? -(n) : (n))
|
124
124
|
#define minv(a, b) ((a) < (b) ? (a) : (b))
|
125
125
|
|
126
|
-
static uint64_t tens[] = {
|
126
|
+
static const uint64_t tens[] = {
|
127
127
|
10000000000000000000U, 1000000000000000000U, 100000000000000000U,
|
128
128
|
10000000000000000U, 1000000000000000U, 100000000000000U,
|
129
129
|
10000000000000U, 1000000000000U, 100000000000U,
|
@@ -244,7 +244,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
|
|
244
244
|
uint64_t part2 = upper->frac & (one.frac - 1);
|
245
245
|
|
246
246
|
int idx = 0, kappa = 10;
|
247
|
-
uint64_t* divp;
|
247
|
+
const uint64_t* divp;
|
248
248
|
/* 1000000000 */
|
249
249
|
for(divp = tens + 10; kappa > 0; divp++) {
|
250
250
|
|
@@ -268,7 +268,7 @@ static int generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K)
|
|
268
268
|
}
|
269
269
|
|
270
270
|
/* 10 */
|
271
|
-
uint64_t* unit = tens + 18;
|
271
|
+
const uint64_t* unit = tens + 18;
|
272
272
|
|
273
273
|
while(true) {
|
274
274
|
part2 *= 10;
|
@@ -340,7 +340,7 @@ static int emit_digits(char* digits, int ndigits, char* dest, int K, bool neg)
|
|
340
340
|
}
|
341
341
|
|
342
342
|
/* write decimal w/o scientific notation */
|
343
|
-
if(K < 0 && (K > -7 || exp <
|
343
|
+
if(K < 0 && (K > -7 || exp < 10)) {
|
344
344
|
int offset = ndigits - absv(K);
|
345
345
|
/* fp < 1.0 -> write leading zero */
|
346
346
|
if(offset <= 0) {
|
data/lib/json/common.rb
CHANGED
@@ -230,7 +230,9 @@ module JSON
|
|
230
230
|
class JSONError < StandardError; end
|
231
231
|
|
232
232
|
# This exception is raised if a parser error occurs.
|
233
|
-
class ParserError < JSONError
|
233
|
+
class ParserError < JSONError
|
234
|
+
attr_reader :line, :column
|
235
|
+
end
|
234
236
|
|
235
237
|
# This exception is raised if the nesting of parsed data structures is too
|
236
238
|
# deep.
|
data/lib/json/version.rb
CHANGED
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Florian Frank
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-05-12 00:00:00.000000000 Z
|
11
11
|
dependencies: []
|
12
12
|
description: This is a JSON implementation as a Ruby extension in C.
|
13
13
|
email: flori@ping.de
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- ext/json/ext/fbuffer/fbuffer.h
|
27
27
|
- ext/json/ext/generator/extconf.rb
|
28
28
|
- ext/json/ext/generator/generator.c
|
29
|
+
- ext/json/ext/generator/simd.h
|
29
30
|
- ext/json/ext/parser/extconf.rb
|
30
31
|
- ext/json/ext/parser/parser.c
|
31
32
|
- ext/json/ext/vendor/fpconv.c
|