json 2.12.0 → 2.13.2

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