json 2.11.3 → 2.12.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.
@@ -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,33 +337,128 @@ 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
- unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
396
+ unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 3];
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;
350
401
 
351
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
352
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
402
+ while (cursor >= state->start) {
403
+ if (*cursor-- == '\n') {
404
+ break;
405
+ }
406
+ column++;
407
+ }
353
408
 
354
- while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
355
- len--;
409
+ while (cursor >= state->start) {
410
+ if (*cursor-- == '\n') {
411
+ line++;
356
412
  }
413
+ }
357
414
 
358
- if (buffer[len - 1] >= 0xC0) { // multibyte character start
359
- len--;
415
+ const char *ptr = "EOF";
416
+ if (state->cursor && state->cursor < state->end) {
417
+ ptr = state->cursor;
418
+ size_t len = 0;
419
+ while (len < PARSE_ERROR_FRAGMENT_LEN) {
420
+ char ch = ptr[len];
421
+ if (!ch || ch == '\n' || ch == ' ' || ch == '\t' || ch == '\r') {
422
+ break;
423
+ }
424
+ len++;
360
425
  }
361
426
 
362
- buffer[len] = '\0';
363
- ptr = (const char *)buffer;
427
+ if (len) {
428
+ buffer[0] = '\'';
429
+ MEMCPY(buffer + 1, ptr, char, len);
430
+
431
+ while (buffer[len] >= 0x80 && buffer[len] < 0xC0) { // Is continuation byte
432
+ len--;
433
+ }
434
+
435
+ if (buffer[len] >= 0xC0) { // multibyte character start
436
+ len--;
437
+ }
438
+
439
+ buffer[len + 1] = '\'';
440
+ buffer[len + 2] = '\0';
441
+ ptr = (const char *)buffer;
442
+ }
364
443
  }
365
444
 
366
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
445
+ VALUE msg = rb_sprintf(format, ptr);
446
+ VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
447
+ RB_GC_GUARD(msg);
448
+
449
+ VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
450
+ rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
451
+ rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
452
+ rb_exc_raise(exc);
453
+ }
454
+
455
+ #ifdef RBIMPL_ATTR_NORETURN
456
+ RBIMPL_ATTR_NORETURN()
457
+ #endif
458
+ static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
459
+ {
460
+ state->cursor = at;
461
+ raise_parse_error(format, state);
367
462
  }
368
463
 
369
464
  /* unicode */
@@ -385,73 +480,25 @@ static const signed char digit_values[256] = {
385
480
  -1, -1, -1, -1, -1, -1, -1
386
481
  };
387
482
 
388
- static uint32_t unescape_unicode(const unsigned char *p)
483
+ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
389
484
  {
390
485
  signed char b;
391
486
  uint32_t result = 0;
392
487
  b = digit_values[p[0]];
393
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
488
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
394
489
  result = (result << 4) | (unsigned char)b;
395
490
  b = digit_values[p[1]];
396
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
491
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
397
492
  result = (result << 4) | (unsigned char)b;
398
493
  b = digit_values[p[2]];
399
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
494
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
400
495
  result = (result << 4) | (unsigned char)b;
401
496
  b = digit_values[p[3]];
402
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
497
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
403
498
  result = (result << 4) | (unsigned char)b;
404
499
  return result;
405
500
  }
406
501
 
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
502
  #define GET_PARSER_CONFIG \
456
503
  JSON_ParserConfig *config; \
457
504
  TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
@@ -485,8 +532,7 @@ json_eat_comments(JSON_ParserState *state)
485
532
  while (true) {
486
533
  state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
487
534
  if (!state->cursor) {
488
- state->cursor = state->end;
489
- raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
535
+ raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
490
536
  } else {
491
537
  state->cursor++;
492
538
  if (state->cursor < state->end && *state->cursor == '/') {
@@ -498,11 +544,11 @@ json_eat_comments(JSON_ParserState *state)
498
544
  break;
499
545
  }
500
546
  default:
501
- raise_parse_error("unexpected token at '%s'", state->cursor);
547
+ raise_parse_error("unexpected token %s", state);
502
548
  break;
503
549
  }
504
550
  } else {
505
- raise_parse_error("unexpected token at '%s'", state->cursor);
551
+ raise_parse_error("unexpected token %s", state);
506
552
  }
507
553
  }
508
554
 
@@ -621,9 +667,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
621
667
  break;
622
668
  case 'u':
623
669
  if (pe > stringEnd - 5) {
624
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
670
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
625
671
  } else {
626
- uint32_t ch = unescape_unicode((unsigned char *) ++pe);
672
+ uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
627
673
  pe += 3;
628
674
  /* To handle values above U+FFFF, we take a sequence of
629
675
  * \uXXXX escapes in the U+D800..U+DBFF then
@@ -638,10 +684,10 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
638
684
  if ((ch & 0xFC00) == 0xD800) {
639
685
  pe++;
640
686
  if (pe > stringEnd - 6) {
641
- raise_parse_error("incomplete surrogate pair at '%s'", p);
687
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
642
688
  }
643
689
  if (pe[0] == '\\' && pe[1] == 'u') {
644
- uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
690
+ uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
645
691
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
646
692
  | (sur & 0x3FF));
647
693
  pe += 5;
@@ -829,12 +875,12 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
829
875
  state->cursor++;
830
876
  escaped = true;
831
877
  if ((unsigned char)*state->cursor < 0x20) {
832
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
878
+ raise_parse_error("invalid ASCII control character in string: %s", state);
833
879
  }
834
880
  break;
835
881
  }
836
882
  default:
837
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
883
+ raise_parse_error("invalid ASCII control character in string: %s", state);
838
884
  break;
839
885
  }
840
886
  }
@@ -842,7 +888,7 @@ static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig
842
888
  state->cursor++;
843
889
  }
844
890
 
845
- raise_parse_error("unexpected end of input, expected closing \"", state->cursor);
891
+ raise_parse_error("unexpected end of input, expected closing \"", state);
846
892
  return Qfalse;
847
893
  }
848
894
 
@@ -850,7 +896,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
850
896
  {
851
897
  json_eat_whitespace(state);
852
898
  if (state->cursor >= state->end) {
853
- raise_parse_error("unexpected end of input", state->cursor);
899
+ raise_parse_error("unexpected end of input", state);
854
900
  }
855
901
 
856
902
  switch (*state->cursor) {
@@ -860,7 +906,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
860
906
  return json_push_value(state, config, Qnil);
861
907
  }
862
908
 
863
- raise_parse_error("unexpected token at '%s'", state->cursor);
909
+ raise_parse_error("unexpected token %s", state);
864
910
  break;
865
911
  case 't':
866
912
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
@@ -868,7 +914,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
868
914
  return json_push_value(state, config, Qtrue);
869
915
  }
870
916
 
871
- raise_parse_error("unexpected token at '%s'", state->cursor);
917
+ raise_parse_error("unexpected token %s", state);
872
918
  break;
873
919
  case 'f':
874
920
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -877,7 +923,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
877
923
  return json_push_value(state, config, Qfalse);
878
924
  }
879
925
 
880
- raise_parse_error("unexpected token at '%s'", state->cursor);
926
+ raise_parse_error("unexpected token %s", state);
881
927
  break;
882
928
  case 'N':
883
929
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -886,7 +932,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
886
932
  return json_push_value(state, config, CNaN);
887
933
  }
888
934
 
889
- raise_parse_error("unexpected token at '%s'", state->cursor);
935
+ raise_parse_error("unexpected token %s", state);
890
936
  break;
891
937
  case 'I':
892
938
  if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
@@ -894,7 +940,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
894
940
  return json_push_value(state, config, CInfinity);
895
941
  }
896
942
 
897
- raise_parse_error("unexpected token at '%s'", state->cursor);
943
+ raise_parse_error("unexpected token %s", state);
898
944
  break;
899
945
  case '-':
900
946
  // Note: memcmp with a small power of two compile to an integer comparison
@@ -903,7 +949,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
903
949
  state->cursor += 9;
904
950
  return json_push_value(state, config, CMinusInfinity);
905
951
  } else {
906
- raise_parse_error("unexpected token at '%s'", state->cursor);
952
+ raise_parse_error("unexpected token %s", state);
907
953
  }
908
954
  }
909
955
  // Fallthrough
@@ -921,11 +967,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
921
967
  long integer_length = state->cursor - start;
922
968
 
923
969
  if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
924
- raise_parse_error("invalid number: %s", start);
970
+ raise_parse_error_at("invalid number: %s", state, start);
925
971
  } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
926
- raise_parse_error("invalid number: %s", start);
972
+ raise_parse_error_at("invalid number: %s", state, start);
927
973
  } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
928
- raise_parse_error("invalid number: %s", start);
974
+ raise_parse_error_at("invalid number: %s", state, start);
929
975
  }
930
976
 
931
977
  if ((state->cursor < state->end) && (*state->cursor == '.')) {
@@ -933,7 +979,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
933
979
  state->cursor++;
934
980
 
935
981
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
936
- raise_parse_error("invalid number: %s", state->cursor);
982
+ raise_parse_error("invalid number: %s", state);
937
983
  }
938
984
 
939
985
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -949,7 +995,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
949
995
  }
950
996
 
951
997
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
952
- raise_parse_error("invalid number: %s", state->cursor);
998
+ raise_parse_error("invalid number: %s", state);
953
999
  }
954
1000
 
955
1001
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -1009,7 +1055,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1009
1055
  }
1010
1056
  }
1011
1057
 
1012
- raise_parse_error("expected ',' or ']' after array value", state->cursor);
1058
+ raise_parse_error("expected ',' or ']' after array value", state);
1013
1059
  }
1014
1060
  break;
1015
1061
  }
@@ -1028,13 +1074,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1028
1074
  }
1029
1075
 
1030
1076
  if (*state->cursor != '"') {
1031
- raise_parse_error("expected object key, got '%s", state->cursor);
1077
+ raise_parse_error("expected object key, got %s", state);
1032
1078
  }
1033
1079
  json_parse_string(state, config, true);
1034
1080
 
1035
1081
  json_eat_whitespace(state);
1036
1082
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1037
- raise_parse_error("expected ':' after object key", state->cursor);
1083
+ raise_parse_error("expected ':' after object key", state);
1038
1084
  }
1039
1085
  state->cursor++;
1040
1086
 
@@ -1063,13 +1109,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1063
1109
  }
1064
1110
 
1065
1111
  if (*state->cursor != '"') {
1066
- raise_parse_error("expected object key, got: '%s'", state->cursor);
1112
+ raise_parse_error("expected object key, got: %s", state);
1067
1113
  }
1068
1114
  json_parse_string(state, config, true);
1069
1115
 
1070
1116
  json_eat_whitespace(state);
1071
1117
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1072
- raise_parse_error("expected ':' after object key, got: '%s", state->cursor);
1118
+ raise_parse_error("expected ':' after object key, got: %s", state);
1073
1119
  }
1074
1120
  state->cursor++;
1075
1121
 
@@ -1079,24 +1125,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1079
1125
  }
1080
1126
  }
1081
1127
 
1082
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor);
1128
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
1083
1129
  }
1084
1130
  break;
1085
1131
  }
1086
1132
 
1087
1133
  default:
1088
- raise_parse_error("unexpected character: '%s'", state->cursor);
1134
+ raise_parse_error("unexpected character: %s", state);
1089
1135
  break;
1090
1136
  }
1091
1137
 
1092
- raise_parse_error("unreacheable: '%s'", state->cursor);
1138
+ raise_parse_error("unreacheable: %s", state);
1093
1139
  }
1094
1140
 
1095
1141
  static void json_ensure_eof(JSON_ParserState *state)
1096
1142
  {
1097
1143
  json_eat_whitespace(state);
1098
1144
  if (state->cursor != state->end) {
1099
- raise_parse_error("unexpected token at end of stream '%s'", state->cursor);
1145
+ raise_parse_error("unexpected token at end of stream %s", state);
1100
1146
  }
1101
1147
  }
1102
1148
 
@@ -1232,9 +1278,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
1232
1278
  .capa = RVALUE_STACK_INITIAL_CAPA,
1233
1279
  };
1234
1280
 
1281
+ long len;
1282
+ const char *start;
1283
+ RSTRING_GETMEM(Vsource, start, len);
1284
+
1235
1285
  JSON_ParserState _state = {
1236
- .cursor = RSTRING_PTR(Vsource),
1237
- .end = RSTRING_END(Vsource),
1286
+ .start = start,
1287
+ .cursor = start,
1288
+ .end = start + len,
1238
1289
  .stack = &stack,
1239
1290
  };
1240
1291
  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 },
@@ -92,7 +92,7 @@ static Fp find_cachedpow10(int exp, int* k)
92
92
  {
93
93
  const double one_log_ten = 0.30102999566398114;
94
94
 
95
- int approx = -(exp + npowers) * one_log_ten;
95
+ int approx = (int)(-(exp + npowers) * one_log_ten);
96
96
  int idx = (approx - firstpower) / steppowers;
97
97
 
98
98
  while(1) {
@@ -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) {
@@ -432,8 +432,8 @@ static int filter_special(double fp, char* dest)
432
432
  *
433
433
  * Input:
434
434
  * fp -> the double to convert, dest -> destination buffer.
435
- * The generated string will never be longer than 24 characters.
436
- * Make sure to pass a pointer to at least 24 bytes of memory.
435
+ * The generated string will never be longer than 28 characters.
436
+ * Make sure to pass a pointer to at least 28 bytes of memory.
437
437
  * The emitted string will not be null terminated.
438
438
  *
439
439
  * Output:
@@ -443,7 +443,7 @@ static int filter_special(double fp, char* dest)
443
443
  *
444
444
  * void print(double d)
445
445
  * {
446
- * char buf[24 + 1] // plus null terminator
446
+ * char buf[28 + 1] // plus null terminator
447
447
  * int str_len = fpconv_dtoa(d, buf);
448
448
  *
449
449
  * buf[str_len] = '\0';
@@ -451,7 +451,7 @@ static int filter_special(double fp, char* dest)
451
451
  * }
452
452
  *
453
453
  */
454
- static int fpconv_dtoa(double d, char dest[24])
454
+ static int fpconv_dtoa(double d, char dest[28])
455
455
  {
456
456
  char digits[18];
457
457