json 2.10.2 → 2.15.1

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.
@@ -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
@@ -31,28 +33,15 @@ typedef unsigned char _Bool;
31
33
  static VALUE mJSON, eNestingError, Encoding_UTF_8;
32
34
  static VALUE CNaN, CInfinity, CMinusInfinity;
33
35
 
34
- static ID i_json_creatable_p, i_json_create, i_create_id,
35
- i_chr, i_deep_const_get, i_match, i_aset, i_aref,
36
+ static ID i_chr, i_aset, i_aref,
36
37
  i_leftshift, i_new, i_try_convert, i_uminus, i_encode;
37
38
 
38
39
  static VALUE sym_max_nesting, sym_allow_nan, sym_allow_trailing_comma, sym_symbolize_names, sym_freeze,
39
- sym_create_additions, sym_create_id, sym_object_class, sym_array_class,
40
- sym_decimal_class, sym_match_string;
40
+ sym_decimal_class, sym_on_load, sym_allow_duplicate_key;
41
41
 
42
42
  static int binary_encindex;
43
43
  static int utf8_encindex;
44
44
 
45
- #ifdef HAVE_RB_CATEGORY_WARN
46
- # define json_deprecated(message) rb_category_warn(RB_WARN_CATEGORY_DEPRECATED, message)
47
- #else
48
- # define json_deprecated(message) rb_warn(message)
49
- #endif
50
-
51
- static const char deprecated_create_additions_warning[] =
52
- "JSON.load implicit support for `create_additions: true` is deprecated "
53
- "and will be removed in 3.0, use JSON.unsafe_load or explicitly "
54
- "pass `create_additions: true`";
55
-
56
45
  #ifndef HAVE_RB_HASH_BULK_INSERT
57
46
  // For TruffleRuby
58
47
  void
@@ -350,73 +339,6 @@ static size_t strnlen(const char *s, size_t maxlen)
350
339
  }
351
340
  #endif
352
341
 
353
- #define PARSE_ERROR_FRAGMENT_LEN 32
354
- #ifdef RBIMPL_ATTR_NORETURN
355
- RBIMPL_ATTR_NORETURN()
356
- #endif
357
- static void raise_parse_error(const char *format, const char *start)
358
- {
359
- unsigned char buffer[PARSE_ERROR_FRAGMENT_LEN + 1];
360
-
361
- size_t len = start ? strnlen(start, PARSE_ERROR_FRAGMENT_LEN) : 0;
362
- const char *ptr = start;
363
-
364
- if (len == PARSE_ERROR_FRAGMENT_LEN) {
365
- MEMCPY(buffer, start, char, PARSE_ERROR_FRAGMENT_LEN);
366
-
367
- while (buffer[len - 1] >= 0x80 && buffer[len - 1] < 0xC0) { // Is continuation byte
368
- len--;
369
- }
370
-
371
- if (buffer[len - 1] >= 0xC0) { // multibyte character start
372
- len--;
373
- }
374
-
375
- buffer[len] = '\0';
376
- ptr = (const char *)buffer;
377
- }
378
-
379
- rb_enc_raise(enc_utf8, rb_path2class("JSON::ParserError"), format, ptr);
380
- }
381
-
382
- /* unicode */
383
-
384
- static const signed char digit_values[256] = {
385
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
386
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
387
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
388
- -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
389
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
390
- 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
391
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
392
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
393
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
394
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
395
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
396
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
397
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
398
- -1, -1, -1, -1, -1, -1, -1
399
- };
400
-
401
- static uint32_t unescape_unicode(const unsigned char *p)
402
- {
403
- signed char b;
404
- uint32_t result = 0;
405
- b = digit_values[p[0]];
406
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
407
- result = (result << 4) | (unsigned char)b;
408
- b = digit_values[p[1]];
409
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
410
- result = (result << 4) | (unsigned char)b;
411
- b = digit_values[p[2]];
412
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
413
- result = (result << 4) | (unsigned char)b;
414
- b = digit_values[p[3]];
415
- if (b < 0) raise_parse_error("incomplete unicode character escape sequence at '%s'", (char *)p - 2);
416
- result = (result << 4) | (unsigned char)b;
417
- return result;
418
- }
419
-
420
342
  static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
421
343
  {
422
344
  int len = 1;
@@ -443,25 +365,28 @@ static int convert_UTF32_to_UTF8(char *buf, uint32_t ch)
443
365
  return len;
444
366
  }
445
367
 
368
+ enum duplicate_key_action {
369
+ JSON_DEPRECATED = 0,
370
+ JSON_IGNORE,
371
+ JSON_RAISE,
372
+ };
373
+
446
374
  typedef struct JSON_ParserStruct {
447
- VALUE create_id;
448
- VALUE object_class;
449
- VALUE array_class;
375
+ VALUE on_load_proc;
450
376
  VALUE decimal_class;
451
377
  ID decimal_method_id;
452
- VALUE match_string;
378
+ enum duplicate_key_action on_duplicate_key;
453
379
  int max_nesting;
454
380
  bool allow_nan;
455
381
  bool allow_trailing_comma;
456
382
  bool parsing_name;
457
383
  bool symbolize_names;
458
384
  bool freeze;
459
- bool create_additions;
460
- bool deprecated_create_additions;
461
385
  } JSON_ParserConfig;
462
386
 
463
387
  typedef struct JSON_ParserStateStruct {
464
388
  VALUE stack_handle;
389
+ const char *start;
465
390
  const char *cursor;
466
391
  const char *end;
467
392
  rvalue_stack *stack;
@@ -470,6 +395,135 @@ typedef struct JSON_ParserStateStruct {
470
395
  int current_nesting;
471
396
  } JSON_ParserState;
472
397
 
398
+ static void cursor_position(JSON_ParserState *state, long *line_out, long *column_out)
399
+ {
400
+ const char *cursor = state->cursor;
401
+ long column = 0;
402
+ long line = 1;
403
+
404
+ while (cursor >= state->start) {
405
+ if (*cursor-- == '\n') {
406
+ break;
407
+ }
408
+ column++;
409
+ }
410
+
411
+ while (cursor >= state->start) {
412
+ if (*cursor-- == '\n') {
413
+ line++;
414
+ }
415
+ }
416
+ *line_out = line;
417
+ *column_out = column;
418
+ }
419
+
420
+ static void emit_parse_warning(const char *message, JSON_ParserState *state)
421
+ {
422
+ long line, column;
423
+ cursor_position(state, &line, &column);
424
+
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
+ }
428
+
429
+ #define PARSE_ERROR_FRAGMENT_LEN 32
430
+
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++;
450
+ }
451
+
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
+ }
468
+ }
469
+
470
+ VALUE msg = rb_sprintf(format, ptr);
471
+ VALUE message = rb_enc_sprintf(enc_utf8, "%s at line %ld column %ld", RSTRING_PTR(msg), line, column);
472
+ RB_GC_GUARD(msg);
473
+
474
+ VALUE exc = rb_exc_new_str(rb_path2class("JSON::ParserError"), message);
475
+ rb_ivar_set(exc, rb_intern("@line"), LONG2NUM(line));
476
+ rb_ivar_set(exc, rb_intern("@column"), LONG2NUM(column));
477
+ rb_exc_raise(exc);
478
+ }
479
+
480
+ #ifdef RBIMPL_ATTR_NORETURN
481
+ RBIMPL_ATTR_NORETURN()
482
+ #endif
483
+ static void raise_parse_error_at(const char *format, JSON_ParserState *state, const char *at)
484
+ {
485
+ state->cursor = at;
486
+ raise_parse_error(format, state);
487
+ }
488
+
489
+ /* unicode */
490
+
491
+ static const signed char digit_values[256] = {
492
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
493
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
494
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1,
495
+ -1, -1, -1, -1, -1, -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1,
496
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
497
+ 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
498
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
499
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
500
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
501
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
502
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
503
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
504
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
505
+ -1, -1, -1, -1, -1, -1, -1
506
+ };
507
+
508
+ static uint32_t unescape_unicode(JSON_ParserState *state, const unsigned char *p)
509
+ {
510
+ signed char b;
511
+ uint32_t result = 0;
512
+ b = digit_values[p[0]];
513
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
514
+ result = (result << 4) | (unsigned char)b;
515
+ b = digit_values[p[1]];
516
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
517
+ result = (result << 4) | (unsigned char)b;
518
+ b = digit_values[p[2]];
519
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
520
+ result = (result << 4) | (unsigned char)b;
521
+ b = digit_values[p[3]];
522
+ if (b < 0) raise_parse_error_at("incomplete unicode character escape sequence at %s", state, (char *)p - 2);
523
+ result = (result << 4) | (unsigned char)b;
524
+ return result;
525
+ }
526
+
473
527
  #define GET_PARSER_CONFIG \
474
528
  JSON_ParserConfig *config; \
475
529
  TypedData_Get_Struct(self, JSON_ParserConfig, &JSON_ParserConfig_type, config)
@@ -488,7 +542,7 @@ static void
488
542
  json_eat_comments(JSON_ParserState *state)
489
543
  {
490
544
  if (state->cursor + 1 < state->end) {
491
- switch(state->cursor[1]) {
545
+ switch (state->cursor[1]) {
492
546
  case '/': {
493
547
  state->cursor = memchr(state->cursor, '\n', state->end - state->cursor);
494
548
  if (!state->cursor) {
@@ -503,8 +557,7 @@ json_eat_comments(JSON_ParserState *state)
503
557
  while (true) {
504
558
  state->cursor = memchr(state->cursor, '*', state->end - state->cursor);
505
559
  if (!state->cursor) {
506
- state->cursor = state->end;
507
- raise_parse_error("unexpected end of input, expected closing '*/'", state->cursor);
560
+ raise_parse_error_at("unexpected end of input, expected closing '*/'", state, state->end);
508
561
  } else {
509
562
  state->cursor++;
510
563
  if (state->cursor < state->end && *state->cursor == '/') {
@@ -516,11 +569,11 @@ json_eat_comments(JSON_ParserState *state)
516
569
  break;
517
570
  }
518
571
  default:
519
- raise_parse_error("unexpected token at '%s'", state->cursor);
572
+ raise_parse_error("unexpected token %s", state);
520
573
  break;
521
574
  }
522
575
  } else {
523
- raise_parse_error("unexpected token at '%s'", state->cursor);
576
+ raise_parse_error("unexpected token %s", state);
524
577
  }
525
578
  }
526
579
 
@@ -639,9 +692,9 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
639
692
  break;
640
693
  case 'u':
641
694
  if (pe > stringEnd - 5) {
642
- raise_parse_error("incomplete unicode character escape sequence at '%s'", p);
695
+ raise_parse_error_at("incomplete unicode character escape sequence at %s", state, p);
643
696
  } else {
644
- uint32_t ch = unescape_unicode((unsigned char *) ++pe);
697
+ uint32_t ch = unescape_unicode(state, (unsigned char *) ++pe);
645
698
  pe += 3;
646
699
  /* To handle values above U+FFFF, we take a sequence of
647
700
  * \uXXXX escapes in the U+D800..U+DBFF then
@@ -656,15 +709,20 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
656
709
  if ((ch & 0xFC00) == 0xD800) {
657
710
  pe++;
658
711
  if (pe > stringEnd - 6) {
659
- raise_parse_error("incomplete surrogate pair at '%s'", p);
712
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
660
713
  }
661
714
  if (pe[0] == '\\' && pe[1] == 'u') {
662
- uint32_t sur = unescape_unicode((unsigned char *) pe + 2);
715
+ uint32_t sur = unescape_unicode(state, (unsigned char *) pe + 2);
716
+
717
+ if ((sur & 0xFC00) != 0xDC00) {
718
+ raise_parse_error_at("invalid surrogate pair at %s", state, p);
719
+ }
720
+
663
721
  ch = (((ch & 0x3F) << 10) | ((((ch >> 6) & 0xF) + 1) << 16)
664
722
  | (sur & 0x3FF));
665
723
  pe += 5;
666
724
  } else {
667
- unescape = (char *) "?";
725
+ raise_parse_error_at("incomplete surrogate pair at %s", state, p);
668
726
  break;
669
727
  }
670
728
  }
@@ -769,18 +827,7 @@ static VALUE json_decode_float(JSON_ParserConfig *config, const char *start, con
769
827
 
770
828
  static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig *config, long count)
771
829
  {
772
- VALUE array;
773
- if (RB_UNLIKELY(config->array_class)) {
774
- array = rb_class_new_instance(0, 0, config->array_class);
775
- VALUE *items = rvalue_stack_peek(state->stack, count);
776
- long index;
777
- for (index = 0; index < count; index++) {
778
- rb_funcall(array, i_leftshift, 1, items[index]);
779
- }
780
- } else {
781
- array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
782
- }
783
-
830
+ VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(state->stack, count));
784
831
  rvalue_stack_pop(state->stack, count);
785
832
 
786
833
  if (config->freeze) {
@@ -790,43 +837,70 @@ static inline VALUE json_decode_array(JSON_ParserState *state, JSON_ParserConfig
790
837
  return array;
791
838
  }
792
839
 
793
- static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, long count)
840
+ static VALUE json_find_duplicated_key(size_t count, const VALUE *pairs)
794
841
  {
795
- VALUE object;
796
- if (RB_UNLIKELY(config->object_class)) {
797
- object = rb_class_new_instance(0, 0, config->object_class);
798
- long index = 0;
799
- VALUE *items = rvalue_stack_peek(state->stack, count);
800
- while (index < count) {
801
- VALUE name = items[index++];
802
- VALUE value = items[index++];
803
- rb_funcall(object, i_aset, 2, name, value);
842
+ VALUE set = rb_hash_new_capa(count / 2);
843
+ for (size_t index = 0; index < count; index += 2) {
844
+ size_t before = RHASH_SIZE(set);
845
+ VALUE key = pairs[index];
846
+ rb_hash_aset(set, key, Qtrue);
847
+ if (RHASH_SIZE(set) == before) {
848
+ if (RB_SYMBOL_P(key)) {
849
+ return rb_sym2str(key);
850
+ }
851
+ return key;
804
852
  }
805
- } else {
806
- object = rb_hash_new_capa(count);
807
- rb_hash_bulk_insert(count, rvalue_stack_peek(state->stack, count), object);
808
853
  }
854
+ return Qfalse;
855
+ }
809
856
 
810
- rvalue_stack_pop(state->stack, count);
857
+ static void emit_duplicate_key_warning(JSON_ParserState *state, VALUE duplicate_key)
858
+ {
859
+ VALUE message = rb_sprintf(
860
+ "detected duplicate key %"PRIsVALUE" in JSON object. This will raise an error in json 3.0 unless enabled via `allow_duplicate_key: true`",
861
+ rb_inspect(duplicate_key)
862
+ );
811
863
 
812
- if (RB_UNLIKELY(config->create_additions)) {
813
- VALUE klassname;
814
- if (config->object_class) {
815
- klassname = rb_funcall(object, i_aref, 1, config->create_id);
816
- } else {
817
- klassname = rb_hash_aref(object, config->create_id);
818
- }
819
- if (!NIL_P(klassname)) {
820
- VALUE klass = rb_funcall(mJSON, i_deep_const_get, 1, klassname);
821
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0))) {
822
- if (config->deprecated_create_additions) {
823
- json_deprecated(deprecated_create_additions_warning);
824
- }
825
- object = rb_funcall(klass, i_json_create, 1, object);
826
- }
864
+ emit_parse_warning(RSTRING_PTR(message), state);
865
+ RB_GC_GUARD(message);
866
+ }
867
+
868
+ #ifdef RBIMPL_ATTR_NORETURN
869
+ RBIMPL_ATTR_NORETURN()
870
+ #endif
871
+ static void raise_duplicate_key_error(JSON_ParserState *state, VALUE duplicate_key)
872
+ {
873
+ VALUE message = rb_sprintf(
874
+ "duplicate key %"PRIsVALUE,
875
+ rb_inspect(duplicate_key)
876
+ );
877
+
878
+ raise_parse_error(RSTRING_PTR(message), state);
879
+ RB_GC_GUARD(message);
880
+ }
881
+
882
+ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfig *config, size_t count)
883
+ {
884
+ size_t entries_count = count / 2;
885
+ VALUE object = rb_hash_new_capa(entries_count);
886
+ const VALUE *pairs = rvalue_stack_peek(state->stack, count);
887
+ rb_hash_bulk_insert(count, pairs, object);
888
+
889
+ if (RB_UNLIKELY(RHASH_SIZE(object) < entries_count)) {
890
+ switch (config->on_duplicate_key) {
891
+ case JSON_IGNORE:
892
+ break;
893
+ case JSON_DEPRECATED:
894
+ emit_duplicate_key_warning(state, json_find_duplicated_key(count, pairs));
895
+ break;
896
+ case JSON_RAISE:
897
+ raise_duplicate_key_error(state, json_find_duplicated_key(count, pairs));
898
+ break;
827
899
  }
828
900
  }
829
901
 
902
+ rvalue_stack_pop(state->stack, count);
903
+
830
904
  if (config->freeze) {
831
905
  RB_OBJ_FREEZE(object);
832
906
  }
@@ -834,17 +908,6 @@ static inline VALUE json_decode_object(JSON_ParserState *state, JSON_ParserConfi
834
908
  return object;
835
909
  }
836
910
 
837
- static int match_i(VALUE regexp, VALUE klass, VALUE memo)
838
- {
839
- if (regexp == Qundef) return ST_STOP;
840
- if (RTEST(rb_funcall(klass, i_json_creatable_p, 0)) &&
841
- RTEST(rb_funcall(regexp, i_match, 1, rb_ary_entry(memo, 0)))) {
842
- rb_ary_push(memo, klass);
843
- return ST_STOP;
844
- }
845
- return ST_CONTINUE;
846
- }
847
-
848
911
  static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfig *config, const char *start, const char *end, bool escaped, bool is_name)
849
912
  {
850
913
  VALUE string;
@@ -856,23 +919,19 @@ static inline VALUE json_decode_string(JSON_ParserState *state, JSON_ParserConfi
856
919
  string = json_string_fastpath(state, start, end, is_name, intern, symbolize);
857
920
  }
858
921
 
859
- if (RB_UNLIKELY(config->create_additions && RTEST(config->match_string))) {
860
- VALUE klass;
861
- VALUE memo = rb_ary_new2(2);
862
- rb_ary_push(memo, string);
863
- rb_hash_foreach(config->match_string, match_i, memo);
864
- klass = rb_ary_entry(memo, 1);
865
- if (RTEST(klass)) {
866
- string = rb_funcall(klass, i_json_create, 1, string);
867
- }
868
- }
869
-
870
922
  return string;
871
923
  }
872
924
 
873
- #define PUSH(result) rvalue_stack_push(state->stack, result, &state->stack_handle, &state->stack)
925
+ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *config, VALUE value)
926
+ {
927
+ if (RB_UNLIKELY(config->on_load_proc)) {
928
+ value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
929
+ }
930
+ rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
931
+ return value;
932
+ }
874
933
 
875
- static const bool string_scan[256] = {
934
+ static const bool string_scan_table[256] = {
876
935
  // ASCII Control Characters
877
936
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
878
937
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
@@ -885,38 +944,77 @@ static const bool string_scan[256] = {
885
944
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
886
945
  };
887
946
 
947
+ #if (defined(__GNUC__ ) || defined(__clang__))
948
+ #define FORCE_INLINE __attribute__((always_inline))
949
+ #else
950
+ #define FORCE_INLINE
951
+ #endif
952
+
953
+ #ifdef HAVE_SIMD
954
+ static SIMD_Implementation simd_impl = SIMD_NONE;
955
+ #endif /* HAVE_SIMD */
956
+
957
+ static inline bool FORCE_INLINE string_scan(JSON_ParserState *state)
958
+ {
959
+ #ifdef HAVE_SIMD
960
+ #if defined(HAVE_SIMD_NEON)
961
+
962
+ uint64_t mask = 0;
963
+ if (string_scan_simd_neon(&state->cursor, state->end, &mask)) {
964
+ state->cursor += trailing_zeros64(mask) >> 2;
965
+ return 1;
966
+ }
967
+
968
+ #elif defined(HAVE_SIMD_SSE2)
969
+ if (simd_impl == SIMD_SSE2) {
970
+ int mask = 0;
971
+ if (string_scan_simd_sse2(&state->cursor, state->end, &mask)) {
972
+ state->cursor += trailing_zeros(mask);
973
+ return 1;
974
+ }
975
+ }
976
+ #endif /* HAVE_SIMD_NEON or HAVE_SIMD_SSE2 */
977
+ #endif /* HAVE_SIMD */
978
+
979
+ while (state->cursor < state->end) {
980
+ if (RB_UNLIKELY(string_scan_table[(unsigned char)*state->cursor])) {
981
+ return 1;
982
+ }
983
+ state->cursor++;
984
+ }
985
+ return 0;
986
+ }
987
+
888
988
  static inline VALUE json_parse_string(JSON_ParserState *state, JSON_ParserConfig *config, bool is_name)
889
989
  {
890
990
  state->cursor++;
891
991
  const char *start = state->cursor;
892
992
  bool escaped = false;
893
993
 
894
- while (state->cursor < state->end) {
895
- if (RB_UNLIKELY(string_scan[(unsigned char)*state->cursor])) {
896
- switch (*state->cursor) {
897
- case '"': {
898
- VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
899
- state->cursor++;
900
- return PUSH(string);
901
- }
902
- case '\\': {
903
- state->cursor++;
904
- escaped = true;
905
- if ((unsigned char)*state->cursor < 0x20) {
906
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
907
- }
908
- break;
994
+ while (RB_UNLIKELY(string_scan(state))) {
995
+ switch (*state->cursor) {
996
+ case '"': {
997
+ VALUE string = json_decode_string(state, config, start, state->cursor, escaped, is_name);
998
+ state->cursor++;
999
+ return json_push_value(state, config, string);
1000
+ }
1001
+ case '\\': {
1002
+ state->cursor++;
1003
+ escaped = true;
1004
+ if ((unsigned char)*state->cursor < 0x20) {
1005
+ raise_parse_error("invalid ASCII control character in string: %s", state);
909
1006
  }
910
- default:
911
- raise_parse_error("invalid ASCII control character in string: %s", state->cursor);
912
- break;
1007
+ break;
913
1008
  }
1009
+ default:
1010
+ raise_parse_error("invalid ASCII control character in string: %s", state);
1011
+ break;
914
1012
  }
915
1013
 
916
1014
  state->cursor++;
917
1015
  }
918
1016
 
919
- raise_parse_error("unexpected end of input, expected closing \"", state->cursor);
1017
+ raise_parse_error("unexpected end of input, expected closing \"", state);
920
1018
  return Qfalse;
921
1019
  }
922
1020
 
@@ -924,60 +1022,60 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
924
1022
  {
925
1023
  json_eat_whitespace(state);
926
1024
  if (state->cursor >= state->end) {
927
- raise_parse_error("unexpected end of input", state->cursor);
1025
+ raise_parse_error("unexpected end of input", state);
928
1026
  }
929
1027
 
930
1028
  switch (*state->cursor) {
931
1029
  case 'n':
932
1030
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "null", 4) == 0)) {
933
1031
  state->cursor += 4;
934
- return PUSH(Qnil);
1032
+ return json_push_value(state, config, Qnil);
935
1033
  }
936
1034
 
937
- raise_parse_error("unexpected token at '%s'", state->cursor);
1035
+ raise_parse_error("unexpected token %s", state);
938
1036
  break;
939
1037
  case 't':
940
1038
  if ((state->end - state->cursor >= 4) && (memcmp(state->cursor, "true", 4) == 0)) {
941
1039
  state->cursor += 4;
942
- return PUSH(Qtrue);
1040
+ return json_push_value(state, config, Qtrue);
943
1041
  }
944
1042
 
945
- raise_parse_error("unexpected token at '%s'", state->cursor);
1043
+ raise_parse_error("unexpected token %s", state);
946
1044
  break;
947
1045
  case 'f':
948
1046
  // Note: memcmp with a small power of two compile to an integer comparison
949
1047
  if ((state->end - state->cursor >= 5) && (memcmp(state->cursor + 1, "alse", 4) == 0)) {
950
1048
  state->cursor += 5;
951
- return PUSH(Qfalse);
1049
+ return json_push_value(state, config, Qfalse);
952
1050
  }
953
1051
 
954
- raise_parse_error("unexpected token at '%s'", state->cursor);
1052
+ raise_parse_error("unexpected token %s", state);
955
1053
  break;
956
1054
  case 'N':
957
1055
  // Note: memcmp with a small power of two compile to an integer comparison
958
1056
  if (config->allow_nan && (state->end - state->cursor >= 3) && (memcmp(state->cursor + 1, "aN", 2) == 0)) {
959
1057
  state->cursor += 3;
960
- return PUSH(CNaN);
1058
+ return json_push_value(state, config, CNaN);
961
1059
  }
962
1060
 
963
- raise_parse_error("unexpected token at '%s'", state->cursor);
1061
+ raise_parse_error("unexpected token %s", state);
964
1062
  break;
965
1063
  case 'I':
966
1064
  if (config->allow_nan && (state->end - state->cursor >= 8) && (memcmp(state->cursor, "Infinity", 8) == 0)) {
967
1065
  state->cursor += 8;
968
- return PUSH(CInfinity);
1066
+ return json_push_value(state, config, CInfinity);
969
1067
  }
970
1068
 
971
- raise_parse_error("unexpected token at '%s'", state->cursor);
1069
+ raise_parse_error("unexpected token %s", state);
972
1070
  break;
973
1071
  case '-':
974
1072
  // Note: memcmp with a small power of two compile to an integer comparison
975
1073
  if ((state->end - state->cursor >= 9) && (memcmp(state->cursor + 1, "Infinity", 8) == 0)) {
976
1074
  if (config->allow_nan) {
977
1075
  state->cursor += 9;
978
- return PUSH(CMinusInfinity);
1076
+ return json_push_value(state, config, CMinusInfinity);
979
1077
  } else {
980
- raise_parse_error("unexpected token at '%s'", state->cursor);
1078
+ raise_parse_error("unexpected token %s", state);
981
1079
  }
982
1080
  }
983
1081
  // Fallthrough
@@ -995,11 +1093,11 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
995
1093
  long integer_length = state->cursor - start;
996
1094
 
997
1095
  if (RB_UNLIKELY(start[0] == '0' && integer_length > 1)) {
998
- raise_parse_error("invalid number: %s", start);
1096
+ raise_parse_error_at("invalid number: %s", state, start);
999
1097
  } else if (RB_UNLIKELY(integer_length > 2 && start[0] == '-' && start[1] == '0')) {
1000
- raise_parse_error("invalid number: %s", start);
1098
+ raise_parse_error_at("invalid number: %s", state, start);
1001
1099
  } else if (RB_UNLIKELY(integer_length == 1 && start[0] == '-')) {
1002
- raise_parse_error("invalid number: %s", start);
1100
+ raise_parse_error_at("invalid number: %s", state, start);
1003
1101
  }
1004
1102
 
1005
1103
  if ((state->cursor < state->end) && (*state->cursor == '.')) {
@@ -1007,7 +1105,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1007
1105
  state->cursor++;
1008
1106
 
1009
1107
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
1010
- raise_parse_error("invalid number: %s", state->cursor);
1108
+ raise_parse_error("invalid number: %s", state);
1011
1109
  }
1012
1110
 
1013
1111
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -1023,7 +1121,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1023
1121
  }
1024
1122
 
1025
1123
  if (state->cursor == state->end || *state->cursor < '0' || *state->cursor > '9') {
1026
- raise_parse_error("invalid number: %s", state->cursor);
1124
+ raise_parse_error("invalid number: %s", state);
1027
1125
  }
1028
1126
 
1029
1127
  while ((state->cursor < state->end) && (*state->cursor >= '0') && (*state->cursor <= '9')) {
@@ -1032,9 +1130,9 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1032
1130
  }
1033
1131
 
1034
1132
  if (integer) {
1035
- return PUSH(json_decode_integer(start, state->cursor));
1133
+ return json_push_value(state, config, json_decode_integer(start, state->cursor));
1036
1134
  }
1037
- return PUSH(json_decode_float(config, start, state->cursor));
1135
+ return json_push_value(state, config, json_decode_float(config, start, state->cursor));
1038
1136
  }
1039
1137
  case '"': {
1040
1138
  // %r{\A"[^"\\\t\n\x00]*(?:\\[bfnrtu\\/"][^"\\]*)*"}
@@ -1048,7 +1146,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1048
1146
 
1049
1147
  if ((state->cursor < state->end) && (*state->cursor == ']')) {
1050
1148
  state->cursor++;
1051
- return PUSH(json_decode_array(state, config, 0));
1149
+ return json_push_value(state, config, json_decode_array(state, config, 0));
1052
1150
  } else {
1053
1151
  state->current_nesting++;
1054
1152
  if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
@@ -1067,7 +1165,7 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1067
1165
  long count = state->stack->head - stack_head;
1068
1166
  state->current_nesting--;
1069
1167
  state->in_array--;
1070
- return PUSH(json_decode_array(state, config, count));
1168
+ return json_push_value(state, config, json_decode_array(state, config, count));
1071
1169
  }
1072
1170
 
1073
1171
  if (*state->cursor == ',') {
@@ -1083,18 +1181,20 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1083
1181
  }
1084
1182
  }
1085
1183
 
1086
- raise_parse_error("expected ',' or ']' after array value", state->cursor);
1184
+ raise_parse_error("expected ',' or ']' after array value", state);
1087
1185
  }
1088
1186
  break;
1089
1187
  }
1090
1188
  case '{': {
1189
+ const char *object_start_cursor = state->cursor;
1190
+
1091
1191
  state->cursor++;
1092
1192
  json_eat_whitespace(state);
1093
1193
  long stack_head = state->stack->head;
1094
1194
 
1095
1195
  if ((state->cursor < state->end) && (*state->cursor == '}')) {
1096
1196
  state->cursor++;
1097
- return PUSH(json_decode_object(state, config, 0));
1197
+ return json_push_value(state, config, json_decode_object(state, config, 0));
1098
1198
  } else {
1099
1199
  state->current_nesting++;
1100
1200
  if (RB_UNLIKELY(config->max_nesting && (config->max_nesting < state->current_nesting))) {
@@ -1102,13 +1202,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1102
1202
  }
1103
1203
 
1104
1204
  if (*state->cursor != '"') {
1105
- raise_parse_error("expected object key, got '%s", state->cursor);
1205
+ raise_parse_error("expected object key, got %s", state);
1106
1206
  }
1107
1207
  json_parse_string(state, config, true);
1108
1208
 
1109
1209
  json_eat_whitespace(state);
1110
1210
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1111
- raise_parse_error("expected ':' after object key", state->cursor);
1211
+ raise_parse_error("expected ':' after object key", state);
1112
1212
  }
1113
1213
  state->cursor++;
1114
1214
 
@@ -1122,8 +1222,15 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1122
1222
  if (*state->cursor == '}') {
1123
1223
  state->cursor++;
1124
1224
  state->current_nesting--;
1125
- long count = state->stack->head - stack_head;
1126
- return PUSH(json_decode_object(state, config, count));
1225
+ size_t count = state->stack->head - stack_head;
1226
+
1227
+ // Temporary rewind cursor in case an error is raised
1228
+ const char *final_cursor = state->cursor;
1229
+ state->cursor = object_start_cursor;
1230
+ VALUE object = json_decode_object(state, config, count);
1231
+ state->cursor = final_cursor;
1232
+
1233
+ return json_push_value(state, config, object);
1127
1234
  }
1128
1235
 
1129
1236
  if (*state->cursor == ',') {
@@ -1137,13 +1244,13 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1137
1244
  }
1138
1245
 
1139
1246
  if (*state->cursor != '"') {
1140
- raise_parse_error("expected object key, got: '%s'", state->cursor);
1247
+ raise_parse_error("expected object key, got: %s", state);
1141
1248
  }
1142
1249
  json_parse_string(state, config, true);
1143
1250
 
1144
1251
  json_eat_whitespace(state);
1145
1252
  if ((state->cursor >= state->end) || (*state->cursor != ':')) {
1146
- raise_parse_error("expected ':' after object key, got: '%s", state->cursor);
1253
+ raise_parse_error("expected ':' after object key, got: %s", state);
1147
1254
  }
1148
1255
  state->cursor++;
1149
1256
 
@@ -1153,24 +1260,24 @@ static VALUE json_parse_any(JSON_ParserState *state, JSON_ParserConfig *config)
1153
1260
  }
1154
1261
  }
1155
1262
 
1156
- raise_parse_error("expected ',' or '}' after object value, got: '%s'", state->cursor);
1263
+ raise_parse_error("expected ',' or '}' after object value, got: %s", state);
1157
1264
  }
1158
1265
  break;
1159
1266
  }
1160
1267
 
1161
1268
  default:
1162
- raise_parse_error("unexpected character: '%s'", state->cursor);
1269
+ raise_parse_error("unexpected character: %s", state);
1163
1270
  break;
1164
1271
  }
1165
1272
 
1166
- raise_parse_error("unreacheable: '%s'", state->cursor);
1273
+ raise_parse_error("unreachable: %s", state);
1167
1274
  }
1168
1275
 
1169
1276
  static void json_ensure_eof(JSON_ParserState *state)
1170
1277
  {
1171
1278
  json_eat_whitespace(state);
1172
1279
  if (state->cursor != state->end) {
1173
- raise_parse_error("unexpected token at end of stream '%s'", state->cursor);
1280
+ raise_parse_error("unexpected token at end of stream %s", state);
1174
1281
  }
1175
1282
  }
1176
1283
 
@@ -1211,10 +1318,8 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1211
1318
  else if (key == sym_allow_trailing_comma) { config->allow_trailing_comma = RTEST(val); }
1212
1319
  else if (key == sym_symbolize_names) { config->symbolize_names = RTEST(val); }
1213
1320
  else if (key == sym_freeze) { config->freeze = RTEST(val); }
1214
- else if (key == sym_create_id) { config->create_id = RTEST(val) ? val : Qfalse; }
1215
- else if (key == sym_object_class) { config->object_class = RTEST(val) ? val : Qfalse; }
1216
- else if (key == sym_array_class) { config->array_class = RTEST(val) ? val : Qfalse; }
1217
- else if (key == sym_match_string) { config->match_string = RTEST(val) ? val : Qfalse; }
1321
+ else if (key == sym_on_load) { config->on_load_proc = RTEST(val) ? val : Qfalse; }
1322
+ else if (key == sym_allow_duplicate_key) { config->on_duplicate_key = RTEST(val) ? JSON_IGNORE : JSON_RAISE; }
1218
1323
  else if (key == sym_decimal_class) {
1219
1324
  if (RTEST(val)) {
1220
1325
  if (rb_respond_to(val, i_try_convert)) {
@@ -1244,15 +1349,6 @@ static int parser_config_init_i(VALUE key, VALUE val, VALUE data)
1244
1349
  }
1245
1350
  }
1246
1351
  }
1247
- else if (key == sym_create_additions) {
1248
- if (NIL_P(val)) {
1249
- config->create_additions = true;
1250
- config->deprecated_create_additions = true;
1251
- } else {
1252
- config->create_additions = RTEST(val);
1253
- config->deprecated_create_additions = false;
1254
- }
1255
- }
1256
1352
 
1257
1353
  return ST_CONTINUE;
1258
1354
  }
@@ -1267,16 +1363,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
1267
1363
  // We assume in most cases few keys are set so it's faster to go over
1268
1364
  // the provided keys than to check all possible keys.
1269
1365
  rb_hash_foreach(opts, parser_config_init_i, (VALUE)config);
1270
-
1271
- if (config->symbolize_names && config->create_additions) {
1272
- rb_raise(rb_eArgError,
1273
- "options :symbolize_names and :create_additions cannot be "
1274
- " used in conjunction");
1275
- }
1276
-
1277
- if (config->create_additions && !config->create_id) {
1278
- config->create_id = rb_funcall(mJSON, i_create_id, 0);
1279
- }
1280
1366
  }
1281
1367
 
1282
1368
  }
@@ -1301,15 +1387,6 @@ static void parser_config_init(JSON_ParserConfig *config, VALUE opts)
1301
1387
  * (keys) in a JSON object. Otherwise strings are returned, which is
1302
1388
  * also the default. It's not possible to use this option in
1303
1389
  * conjunction with the *create_additions* option.
1304
- * * *create_additions*: If set to false, the Parser doesn't create
1305
- * additions even if a matching class and create_id was found. This option
1306
- * defaults to false.
1307
- * * *object_class*: Defaults to Hash. If another type is provided, it will be used
1308
- * instead of Hash to represent JSON objects. The type must respond to
1309
- * +new+ without arguments, and return an object that respond to +[]=+.
1310
- * * *array_class*: Defaults to Array If another type is provided, it will be used
1311
- * instead of Hash to represent JSON arrays. The type must respond to
1312
- * +new+ without arguments, and return an object that respond to +<<+.
1313
1390
  * * *decimal_class*: Specifies which class to use instead of the default
1314
1391
  * (Float) when parsing decimal numbers. This class must accept a single
1315
1392
  * string argument in its constructor.
@@ -1320,11 +1397,7 @@ static VALUE cParserConfig_initialize(VALUE self, VALUE opts)
1320
1397
 
1321
1398
  parser_config_init(config, opts);
1322
1399
 
1323
- RB_OBJ_WRITTEN(self, Qundef, config->create_id);
1324
- RB_OBJ_WRITTEN(self, Qundef, config->object_class);
1325
- RB_OBJ_WRITTEN(self, Qundef, config->array_class);
1326
1400
  RB_OBJ_WRITTEN(self, Qundef, config->decimal_class);
1327
- RB_OBJ_WRITTEN(self, Qundef, config->match_string);
1328
1401
 
1329
1402
  return self;
1330
1403
  }
@@ -1341,9 +1414,14 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
1341
1414
  .capa = RVALUE_STACK_INITIAL_CAPA,
1342
1415
  };
1343
1416
 
1417
+ long len;
1418
+ const char *start;
1419
+ RSTRING_GETMEM(Vsource, start, len);
1420
+
1344
1421
  JSON_ParserState _state = {
1345
- .cursor = RSTRING_PTR(Vsource),
1346
- .end = RSTRING_END(Vsource),
1422
+ .start = start,
1423
+ .cursor = start,
1424
+ .end = start + len,
1347
1425
  .stack = &stack,
1348
1426
  };
1349
1427
  JSON_ParserState *state = &_state;
@@ -1387,11 +1465,8 @@ static VALUE cParser_m_parse(VALUE klass, VALUE Vsource, VALUE opts)
1387
1465
  static void JSON_ParserConfig_mark(void *ptr)
1388
1466
  {
1389
1467
  JSON_ParserConfig *config = ptr;
1390
- rb_gc_mark(config->create_id);
1391
- rb_gc_mark(config->object_class);
1392
- rb_gc_mark(config->array_class);
1468
+ rb_gc_mark(config->on_load_proc);
1393
1469
  rb_gc_mark(config->decimal_class);
1394
- rb_gc_mark(config->match_string);
1395
1470
  }
1396
1471
 
1397
1472
  static void JSON_ParserConfig_free(void *ptr)
@@ -1459,19 +1534,11 @@ void Init_parser(void)
1459
1534
  sym_allow_trailing_comma = ID2SYM(rb_intern("allow_trailing_comma"));
1460
1535
  sym_symbolize_names = ID2SYM(rb_intern("symbolize_names"));
1461
1536
  sym_freeze = ID2SYM(rb_intern("freeze"));
1462
- sym_create_additions = ID2SYM(rb_intern("create_additions"));
1463
- sym_create_id = ID2SYM(rb_intern("create_id"));
1464
- sym_object_class = ID2SYM(rb_intern("object_class"));
1465
- sym_array_class = ID2SYM(rb_intern("array_class"));
1537
+ sym_on_load = ID2SYM(rb_intern("on_load"));
1466
1538
  sym_decimal_class = ID2SYM(rb_intern("decimal_class"));
1467
- sym_match_string = ID2SYM(rb_intern("match_string"));
1539
+ sym_allow_duplicate_key = ID2SYM(rb_intern("allow_duplicate_key"));
1468
1540
 
1469
- i_create_id = rb_intern("create_id");
1470
- i_json_creatable_p = rb_intern("json_creatable?");
1471
- i_json_create = rb_intern("json_create");
1472
1541
  i_chr = rb_intern("chr");
1473
- i_match = rb_intern("match");
1474
- i_deep_const_get = rb_intern("deep_const_get");
1475
1542
  i_aset = rb_intern("[]=");
1476
1543
  i_aref = rb_intern("[]");
1477
1544
  i_leftshift = rb_intern("<<");
@@ -1483,4 +1550,8 @@ void Init_parser(void)
1483
1550
  binary_encindex = rb_ascii8bit_encindex();
1484
1551
  utf8_encindex = rb_utf8_encindex();
1485
1552
  enc_utf8 = rb_utf8_encoding();
1553
+
1554
+ #ifdef HAVE_SIMD
1555
+ simd_impl = find_simd_implementation();
1556
+ #endif
1486
1557
  }