oj 3.13.7 → 3.13.23

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +75 -0
  3. data/README.md +11 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +66 -112
  9. data/ext/oj/dump.c +147 -184
  10. data/ext/oj/dump.h +25 -8
  11. data/ext/oj/dump_compat.c +47 -89
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +72 -188
  14. data/ext/oj/dump_strict.c +19 -31
  15. data/ext/oj/encoder.c +43 -0
  16. data/ext/oj/extconf.rb +5 -4
  17. data/ext/oj/fast.c +36 -24
  18. data/ext/oj/intern.c +22 -12
  19. data/ext/oj/intern.h +1 -1
  20. data/ext/oj/mimic_json.c +74 -73
  21. data/ext/oj/object.c +54 -72
  22. data/ext/oj/odd.c +83 -63
  23. data/ext/oj/odd.h +13 -13
  24. data/ext/oj/oj.c +166 -175
  25. data/ext/oj/oj.h +25 -3
  26. data/ext/oj/parse.c +123 -79
  27. data/ext/oj/parse.h +2 -0
  28. data/ext/oj/parser.c +77 -21
  29. data/ext/oj/parser.h +12 -0
  30. data/ext/oj/rails.c +46 -70
  31. data/ext/oj/rails.h +1 -1
  32. data/ext/oj/reader.c +2 -0
  33. data/ext/oj/saj.c +11 -23
  34. data/ext/oj/saj2.c +333 -85
  35. data/ext/oj/saj2.h +23 -0
  36. data/ext/oj/sparse.c +4 -0
  37. data/ext/oj/stream_writer.c +3 -1
  38. data/ext/oj/strict.c +13 -13
  39. data/ext/oj/string_writer.c +12 -5
  40. data/ext/oj/usual.c +86 -131
  41. data/ext/oj/usual.h +68 -0
  42. data/ext/oj/val_stack.c +1 -1
  43. data/ext/oj/validate.c +21 -26
  44. data/ext/oj/wab.c +22 -27
  45. data/lib/oj/saj.rb +20 -6
  46. data/lib/oj/state.rb +1 -1
  47. data/lib/oj/version.rb +1 -1
  48. data/pages/Compatibility.md +1 -1
  49. data/pages/JsonGem.md +15 -0
  50. data/pages/Modes.md +6 -3
  51. data/pages/Options.md +6 -0
  52. data/pages/Rails.md +12 -0
  53. data/test/activesupport7/abstract_unit.rb +49 -0
  54. data/test/activesupport7/decoding_test.rb +125 -0
  55. data/test/activesupport7/encoding_test.rb +486 -0
  56. data/test/activesupport7/encoding_test_cases.rb +104 -0
  57. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  58. data/test/bar.rb +3 -8
  59. data/test/bug.rb +16 -0
  60. data/test/foo.rb +71 -7
  61. data/test/helper.rb +8 -2
  62. data/test/json_gem/json_generator_test.rb +5 -4
  63. data/test/json_gem/json_parser_test.rb +8 -1
  64. data/test/json_gem/test_helper.rb +7 -3
  65. data/test/perf_dump.rb +50 -0
  66. data/test/test_compat.rb +25 -0
  67. data/test/test_custom.rb +13 -2
  68. data/test/test_fast.rb +37 -7
  69. data/test/test_file.rb +23 -7
  70. data/test/test_gc.rb +11 -0
  71. data/test/test_object.rb +8 -10
  72. data/test/test_parser.rb +3 -19
  73. data/test/test_parser_debug.rb +27 -0
  74. data/test/test_parser_saj.rb +92 -2
  75. data/test/test_saj.rb +1 -1
  76. data/test/test_scp.rb +2 -4
  77. data/test/test_strict.rb +2 -0
  78. data/test/test_various.rb +32 -2
  79. data/test/test_wab.rb +2 -0
  80. data/test/tests.rb +9 -1
  81. data/test/tests_mimic.rb +9 -0
  82. data/test/tests_mimic_addition.rb +9 -0
  83. metadata +15 -115
data/ext/oj/parser.c CHANGED
@@ -11,8 +11,8 @@
11
11
  #define USE_THREAD_LIMIT 0
12
12
  // #define USE_THREAD_LIMIT 100000
13
13
  #define MAX_EXP 4932
14
- // max in the pow_map
15
- #define MAX_POW 400
14
+ // max in the pow_map which is the limit for double
15
+ #define MAX_POW 308
16
16
 
17
17
  #define MIN_SLEEP (1000000000LL / (double)CLOCKS_PER_SEC)
18
18
  // 9,223,372,036,854,775,807
@@ -385,7 +385,7 @@ static const byte hex_map[256] = "\
385
385
  ................................\
386
386
  ................................";
387
387
 
388
- static long double pow_map[401] = {
388
+ static long double pow_map[309] = {
389
389
  1.0L, 1.0e1L, 1.0e2L, 1.0e3L, 1.0e4L, 1.0e5L, 1.0e6L, 1.0e7L, 1.0e8L, 1.0e9L, 1.0e10L,
390
390
  1.0e11L, 1.0e12L, 1.0e13L, 1.0e14L, 1.0e15L, 1.0e16L, 1.0e17L, 1.0e18L, 1.0e19L, 1.0e20L, 1.0e21L,
391
391
  1.0e22L, 1.0e23L, 1.0e24L, 1.0e25L, 1.0e26L, 1.0e27L, 1.0e28L, 1.0e29L, 1.0e30L, 1.0e31L, 1.0e32L,
@@ -414,15 +414,7 @@ static long double pow_map[401] = {
414
414
  1.0e275L, 1.0e276L, 1.0e277L, 1.0e278L, 1.0e279L, 1.0e280L, 1.0e281L, 1.0e282L, 1.0e283L, 1.0e284L, 1.0e285L,
415
415
  1.0e286L, 1.0e287L, 1.0e288L, 1.0e289L, 1.0e290L, 1.0e291L, 1.0e292L, 1.0e293L, 1.0e294L, 1.0e295L, 1.0e296L,
416
416
  1.0e297L, 1.0e298L, 1.0e299L, 1.0e300L, 1.0e301L, 1.0e302L, 1.0e303L, 1.0e304L, 1.0e305L, 1.0e306L, 1.0e307L,
417
- 1.0e308L, 1.0e309L, 1.0e310L, 1.0e311L, 1.0e312L, 1.0e313L, 1.0e314L, 1.0e315L, 1.0e316L, 1.0e317L, 1.0e318L,
418
- 1.0e319L, 1.0e320L, 1.0e321L, 1.0e322L, 1.0e323L, 1.0e324L, 1.0e325L, 1.0e326L, 1.0e327L, 1.0e328L, 1.0e329L,
419
- 1.0e330L, 1.0e331L, 1.0e332L, 1.0e333L, 1.0e334L, 1.0e335L, 1.0e336L, 1.0e337L, 1.0e338L, 1.0e339L, 1.0e340L,
420
- 1.0e341L, 1.0e342L, 1.0e343L, 1.0e344L, 1.0e345L, 1.0e346L, 1.0e347L, 1.0e348L, 1.0e349L, 1.0e350L, 1.0e351L,
421
- 1.0e352L, 1.0e353L, 1.0e354L, 1.0e355L, 1.0e356L, 1.0e357L, 1.0e358L, 1.0e359L, 1.0e360L, 1.0e361L, 1.0e362L,
422
- 1.0e363L, 1.0e364L, 1.0e365L, 1.0e366L, 1.0e367L, 1.0e368L, 1.0e369L, 1.0e370L, 1.0e371L, 1.0e372L, 1.0e373L,
423
- 1.0e374L, 1.0e375L, 1.0e376L, 1.0e377L, 1.0e378L, 1.0e379L, 1.0e380L, 1.0e381L, 1.0e382L, 1.0e383L, 1.0e384L,
424
- 1.0e385L, 1.0e386L, 1.0e387L, 1.0e388L, 1.0e389L, 1.0e390L, 1.0e391L, 1.0e392L, 1.0e393L, 1.0e394L, 1.0e395L,
425
- 1.0e396L, 1.0e397L, 1.0e398L, 1.0e399L, 1.0e400L};
417
+ 1.0e308L};
426
418
 
427
419
  static VALUE parser_class;
428
420
 
@@ -541,6 +533,7 @@ static void calc_num(ojParser p) {
541
533
  // nothing to do
542
534
  break;
543
535
  }
536
+ p->type = OJ_NONE;
544
537
  }
545
538
 
546
539
  static void big_change(ojParser p) {
@@ -606,6 +599,8 @@ static void parse(ojParser p, const byte *json) {
606
599
  const byte *b = json;
607
600
  int i;
608
601
 
602
+ p->line = 1;
603
+ p->col = -1;
609
604
  #if DEBUG
610
605
  printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
611
606
  #endif
@@ -660,6 +655,7 @@ static void parse(ojParser p, const byte *json) {
660
655
  }
661
656
  buf_append_string(&p->buf, (const char *)start, b - start);
662
657
  if ('"' == *b) {
658
+ p->cur = b - json;
663
659
  p->funcs[p->stack[p->depth]].add_str(p);
664
660
  p->map = (0 == p->depth) ? value_map : after_map;
665
661
  break;
@@ -669,12 +665,14 @@ static void parse(ojParser p, const byte *json) {
669
665
  p->next_map = (0 == p->depth) ? value_map : after_map;
670
666
  break;
671
667
  case OPEN_OBJECT:
668
+ p->cur = b - json;
672
669
  p->funcs[p->stack[p->depth]].open_object(p);
673
670
  p->depth++;
674
671
  p->stack[p->depth] = OBJECT_FUN;
675
672
  p->map = key1_map;
676
673
  break;
677
674
  case NUM_CLOSE_OBJECT:
675
+ p->cur = b - json;
678
676
  calc_num(p);
679
677
  // flow through
680
678
  case CLOSE_OBJECT:
@@ -685,15 +683,18 @@ static void parse(ojParser p, const byte *json) {
685
683
  return;
686
684
  }
687
685
  p->depth--;
686
+ p->cur = b - json;
688
687
  p->funcs[p->stack[p->depth]].close_object(p);
689
688
  break;
690
689
  case OPEN_ARRAY:
690
+ p->cur = b - json;
691
691
  p->funcs[p->stack[p->depth]].open_array(p);
692
692
  p->depth++;
693
693
  p->stack[p->depth] = ARRAY_FUN;
694
694
  p->map = value_map;
695
695
  break;
696
696
  case NUM_CLOSE_ARRAY:
697
+ p->cur = b - json;
697
698
  calc_num(p);
698
699
  // flow through
699
700
  case CLOSE_ARRAY:
@@ -704,9 +705,11 @@ static void parse(ojParser p, const byte *json) {
704
705
  return;
705
706
  }
706
707
  p->depth--;
708
+ p->cur = b - json;
707
709
  p->funcs[p->stack[p->depth]].close_array(p);
708
710
  break;
709
711
  case NUM_COMMA:
712
+ p->cur = b - json;
710
713
  calc_num(p);
711
714
  if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
712
715
  p->map = key_map;
@@ -868,8 +871,14 @@ static void parse(ojParser p, const byte *json) {
868
871
  b--;
869
872
  p->map = big_exp_map;
870
873
  break;
871
- case NUM_SPC: calc_num(p); break;
872
- case NUM_NEWLINE: calc_num(p); b++;
874
+ case NUM_SPC:
875
+ p->cur = b - json;
876
+ calc_num(p);
877
+ break;
878
+ case NUM_NEWLINE:
879
+ p->cur = b - json;
880
+ calc_num(p);
881
+ b++;
873
882
  #ifdef SPACE_JUMP
874
883
  // for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
875
884
  for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
@@ -890,6 +899,7 @@ static void parse(ojParser p, const byte *json) {
890
899
  buf_append_string(&p->buf, (const char *)start, b - start);
891
900
  }
892
901
  if ('"' == *b) {
902
+ p->cur = b - json;
893
903
  p->funcs[p->stack[p->depth]].add_str(p);
894
904
  p->map = p->next_map;
895
905
  break;
@@ -898,6 +908,7 @@ static void parse(ojParser p, const byte *json) {
898
908
  break;
899
909
  case STR_SLASH: p->map = esc_map; break;
900
910
  case STR_QUOTE:
911
+ p->cur = b - json;
901
912
  p->funcs[p->stack[p->depth]].add_str(p);
902
913
  p->map = p->next_map;
903
914
  break;
@@ -975,6 +986,7 @@ static void parse(ojParser p, const byte *json) {
975
986
  case VAL_NULL:
976
987
  if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
977
988
  b += 3;
989
+ p->cur = b - json;
978
990
  p->funcs[p->stack[p->depth]].add_null(p);
979
991
  p->map = (0 == p->depth) ? value_map : after_map;
980
992
  break;
@@ -1000,6 +1012,7 @@ static void parse(ojParser p, const byte *json) {
1000
1012
  case VAL_TRUE:
1001
1013
  if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
1002
1014
  b += 3;
1015
+ p->cur = b - json;
1003
1016
  p->funcs[p->stack[p->depth]].add_true(p);
1004
1017
  p->map = (0 == p->depth) ? value_map : after_map;
1005
1018
  break;
@@ -1025,6 +1038,7 @@ static void parse(ojParser p, const byte *json) {
1025
1038
  case VAL_FALSE:
1026
1039
  if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
1027
1040
  b += 4;
1041
+ p->cur = b - json;
1028
1042
  p->funcs[p->stack[p->depth]].add_false(p);
1029
1043
  p->map = (0 == p->depth) ? value_map : after_map;
1030
1044
  break;
@@ -1058,6 +1072,7 @@ static void parse(ojParser p, const byte *json) {
1058
1072
  parse_error(p, "expected null");
1059
1073
  return;
1060
1074
  }
1075
+ p->cur = b - json;
1061
1076
  p->funcs[p->stack[p->depth]].add_null(p);
1062
1077
  p->map = (0 == p->depth) ? value_map : after_map;
1063
1078
  }
@@ -1069,6 +1084,7 @@ static void parse(ojParser p, const byte *json) {
1069
1084
  parse_error(p, "expected false");
1070
1085
  return;
1071
1086
  }
1087
+ p->cur = b - json;
1072
1088
  p->funcs[p->stack[p->depth]].add_false(p);
1073
1089
  p->map = (0 == p->depth) ? value_map : after_map;
1074
1090
  }
@@ -1080,6 +1096,7 @@ static void parse(ojParser p, const byte *json) {
1080
1096
  parse_error(p, "expected true");
1081
1097
  return;
1082
1098
  }
1099
+ p->cur = b - json;
1083
1100
  p->funcs[p->stack[p->depth]].add_true(p);
1084
1101
  p->map = (0 == p->depth) ? value_map : after_map;
1085
1102
  }
@@ -1097,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
1097
1114
  p->map = trail_map;
1098
1115
  }
1099
1116
  }
1117
+ if (0 < p->depth) {
1118
+ parse_error(p, "parse error, not closed");
1119
+ }
1100
1120
  if (0 == p->depth) {
1101
1121
  switch (p->map[256]) {
1102
1122
  case '0':
@@ -1107,7 +1127,10 @@ static void parse(ojParser p, const byte *json) {
1107
1127
  case 'D':
1108
1128
  case 'g':
1109
1129
  case 'B':
1110
- case 'Y': calc_num(p); break;
1130
+ case 'Y':
1131
+ p->cur = b - json;
1132
+ calc_num(p);
1133
+ break;
1111
1134
  }
1112
1135
  }
1113
1136
  return;
@@ -1122,7 +1145,9 @@ static void parser_free(void *ptr) {
1122
1145
  p = (ojParser)ptr;
1123
1146
  buf_cleanup(&p->key);
1124
1147
  buf_cleanup(&p->buf);
1125
- p->free(p);
1148
+ if (NULL != p->free) {
1149
+ p->free(p);
1150
+ }
1126
1151
  xfree(ptr);
1127
1152
  }
1128
1153
 
@@ -1133,7 +1158,9 @@ static void parser_mark(void *ptr) {
1133
1158
  if (0 != p->reader) {
1134
1159
  rb_gc_mark(p->reader);
1135
1160
  }
1136
- p->mark(p);
1161
+ if (NULL != p->mark) {
1162
+ p->mark(p);
1163
+ }
1137
1164
  }
1138
1165
  }
1139
1166
 
@@ -1190,7 +1217,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1190
1217
  p->map = value_map;
1191
1218
 
1192
1219
  if (argc < 1) {
1193
- oj_set_parser_validator(p);
1220
+ oj_set_parser_validator(p);
1194
1221
  } else {
1195
1222
  VALUE mode = argv[0];
1196
1223
 
@@ -1231,6 +1258,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1231
1258
  return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1232
1259
  }
1233
1260
 
1261
+ // Create a new parser without setting the delegate. The parser is
1262
+ // wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
1263
+ // from this function. A delegate must be added before the parser can be
1264
+ // used. Optionally oj_parser_set_options can be called if the options are not
1265
+ // set directly.
1266
+ VALUE oj_parser_new() {
1267
+ ojParser p = ALLOC(struct _ojParser);
1268
+
1269
+ #if HAVE_RB_EXT_RACTOR_SAFE
1270
+ // This doesn't seem to do anything.
1271
+ rb_ext_ractor_safe(true);
1272
+ #endif
1273
+ memset(p, 0, sizeof(struct _ojParser));
1274
+ buf_init(&p->key);
1275
+ buf_init(&p->buf);
1276
+ p->map = value_map;
1277
+
1278
+ return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
1279
+ }
1280
+
1281
+ // Set set the options from a hash (ropts).
1282
+ void oj_parser_set_option(ojParser p, VALUE ropts) {
1283
+ Check_Type(ropts, T_HASH);
1284
+ rb_hash_foreach(ropts, opt_cb, (VALUE)p);
1285
+ }
1286
+
1234
1287
  /* Document-method: method_missing(value)
1235
1288
  * call-seq: method_missing(value)
1236
1289
  *
@@ -1284,7 +1337,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
1284
1337
  */
1285
1338
  static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
1286
1339
  ojParser p = (ojParser)DATA_PTR(self);
1287
- const char * key = NULL;
1340
+ const char *key = NULL;
1288
1341
  volatile VALUE rkey = *argv;
1289
1342
  volatile VALUE rv = Qnil;
1290
1343
 
@@ -1464,7 +1517,7 @@ static VALUE saj_parser = Qundef;
1464
1517
  /* Document-method: saj
1465
1518
  * call-seq: saj
1466
1519
  *
1467
- * Returns the default saj parser. Note the default SAJ parser can not be used
1520
+ * Returns the default SAJ parser. Note the default SAJ parser can not be used
1468
1521
  * concurrently in more than one thread.
1469
1522
  */
1470
1523
  static VALUE parser_saj(VALUE self) {
@@ -1515,8 +1568,11 @@ static VALUE parser_validate(VALUE self) {
1515
1568
  * isolates options to just the parser so that other parts of the code are not
1516
1569
  * forced to use the same options.
1517
1570
  */
1518
- void oj_parser_init() {
1571
+ void oj_parser_init(void) {
1519
1572
  parser_class = rb_define_class_under(Oj, "Parser", rb_cObject);
1573
+ rb_gc_register_address(&parser_class);
1574
+ rb_undef_alloc_func(parser_class);
1575
+
1520
1576
  rb_define_module_function(parser_class, "new", parser_new, -1);
1521
1577
  rb_define_method(parser_class, "parse", parser_parse, 1);
1522
1578
  rb_define_method(parser_class, "load", parser_load, 1);
data/ext/oj/parser.h CHANGED
@@ -80,6 +80,7 @@ typedef struct _ojParser {
80
80
 
81
81
  char token[8];
82
82
  long line;
83
+ long cur; // only set before call to a function
83
84
  long col;
84
85
  int ri;
85
86
  uint32_t ucode;
@@ -87,4 +88,15 @@ typedef struct _ojParser {
87
88
  bool just_one;
88
89
  } * ojParser;
89
90
 
91
+ // Create a new parser without setting the delegate. The parser is
92
+ // wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
93
+ // from this function. A delegate must be added before the parser can be
94
+ // used. Optionally oj_parser_set_options can be called if the options are not
95
+ // set directly.
96
+ extern VALUE oj_parser_new();
97
+
98
+ // Set set the options from a hash (ropts).
99
+ extern void oj_parser_set_option(ojParser p, VALUE ropts);
100
+
101
+
90
102
  #endif /* OJ_PARSER_H */
data/ext/oj/rails.c CHANGED
@@ -157,7 +157,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
157
157
  assure_size(out, 2);
158
158
  *out->cur++ = '{';
159
159
  for (i = 0; i < cnt; i++) {
160
- volatile VALUE s = rb_sym2str(rb_ary_entry(ma, i));
160
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
161
161
 
162
162
  name = RSTRING_PTR(s);
163
163
  len = (int)RSTRING_LEN(s);
@@ -167,17 +167,14 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
167
167
  }
168
168
  fill_indent(out, d3);
169
169
  *out->cur++ = '"';
170
- memcpy(out->cur, name, len);
171
- out->cur += len;
170
+ APPEND_CHARS(out->cur, name, len);
172
171
  *out->cur++ = '"';
173
172
  if (0 < out->opts->dump_opts.before_size) {
174
- strcpy(out->cur, out->opts->dump_opts.before_sep);
175
- out->cur += out->opts->dump_opts.before_size;
173
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
176
174
  }
177
175
  *out->cur++ = ':';
178
176
  if (0 < out->opts->dump_opts.after_size) {
179
- strcpy(out->cur, out->opts->dump_opts.after_sep);
180
- out->cur += out->opts->dump_opts.after_size;
177
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
181
178
  }
182
179
  #ifdef RSTRUCT_LEN
183
180
  v = RSTRUCT_GET(obj, i);
@@ -323,20 +320,15 @@ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
323
320
  long long sec;
324
321
  long long nsec;
325
322
 
326
- #ifdef HAVE_RB_TIME_TIMESPEC
327
323
  if (16 <= sizeof(struct timespec)) {
328
324
  struct timespec ts = rb_time_timespec(obj);
329
325
 
330
326
  sec = (long long)ts.tv_sec;
331
327
  nsec = ts.tv_nsec;
332
328
  } else {
333
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
334
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
329
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
330
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
335
331
  }
336
- #else
337
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
338
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
339
- #endif
340
332
  dump_sec_nano(obj, sec, nsec, out);
341
333
  }
342
334
 
@@ -345,9 +337,9 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
345
337
  long long nsec = 0;
346
338
 
347
339
  if (rb_respond_to(obj, oj_tv_nsec_id)) {
348
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
340
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
349
341
  } else if (rb_respond_to(obj, oj_tv_usec_id)) {
350
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
342
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
351
343
  }
352
344
  dump_sec_nano(obj, sec, nsec, out);
353
345
  }
@@ -383,7 +375,7 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
383
375
  *ccnt = cnt;
384
376
  cols = ALLOC_N(struct _strLen, cnt);
385
377
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
386
- v = rb_ary_entry(rcols, i);
378
+ v = RARRAY_AREF(rcols, i);
387
379
  if (T_STRING != rb_type(v)) {
388
380
  v = rb_funcall(v, oj_to_s_id, 0);
389
381
  }
@@ -405,14 +397,12 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
405
397
  assure_size(out, size);
406
398
  if (out->opts->dump_opts.use) {
407
399
  if (0 < out->opts->dump_opts.array_size) {
408
- strcpy(out->cur, out->opts->dump_opts.array_nl);
409
- out->cur += out->opts->dump_opts.array_size;
400
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
410
401
  }
411
402
  if (0 < out->opts->dump_opts.indent_size) {
412
403
  int i;
413
404
  for (i = d2; 0 < i; i--) {
414
- strcpy(out->cur, out->opts->dump_opts.indent_str);
415
- out->cur += out->opts->dump_opts.indent_size;
405
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
416
406
  }
417
407
  }
418
408
  } else {
@@ -420,7 +410,7 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
420
410
  }
421
411
  oj_dump_cstr(cols->str, cols->len, 0, 0, out);
422
412
  *out->cur++ = ':';
423
- dump_rails_val(rb_ary_entry(row, i), depth, out, true);
413
+ dump_rails_val(RARRAY_AREF(row, i), depth, out, true);
424
414
  if (i < ccnt - 1) {
425
415
  *out->cur++ = ',';
426
416
  }
@@ -429,15 +419,13 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
429
419
  assure_size(out, size);
430
420
  if (out->opts->dump_opts.use) {
431
421
  if (0 < out->opts->dump_opts.array_size) {
432
- strcpy(out->cur, out->opts->dump_opts.array_nl);
433
- out->cur += out->opts->dump_opts.array_size;
422
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
434
423
  }
435
424
  if (0 < out->opts->dump_opts.indent_size) {
436
425
  int i;
437
426
 
438
427
  for (i = depth; 0 < i; i--) {
439
- strcpy(out->cur, out->opts->dump_opts.indent_str);
440
- out->cur += out->opts->dump_opts.indent_size;
428
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
441
429
  }
442
430
  }
443
431
  } else {
@@ -477,20 +465,18 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
477
465
  assure_size(out, size);
478
466
  if (out->opts->dump_opts.use) {
479
467
  if (0 < out->opts->dump_opts.array_size) {
480
- strcpy(out->cur, out->opts->dump_opts.array_nl);
481
- out->cur += out->opts->dump_opts.array_size;
468
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
482
469
  }
483
470
  if (0 < out->opts->dump_opts.indent_size) {
484
471
  int i;
485
472
  for (i = d2; 0 < i; i--) {
486
- strcpy(out->cur, out->opts->dump_opts.indent_str);
487
- out->cur += out->opts->dump_opts.indent_size;
473
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
488
474
  }
489
475
  }
490
476
  } else {
491
477
  fill_indent(out, d2);
492
478
  }
493
- dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out);
479
+ dump_row(RARRAY_AREF(rows, i), cols, ccnt, d2, out);
494
480
  if (i < rcnt - 1) {
495
481
  *out->cur++ = ',';
496
482
  }
@@ -500,15 +486,13 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
500
486
  assure_size(out, size);
501
487
  if (out->opts->dump_opts.use) {
502
488
  if (0 < out->opts->dump_opts.array_size) {
503
- strcpy(out->cur, out->opts->dump_opts.array_nl);
504
- out->cur += out->opts->dump_opts.array_size;
489
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
505
490
  }
506
491
  if (0 < out->opts->dump_opts.indent_size) {
507
492
  int i;
508
493
 
509
494
  for (i = depth; 0 < i; i--) {
510
- strcpy(out->cur, out->opts->dump_opts.indent_str);
511
- out->cur += out->opts->dump_opts.indent_size;
495
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
512
496
  }
513
497
  }
514
498
  } else {
@@ -533,7 +517,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
533
517
  static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
534
518
  volatile VALUE ja;
535
519
 
536
- if (Yes == out->opts->trace) {
520
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
537
521
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
538
522
  }
539
523
  // Some classes elect to not take an options argument so check the arity
@@ -543,7 +527,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
543
527
  } else {
544
528
  ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
545
529
  }
546
- if (Yes == out->opts->trace) {
530
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
547
531
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
548
532
  }
549
533
 
@@ -908,7 +892,6 @@ static VALUE protect_dump(VALUE ov) {
908
892
  }
909
893
 
910
894
  static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
911
- char buf[4096];
912
895
  struct _out out;
913
896
  struct _options copts = *opts;
914
897
  volatile VALUE rstr = Qnil;
@@ -925,9 +908,9 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
925
908
  } else {
926
909
  copts.escape_mode = RailsEsc;
927
910
  }
928
- out.buf = buf;
929
- out.end = buf + sizeof(buf) - 10;
930
- out.allocated = false;
911
+
912
+ oj_out_init(&out);
913
+
931
914
  out.omit_nil = copts.dump_opts.omit_nil;
932
915
  out.caller = 0;
933
916
  out.cur = out.buf;
@@ -963,9 +946,9 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
963
946
  if (Yes == copts.circular) {
964
947
  oj_cache8_delete(out.circ_cache);
965
948
  }
966
- if (out.allocated) {
967
- xfree(out.buf);
968
- }
949
+
950
+ oj_out_free(&out);
951
+
969
952
  if (0 != line) {
970
953
  rb_jump_tag(line);
971
954
  }
@@ -1175,12 +1158,15 @@ oj_optimize_rails(VALUE self) {
1175
1158
  *
1176
1159
  * The Oj ActiveSupport compliant encoder.
1177
1160
  */
1178
- void oj_mimic_rails_init() {
1161
+ void oj_mimic_rails_init(void) {
1179
1162
  VALUE rails = rb_define_module_under(Oj, "Rails");
1180
1163
 
1181
1164
  rb_define_module_function(rails, "encode", rails_encode, -1);
1182
1165
 
1183
1166
  encoder_class = rb_define_class_under(rails, "Encoder", rb_cObject);
1167
+ rb_gc_register_address(&encoder_class);
1168
+ rb_undef_alloc_func(encoder_class);
1169
+
1184
1170
  rb_define_module_function(encoder_class, "new", encoder_new, -1);
1185
1171
  rb_define_module_function(rails, "optimize", rails_optimize, -1);
1186
1172
  rb_define_module_function(rails, "deoptimize", rails_deoptimize, -1);
@@ -1263,25 +1249,23 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1263
1249
  } else {
1264
1250
  size = d2 * out->indent + 2;
1265
1251
  }
1252
+ assure_size(out, size * cnt);
1266
1253
  cnt--;
1267
1254
  for (i = 0; i <= cnt; i++) {
1268
- assure_size(out, size);
1269
1255
  if (out->opts->dump_opts.use) {
1270
1256
  if (0 < out->opts->dump_opts.array_size) {
1271
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1272
- out->cur += out->opts->dump_opts.array_size;
1257
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1273
1258
  }
1274
1259
  if (0 < out->opts->dump_opts.indent_size) {
1275
1260
  int i;
1276
1261
  for (i = d2; 0 < i; i--) {
1277
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1278
- out->cur += out->opts->dump_opts.indent_size;
1262
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1279
1263
  }
1280
1264
  }
1281
1265
  } else {
1282
1266
  fill_indent(out, d2);
1283
1267
  }
1284
- dump_rails_val(rb_ary_entry(a, i), d2, out, true);
1268
+ dump_rails_val(RARRAY_AREF(a, i), d2, out, true);
1285
1269
  if (i < cnt) {
1286
1270
  *out->cur++ = ',';
1287
1271
  }
@@ -1290,15 +1274,13 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1290
1274
  assure_size(out, size);
1291
1275
  if (out->opts->dump_opts.use) {
1292
1276
  if (0 < out->opts->dump_opts.array_size) {
1293
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1294
- out->cur += out->opts->dump_opts.array_size;
1277
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1295
1278
  }
1296
1279
  if (0 < out->opts->dump_opts.indent_size) {
1297
1280
  int i;
1298
1281
 
1299
1282
  for (i = depth; 0 < i; i--) {
1300
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1301
- out->cur += out->opts->dump_opts.indent_size;
1283
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1302
1284
  }
1303
1285
  }
1304
1286
  } else {
@@ -1336,14 +1318,12 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1336
1318
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1337
1319
  assure_size(out, size);
1338
1320
  if (0 < out->opts->dump_opts.hash_size) {
1339
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1340
- out->cur += out->opts->dump_opts.hash_size;
1321
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1341
1322
  }
1342
1323
  if (0 < out->opts->dump_opts.indent_size) {
1343
1324
  int i;
1344
1325
  for (i = depth; 0 < i; i--) {
1345
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1346
- out->cur += out->opts->dump_opts.indent_size;
1326
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1347
1327
  }
1348
1328
  }
1349
1329
  if (rtype == T_STRING) {
@@ -1354,13 +1334,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1354
1334
  size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1355
1335
  assure_size(out, size);
1356
1336
  if (0 < out->opts->dump_opts.before_size) {
1357
- strcpy(out->cur, out->opts->dump_opts.before_sep);
1358
- out->cur += out->opts->dump_opts.before_size;
1337
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
1359
1338
  }
1360
1339
  *out->cur++ = ':';
1361
1340
  if (0 < out->opts->dump_opts.after_size) {
1362
- strcpy(out->cur, out->opts->dump_opts.after_sep);
1363
- out->cur += out->opts->dump_opts.after_size;
1341
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
1364
1342
  }
1365
1343
  }
1366
1344
  dump_rails_val(value, depth, out, true);
@@ -1403,15 +1381,13 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1403
1381
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1404
1382
  assure_size(out, size);
1405
1383
  if (0 < out->opts->dump_opts.hash_size) {
1406
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1407
- out->cur += out->opts->dump_opts.hash_size;
1384
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1408
1385
  }
1409
1386
  if (0 < out->opts->dump_opts.indent_size) {
1410
1387
  int i;
1411
1388
 
1412
1389
  for (i = depth; 0 < i; i--) {
1413
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1414
- out->cur += out->opts->dump_opts.indent_size;
1390
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1415
1391
  }
1416
1392
  }
1417
1393
  }
@@ -1488,7 +1464,7 @@ static DumpFunc rails_funcs[] = {
1488
1464
  static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1489
1465
  int type = rb_type(obj);
1490
1466
 
1491
- if (Yes == out->opts->trace) {
1467
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1492
1468
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1493
1469
  }
1494
1470
  if (MAX_DEPTH < depth) {
@@ -1499,14 +1475,14 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1499
1475
 
1500
1476
  if (NULL != f) {
1501
1477
  f(obj, depth, out, as_ok);
1502
- if (Yes == out->opts->trace) {
1478
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1503
1479
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1504
1480
  }
1505
1481
  return;
1506
1482
  }
1507
1483
  }
1508
1484
  oj_dump_nil(Qnil, depth, out, false);
1509
- if (Yes == out->opts->trace) {
1485
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1510
1486
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1511
1487
  }
1512
1488
  }
data/ext/oj/rails.h CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  #include "dump.h"
8
8
 
9
- extern void oj_mimic_rails_init();
9
+ extern void oj_mimic_rails_init(void);
10
10
  extern ROpt oj_rails_get_opt(ROptTable rot, VALUE clas);
11
11
 
12
12
  extern bool oj_rails_hash_opt;