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.
@@ -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, const char *start)
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
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
349
- const char *ptr = start;
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, start, char, PARSE_ERROR_FRAGMENT_LEN);
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
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
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) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
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) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
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) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
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) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
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
- state->cursor = state->end;
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 at '%s'", state->cursor);
535
+ raise_parse_error("unexpected token '%s'", state);
502
536
  break;
503
537
  }
504
538
  } else {
505
- raise_parse_error("unexpected token at '%s'", state->cursor);
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
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
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
- raise_parse_error("incomplete surrogate pair at '%s'", p);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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 at '%s'", state->cursor);
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 at '%s'", state->cursor);
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 at '%s'", state->cursor);
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 at '%s'", state->cursor);
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 at '%s'", state->cursor);
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 at '%s'", state->cursor);
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
- raise_parse_error("invalid number: %s", start);
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
- raise_parse_error("invalid number: %s", start);
960
+ raise_parse_error_at("invalid number: %s", state, start);
927
961
  } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
928
- raise_parse_error("invalid number: %s", start);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
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->cursor);
1122
+ raise_parse_error("unexpected character: '%s'", state);
1089
1123
  break;
1090
1124
  }
1091
1125
 
1092
- raise_parse_error("unreacheable: '%s'", state->cursor);
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->cursor);
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
- .cursor = RSTRING_PTR(Vsource),
1237
- .end = RSTRING_END(Vsource),
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 < 4)) {
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; end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSON
4
- VERSION = '2.11.2'
4
+ VERSION = '2.12.0'
5
5
  end
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.11.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-04-24 00:00:00.000000000 Z
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