oj 3.13.11 → 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 (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +2 -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 +62 -108
  9. data/ext/oj/dump.c +85 -97
  10. data/ext/oj/dump.h +12 -8
  11. data/ext/oj/dump_compat.c +46 -88
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +33 -156
  14. data/ext/oj/dump_strict.c +17 -29
  15. data/ext/oj/extconf.rb +5 -4
  16. data/ext/oj/fast.c +24 -22
  17. data/ext/oj/intern.c +15 -11
  18. data/ext/oj/intern.h +1 -1
  19. data/ext/oj/mimic_json.c +44 -32
  20. data/ext/oj/object.c +42 -41
  21. data/ext/oj/odd.c +83 -63
  22. data/ext/oj/odd.h +13 -13
  23. data/ext/oj/oj.c +57 -22
  24. data/ext/oj/oj.h +24 -3
  25. data/ext/oj/parse.c +114 -78
  26. data/ext/oj/parse.h +2 -0
  27. data/ext/oj/parser.c +77 -21
  28. data/ext/oj/parser.h +12 -0
  29. data/ext/oj/rails.c +41 -65
  30. data/ext/oj/rails.h +1 -1
  31. data/ext/oj/reader.c +2 -0
  32. data/ext/oj/saj.c +11 -23
  33. data/ext/oj/saj2.c +333 -85
  34. data/ext/oj/saj2.h +23 -0
  35. data/ext/oj/sparse.c +4 -0
  36. data/ext/oj/stream_writer.c +3 -1
  37. data/ext/oj/strict.c +13 -13
  38. data/ext/oj/string_writer.c +12 -5
  39. data/ext/oj/usual.c +82 -129
  40. data/ext/oj/usual.h +68 -0
  41. data/ext/oj/val_stack.c +1 -1
  42. data/ext/oj/validate.c +21 -26
  43. data/ext/oj/wab.c +21 -26
  44. data/lib/oj/saj.rb +20 -6
  45. data/lib/oj/state.rb +1 -1
  46. data/lib/oj/version.rb +1 -1
  47. data/pages/Compatibility.md +1 -1
  48. data/pages/Options.md +6 -0
  49. data/test/activesupport7/abstract_unit.rb +49 -0
  50. data/test/activesupport7/decoding_test.rb +125 -0
  51. data/test/activesupport7/encoding_test.rb +486 -0
  52. data/test/activesupport7/encoding_test_cases.rb +104 -0
  53. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  54. data/test/bar.rb +3 -8
  55. data/test/foo.rb +3 -3
  56. data/test/helper.rb +8 -2
  57. data/test/json_gem/json_generator_test.rb +5 -4
  58. data/test/json_gem/json_parser_test.rb +8 -1
  59. data/test/json_gem/test_helper.rb +7 -3
  60. data/test/perf_dump.rb +50 -0
  61. data/test/test_compat.rb +25 -0
  62. data/test/test_custom.rb +13 -2
  63. data/test/test_file.rb +23 -7
  64. data/test/test_gc.rb +11 -0
  65. data/test/test_object.rb +8 -10
  66. data/test/test_parser.rb +3 -19
  67. data/test/test_parser_debug.rb +27 -0
  68. data/test/test_parser_saj.rb +92 -2
  69. data/test/test_scp.rb +2 -4
  70. data/test/test_strict.rb +2 -0
  71. data/test/test_various.rb +8 -3
  72. data/test/test_wab.rb +2 -0
  73. data/test/tests.rb +9 -0
  74. data/test/tests_mimic.rb +9 -0
  75. data/test/tests_mimic_addition.rb +9 -0
  76. metadata +13 -116
data/ext/oj/dump_object.c CHANGED
@@ -24,12 +24,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
24
24
 
25
25
  if (rb_cTime == clas) {
26
26
  assure_size(out, 6);
27
- *out->cur++ = '{';
28
- *out->cur++ = '"';
29
- *out->cur++ = '^';
30
- *out->cur++ = 't';
31
- *out->cur++ = '"';
32
- *out->cur++ = ':';
27
+ APPEND_CHARS(out->cur, "{\"^t\":", 6);
33
28
  dump_time(obj, out);
34
29
  *out->cur++ = '}';
35
30
  *out->cur = '\0';
@@ -91,12 +86,7 @@ static void dump_class(VALUE obj, int depth, Out out, bool as_ok) {
91
86
  size_t len = strlen(s);
92
87
 
93
88
  assure_size(out, 6);
94
- *out->cur++ = '{';
95
- *out->cur++ = '"';
96
- *out->cur++ = '^';
97
- *out->cur++ = 'c';
98
- *out->cur++ = '"';
99
- *out->cur++ = ':';
89
+ APPEND_CHARS(out->cur, "{\"^c\":", 6);
100
90
  oj_dump_cstr(s, len, 0, 0, out);
101
91
  *out->cur++ = '}';
102
92
  *out->cur = '\0';
@@ -120,9 +110,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
120
110
  if (0 < id) {
121
111
  assure_size(out, d2 * out->indent + 16);
122
112
  fill_indent(out, d2);
123
- *out->cur++ = '"';
124
- *out->cur++ = '^';
125
- *out->cur++ = 'i';
113
+ APPEND_CHARS(out->cur, "\"^i", 3);
126
114
  dump_ulong(id, out);
127
115
  *out->cur++ = '"';
128
116
  }
@@ -139,19 +127,17 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
139
127
  } else {
140
128
  size = d2 * out->indent + 2;
141
129
  }
130
+ assure_size(out, size * cnt);
142
131
  cnt--;
143
132
  for (i = 0; i <= cnt; i++) {
144
- assure_size(out, size);
145
133
  if (out->opts->dump_opts.use) {
146
134
  if (0 < out->opts->dump_opts.array_size) {
147
- strcpy(out->cur, out->opts->dump_opts.array_nl);
148
- out->cur += out->opts->dump_opts.array_size;
135
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
149
136
  }
150
137
  if (0 < out->opts->dump_opts.indent_size) {
151
138
  int i;
152
139
  for (i = d2; 0 < i; i--) {
153
- strcpy(out->cur, out->opts->dump_opts.indent_str);
154
- out->cur += out->opts->dump_opts.indent_size;
140
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
155
141
  }
156
142
  }
157
143
  } else {
@@ -168,15 +154,13 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
168
154
  // printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
169
155
  // out->opts->dump_opts->indent);
170
156
  if (0 < out->opts->dump_opts.array_size) {
171
- strcpy(out->cur, out->opts->dump_opts.array_nl);
172
- out->cur += out->opts->dump_opts.array_size;
157
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
173
158
  }
174
159
  if (0 < out->opts->dump_opts.indent_size) {
175
160
  int i;
176
161
 
177
162
  for (i = depth; 0 < i; i--) {
178
- strcpy(out->cur, out->opts->dump_opts.indent_str);
179
- out->cur += out->opts->dump_opts.indent_size;
163
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
180
164
  }
181
165
  }
182
166
  } else {
@@ -248,9 +232,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
248
232
  uint8_t b;
249
233
 
250
234
  assure_size(out, s2 + 15);
251
- *out->cur++ = '"';
252
- *out->cur++ = '^';
253
- *out->cur++ = '#';
235
+ APPEND_CHARS(out->cur, "\"^#", 3);
254
236
  out->hash_cnt++;
255
237
  for (i = 28; 0 <= i; i -= 4) {
256
238
  b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
@@ -261,9 +243,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
261
243
  *out->cur++ = hex_chars[b];
262
244
  }
263
245
  }
264
- *out->cur++ = '"';
265
- *out->cur++ = ':';
266
- *out->cur++ = '[';
246
+ APPEND_CHARS(out->cur, "\":[", 3);
267
247
  fill_indent(out, d2);
268
248
  oj_dump_obj_val(key, d2, out);
269
249
  assure_size(out, s2);
@@ -293,8 +273,7 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
293
273
  size = depth * out->indent + 2;
294
274
  assure_size(out, 2);
295
275
  if (0 == cnt) {
296
- *out->cur++ = '{';
297
- *out->cur++ = '}';
276
+ APPEND_CHARS(out->cur, "{}", 2);
298
277
  } else {
299
278
  long id = oj_check_circular(obj, out);
300
279
 
@@ -305,11 +284,7 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
305
284
  if (0 < id) {
306
285
  assure_size(out, size + 16);
307
286
  fill_indent(out, depth + 1);
308
- *out->cur++ = '"';
309
- *out->cur++ = '^';
310
- *out->cur++ = 'i';
311
- *out->cur++ = '"';
312
- *out->cur++ = ':';
287
+ APPEND_CHARS(out->cur, "\"^i\":", 5);
313
288
  dump_ulong(id, out);
314
289
  *out->cur++ = ',';
315
290
  }
@@ -325,15 +300,13 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
325
300
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
326
301
  assure_size(out, size);
327
302
  if (0 < out->opts->dump_opts.hash_size) {
328
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
329
- out->cur += out->opts->dump_opts.hash_size;
303
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
330
304
  }
331
305
  if (0 < out->opts->dump_opts.indent_size) {
332
306
  int i;
333
307
 
334
308
  for (i = depth; 0 < i; i--) {
335
- strcpy(out->cur, out->opts->dump_opts.indent_str);
336
- out->cur += out->opts->dump_opts.indent_size;
309
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
337
310
  }
338
311
  }
339
312
  }
@@ -342,7 +315,6 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
342
315
  *out->cur = '\0';
343
316
  }
344
317
 
345
- #ifdef HAVE_RB_IVAR_FOREACH
346
318
  static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
347
319
  Out out = (Out)ov;
348
320
  int depth = out->depth;
@@ -385,7 +357,6 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
385
357
 
386
358
  return ST_CONTINUE;
387
359
  }
388
- #endif
389
360
 
390
361
  static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
391
362
  dump_hash_class(obj, rb_obj_class(obj), depth, out);
@@ -408,11 +379,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
408
379
  size = d2 * out->indent + clen + 10;
409
380
  assure_size(out, size);
410
381
  fill_indent(out, d2);
411
- *out->cur++ = '"';
412
- *out->cur++ = '^';
413
- *out->cur++ = 'O';
414
- *out->cur++ = '"';
415
- *out->cur++ = ':';
382
+ APPEND_CHARS(out->cur, "\"^O\":", 5);
416
383
  oj_dump_cstr(class_name, clen, 0, 0, out);
417
384
  *out->cur++ = ',';
418
385
  }
@@ -430,12 +397,9 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
430
397
  assure_size(out, size);
431
398
  fill_indent(out, d2);
432
399
  *out->cur++ = '"';
433
- memcpy(out->cur, name, nlen);
434
- out->cur += nlen;
435
- *out->cur++ = '"';
436
- *out->cur++ = ':';
437
- memcpy(out->cur, s, len);
438
- out->cur += len;
400
+ APPEND_CHARS(out->cur, name, nlen);
401
+ APPEND_CHARS(out->cur, "\":", 2);
402
+ APPEND_CHARS(out->cur, s, len);
439
403
  *out->cur = '\0';
440
404
  }
441
405
  } else {
@@ -446,7 +410,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
446
410
  assure_size(out, size);
447
411
  name = rb_id2name(*idp);
448
412
  nlen = strlen(name);
449
- if (0 != *fp) {
413
+ if (NULL != *fp) {
450
414
  v = (*fp)(obj);
451
415
  } else if (0 == strchr(name, '.')) {
452
416
  v = rb_funcall(obj, *idp, 0);
@@ -509,22 +473,14 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
509
473
 
510
474
  assure_size(out, d2 * out->indent + clen + 10);
511
475
  fill_indent(out, d2);
512
- *out->cur++ = '"';
513
- *out->cur++ = '^';
514
- *out->cur++ = 'o';
515
- *out->cur++ = '"';
516
- *out->cur++ = ':';
476
+ APPEND_CHARS(out->cur, "\"^o\":", 5);
517
477
  oj_dump_cstr(class_name, clen, 0, 0, out);
518
478
  }
519
479
  if (0 < id) {
520
480
  assure_size(out, d2 * out->indent + 16);
521
481
  *out->cur++ = ',';
522
482
  fill_indent(out, d2);
523
- *out->cur++ = '"';
524
- *out->cur++ = '^';
525
- *out->cur++ = 'i';
526
- *out->cur++ = '"';
527
- *out->cur++ = ':';
483
+ APPEND_CHARS(out->cur, "\"^i\":", 5);
528
484
  dump_ulong(id, out);
529
485
  }
530
486
  switch (type) {
@@ -532,57 +488,28 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
532
488
  assure_size(out, d2 * out->indent + 14);
533
489
  *out->cur++ = ',';
534
490
  fill_indent(out, d2);
535
- *out->cur++ = '"';
536
- *out->cur++ = 's';
537
- *out->cur++ = 'e';
538
- *out->cur++ = 'l';
539
- *out->cur++ = 'f';
540
- *out->cur++ = '"';
541
- *out->cur++ = ':';
491
+ APPEND_CHARS(out->cur, "\"self\":", 7);
542
492
  oj_dump_cstr(RSTRING_PTR(obj), (int)RSTRING_LEN(obj), 0, 0, out);
543
493
  break;
544
494
  case T_ARRAY:
545
495
  assure_size(out, d2 * out->indent + 14);
546
496
  *out->cur++ = ',';
547
497
  fill_indent(out, d2);
548
- *out->cur++ = '"';
549
- *out->cur++ = 's';
550
- *out->cur++ = 'e';
551
- *out->cur++ = 'l';
552
- *out->cur++ = 'f';
553
- *out->cur++ = '"';
554
- *out->cur++ = ':';
498
+ APPEND_CHARS(out->cur, "\"self\":", 7);
555
499
  dump_array_class(obj, Qundef, depth + 1, out);
556
500
  break;
557
501
  case T_HASH:
558
502
  assure_size(out, d2 * out->indent + 14);
559
503
  *out->cur++ = ',';
560
504
  fill_indent(out, d2);
561
- *out->cur++ = '"';
562
- *out->cur++ = 's';
563
- *out->cur++ = 'e';
564
- *out->cur++ = 'l';
565
- *out->cur++ = 'f';
566
- *out->cur++ = '"';
567
- *out->cur++ = ':';
505
+ APPEND_CHARS(out->cur, "\"self\":", 7);
568
506
  dump_hash_class(obj, Qundef, depth + 1, out);
569
507
  break;
570
508
  default: break;
571
509
  }
572
510
  {
573
- int cnt;
574
- #ifdef HAVE_RB_IVAR_COUNT
575
- cnt = (int)rb_ivar_count(obj);
576
- #else
577
- volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
578
- VALUE * np = RARRAY_PTR(vars);
579
- ID vid;
580
- const char * attr;
581
- int i;
582
- int first = 1;
583
-
584
- cnt = (int)RARRAY_LEN(vars);
585
- #endif
511
+ int cnt = (int)rb_ivar_count(obj);
512
+
586
513
  if (Qundef != clas && 0 < cnt) {
587
514
  *out->cur++ = ',';
588
515
  }
@@ -595,52 +522,10 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
595
522
  }
596
523
  }
597
524
  out->depth = depth + 1;
598
- #ifdef HAVE_RB_IVAR_FOREACH
599
525
  rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
600
526
  if (',' == *(out->cur - 1)) {
601
527
  out->cur--; // backup to overwrite last comma
602
528
  }
603
- #else
604
- size = d2 * out->indent + 1;
605
- for (i = cnt; 0 < i; i--, np++) {
606
- VALUE value;
607
-
608
- vid = rb_to_id(*np);
609
- attr = rb_id2name(vid);
610
- if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
611
- continue;
612
- }
613
- value = rb_ivar_get(obj, vid);
614
-
615
- if (dump_ignore(out->opts, value)) {
616
- continue;
617
- }
618
- if (out->omit_nil && Qnil == value) {
619
- continue;
620
- }
621
- if (first) {
622
- first = 0;
623
- } else {
624
- *out->cur++ = ',';
625
- }
626
- assure_size(out, size);
627
- fill_indent(out, d2);
628
- if ('@' == *attr) {
629
- attr++;
630
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
631
- } else {
632
- char buf[32];
633
-
634
- *buf = '~';
635
- strncpy(buf + 1, attr, sizeof(buf) - 2);
636
- buf[sizeof(buf) - 1] = '\0';
637
- oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
638
- }
639
- *out->cur++ = ':';
640
- oj_dump_obj_val(value, d2, out);
641
- assure_size(out, 2);
642
- }
643
- #endif
644
529
  if (rb_obj_is_kind_of(obj, rb_eException)) {
645
530
  volatile VALUE rv;
646
531
 
@@ -688,12 +573,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
688
573
  assure_size(out, size);
689
574
  *out->cur++ = '{';
690
575
  fill_indent(out, d2);
691
- *out->cur++ = '"';
692
- *out->cur++ = '^';
693
- *out->cur++ = 'u';
694
- *out->cur++ = '"';
695
- *out->cur++ = ':';
696
- *out->cur++ = '[';
576
+ APPEND_CHARS(out->cur, "\"^u\":[", 6);
697
577
  if ('#' == *class_name) {
698
578
  VALUE ma = rb_struct_s_members(clas);
699
579
  const char *name;
@@ -711,16 +591,14 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
711
591
  *out->cur++ = ',';
712
592
  }
713
593
  *out->cur++ = '"';
714
- memcpy(out->cur, name, len);
715
- out->cur += len;
594
+ APPEND_CHARS(out->cur, name, len);
716
595
  *out->cur++ = '"';
717
596
  }
718
597
  *out->cur++ = ']';
719
598
  } else {
720
599
  fill_indent(out, d3);
721
600
  *out->cur++ = '"';
722
- memcpy(out->cur, class_name, len);
723
- out->cur += len;
601
+ APPEND_CHARS(out->cur, class_name, len);
724
602
  *out->cur++ = '"';
725
603
  }
726
604
  *out->cur++ = ',';
@@ -764,8 +642,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
764
642
  }
765
643
  #endif
766
644
  out->cur--;
767
- *out->cur++ = ']';
768
- *out->cur++ = '}';
645
+ APPEND_CHARS(out->cur, "]}", 2);
769
646
  *out->cur = '\0';
770
647
  }
771
648
 
@@ -805,7 +682,7 @@ static DumpFunc obj_funcs[] = {
805
682
  void oj_dump_obj_val(VALUE obj, int depth, Out out) {
806
683
  int type = rb_type(obj);
807
684
 
808
- if (Yes == out->opts->trace) {
685
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
809
686
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
810
687
  }
811
688
  if (MAX_DEPTH < depth) {
@@ -816,14 +693,14 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
816
693
 
817
694
  if (NULL != f) {
818
695
  f(obj, depth, out, false);
819
- if (Yes == out->opts->trace) {
696
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
820
697
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
821
698
  }
822
699
  return;
823
700
  }
824
701
  }
825
702
  oj_dump_nil(Qnil, depth, out, false);
826
- if (Yes == out->opts->trace) {
703
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
827
704
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
828
705
  }
829
706
  }
data/ext/oj/dump_strict.c CHANGED
@@ -105,9 +105,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
105
105
  }
106
106
  }
107
107
  assure_size(out, cnt);
108
- for (b = buf; '\0' != *b; b++) {
109
- *out->cur++ = *b;
110
- }
108
+ APPEND_CHARS(out->cur, buf, cnt);
111
109
  *out->cur = '\0';
112
110
  }
113
111
 
@@ -134,19 +132,17 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
134
132
  } else {
135
133
  size = d2 * out->indent + 2;
136
134
  }
135
+ assure_size(out, size * cnt);
137
136
  cnt--;
138
137
  for (i = 0; i <= cnt; i++) {
139
- assure_size(out, size);
140
138
  if (out->opts->dump_opts.use) {
141
139
  if (0 < out->opts->dump_opts.array_size) {
142
- strcpy(out->cur, out->opts->dump_opts.array_nl);
143
- out->cur += out->opts->dump_opts.array_size;
140
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
144
141
  }
145
142
  if (0 < out->opts->dump_opts.indent_size) {
146
143
  int i;
147
144
  for (i = d2; 0 < i; i--) {
148
- strcpy(out->cur, out->opts->dump_opts.indent_str);
149
- out->cur += out->opts->dump_opts.indent_size;
145
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
150
146
  }
151
147
  }
152
148
  } else {
@@ -167,15 +163,13 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
167
163
  // printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
168
164
  // out->opts->dump_opts->indent);
169
165
  if (0 < out->opts->dump_opts.array_size) {
170
- strcpy(out->cur, out->opts->dump_opts.array_nl);
171
- out->cur += out->opts->dump_opts.array_size;
166
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
172
167
  }
173
168
  if (0 < out->opts->dump_opts.indent_size) {
174
169
  int i;
175
170
 
176
171
  for (i = depth; 0 < i; i--) {
177
- strcpy(out->cur, out->opts->dump_opts.indent_str);
178
- out->cur += out->opts->dump_opts.indent_size;
172
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
179
173
  }
180
174
  }
181
175
  } else {
@@ -214,14 +208,12 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
214
208
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
215
209
  assure_size(out, size);
216
210
  if (0 < out->opts->dump_opts.hash_size) {
217
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
218
- out->cur += out->opts->dump_opts.hash_size;
211
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
219
212
  }
220
213
  if (0 < out->opts->dump_opts.indent_size) {
221
214
  int i;
222
215
  for (i = depth; 0 < i; i--) {
223
- strcpy(out->cur, out->opts->dump_opts.indent_str);
224
- out->cur += out->opts->dump_opts.indent_size;
216
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
225
217
  }
226
218
  }
227
219
  if (rtype == T_STRING) {
@@ -232,13 +224,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
232
224
  size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
233
225
  assure_size(out, size);
234
226
  if (0 < out->opts->dump_opts.before_size) {
235
- strcpy(out->cur, out->opts->dump_opts.before_sep);
236
- out->cur += out->opts->dump_opts.before_size;
227
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
237
228
  }
238
229
  *out->cur++ = ':';
239
230
  if (0 < out->opts->dump_opts.after_size) {
240
- strcpy(out->cur, out->opts->dump_opts.after_sep);
241
- out->cur += out->opts->dump_opts.after_size;
231
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
242
232
  }
243
233
  }
244
234
  if (NullMode == out->opts->mode) {
@@ -281,15 +271,13 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
281
271
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
282
272
  assure_size(out, size);
283
273
  if (0 < out->opts->dump_opts.hash_size) {
284
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
285
- out->cur += out->opts->dump_opts.hash_size;
274
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
286
275
  }
287
276
  if (0 < out->opts->dump_opts.indent_size) {
288
277
  int i;
289
278
 
290
279
  for (i = depth; 0 < i; i--) {
291
- strcpy(out->cur, out->opts->dump_opts.indent_str);
292
- out->cur += out->opts->dump_opts.indent_size;
280
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
293
281
  }
294
282
  }
295
283
  }
@@ -350,7 +338,7 @@ static DumpFunc strict_funcs[] = {
350
338
  void oj_dump_strict_val(VALUE obj, int depth, Out out) {
351
339
  int type = rb_type(obj);
352
340
 
353
- if (Yes == out->opts->trace) {
341
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
354
342
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
355
343
  }
356
344
  if (MAX_DEPTH < depth) {
@@ -361,7 +349,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
361
349
 
362
350
  if (NULL != f) {
363
351
  f(obj, depth, out, false);
364
- if (Yes == out->opts->trace) {
352
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
365
353
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
366
354
  }
367
355
  return;
@@ -398,7 +386,7 @@ static DumpFunc null_funcs[] = {
398
386
  void oj_dump_null_val(VALUE obj, int depth, Out out) {
399
387
  int type = rb_type(obj);
400
388
 
401
- if (Yes == out->opts->trace) {
389
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
402
390
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
403
391
  }
404
392
  if (MAX_DEPTH < depth) {
@@ -409,14 +397,14 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
409
397
 
410
398
  if (NULL != f) {
411
399
  f(obj, depth, out, false);
412
- if (Yes == out->opts->trace) {
400
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
413
401
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
414
402
  }
415
403
  return;
416
404
  }
417
405
  }
418
406
  oj_dump_nil(Qnil, depth, out, false);
419
- if (Yes == out->opts->trace) {
407
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
420
408
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
421
409
  }
422
410
  }
data/ext/oj/extconf.rb CHANGED
@@ -23,14 +23,10 @@ dflags = {
23
23
  'RSTRUCT_LEN_RETURNS_INTEGER_OBJECT' => ('ruby' == type && '2' == version[0] && '4' == version[1] && '1' >= version[2]) ? 1 : 0,
24
24
  }
25
25
 
26
- have_func('rb_time_timespec')
27
- have_func('rb_ivar_count')
28
- have_func('rb_ivar_foreach')
29
26
  # Support for compaction.
30
27
  have_func('rb_gc_mark_movable')
31
28
  have_func('stpcpy')
32
29
  have_func('pthread_mutex_init')
33
- have_func('rb_enc_associate')
34
30
  have_func('rb_enc_interned_str')
35
31
  have_func('rb_ext_ractor_safe', 'ruby.h')
36
32
  # rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
@@ -38,6 +34,11 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
38
34
 
39
35
  dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
40
36
 
37
+ if with_config('--with-sse42')
38
+ $CPPFLAGS += ' -msse4.2'
39
+ dflags['OJ_USE_SSE4_2'] = 1
40
+ end
41
+
41
42
  dflags.each do |k,v|
42
43
  if v.nil?
43
44
  $CPPFLAGS += " -D#{k}"
data/ext/oj/fast.c CHANGED
@@ -13,6 +13,7 @@
13
13
 
14
14
  #include "encode.h"
15
15
  #include "oj.h"
16
+ #include "dump.h"
16
17
 
17
18
  // maximum to allocate on the stack, arbitrary limit
18
19
  #define SMALL_JSON 65536
@@ -676,21 +677,23 @@ static void free_doc_cb(void *x) {
676
677
  }
677
678
 
678
679
  static void mark_leaf(Leaf leaf) {
679
- switch (leaf->value_type) {
680
- case COL_VAL:
681
- if (NULL != leaf->elements) {
682
- Leaf first = leaf->elements->next;
683
- Leaf e = first;
680
+ if (NULL != leaf) {
681
+ switch (leaf->value_type) {
682
+ case COL_VAL:
683
+ if (NULL != leaf->elements) {
684
+ Leaf first = leaf->elements->next;
685
+ Leaf e = first;
684
686
 
685
- do {
686
- mark_leaf(e);
687
- e = e->next;
688
- } while (e != first);
689
- }
690
- break;
691
- case RUBY_VAL: mark(leaf->value); break;
687
+ do {
688
+ mark_leaf(e);
689
+ e = e->next;
690
+ } while (e != first);
691
+ }
692
+ break;
693
+ case RUBY_VAL: mark(leaf->value); break;
692
694
 
693
- default: break;
695
+ default: break;
696
+ }
694
697
  }
695
698
  }
696
699
 
@@ -771,7 +774,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
771
774
  pi.doc = doc;
772
775
  #if IS_WINDOWS
773
776
  // assume a 1M stack and give half to ruby
774
- pi.stack_min = (void *)((char *)&pi - (512 * 1024));
777
+ pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
775
778
  #else
776
779
  {
777
780
  struct rlimit lim;
@@ -1610,18 +1613,15 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
1610
1613
  volatile VALUE rjson;
1611
1614
 
1612
1615
  if (0 == filename) {
1613
- char buf[4096];
1614
1616
  struct _out out;
1615
1617
 
1616
- out.buf = buf;
1617
- out.end = buf + sizeof(buf) - 10;
1618
- out.allocated = false;
1618
+ oj_out_init(&out);
1619
+
1619
1620
  out.omit_nil = oj_default_options.dump_opts.omit_nil;
1620
1621
  oj_dump_leaf_to_json(leaf, &oj_default_options, &out);
1621
1622
  rjson = rb_str_new2(out.buf);
1622
- if (out.allocated) {
1623
- xfree(out.buf);
1624
- }
1623
+
1624
+ oj_out_free(&out);
1625
1625
  } else {
1626
1626
  oj_write_leaf_to_file(leaf, filename, &oj_default_options);
1627
1627
  rjson = Qnil;
@@ -1717,8 +1717,10 @@ static VALUE doc_not_implemented(VALUE self) {
1717
1717
  * # Now try again using a path to Oj::Doc.fetch() directly and not using a
1718
1718
  * block. doc = Oj::Doc.open(json) doc.fetch('/2/three') #=> 3 doc.close()
1719
1719
  */
1720
- void oj_init_doc() {
1720
+ void oj_init_doc(void) {
1721
1721
  oj_doc_class = rb_define_class_under(Oj, "Doc", rb_cObject);
1722
+ rb_gc_register_address(&oj_doc_class);
1723
+ rb_undef_alloc_func(oj_doc_class);
1722
1724
  rb_define_singleton_method(oj_doc_class, "open", doc_open, 1);
1723
1725
  rb_define_singleton_method(oj_doc_class, "open_file", doc_open_file, 1);
1724
1726
  rb_define_singleton_method(oj_doc_class, "parse", doc_open, 1);