oj 3.13.11 → 3.15.0

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +20 -31
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -21
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +4 -2
  67. data/lib/oj/mimic.rb +4 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/sparse.c CHANGED
@@ -10,6 +10,7 @@
10
10
  #include "buf.h"
11
11
  #include "encode.h"
12
12
  #include "intern.h" // for oj_strndup()
13
+ #include "mem.h"
13
14
  #include "oj.h"
14
15
  #include "parse.h"
15
16
  #include "val_stack.h"
@@ -71,7 +72,7 @@ static void add_value(ParseInfo pi, VALUE rval) {
71
72
  case NEXT_HASH_VALUE:
72
73
  pi->hash_set_value(pi, parent, rval);
73
74
  if (parent->kalloc) {
74
- xfree((char *)parent->key);
75
+ OJ_R_FREE((char *)parent->key);
75
76
  }
76
77
  parent->key = 0;
77
78
  parent->kalloc = 0;
@@ -110,7 +111,7 @@ static void add_num_value(ParseInfo pi, NumInfo ni) {
110
111
  case NEXT_HASH_VALUE:
111
112
  pi->hash_set_num(pi, parent, ni);
112
113
  if (parent->kalloc) {
113
- xfree((char *)parent->key);
114
+ OJ_R_FREE((char *)parent->key);
114
115
  }
115
116
  parent->key = 0;
116
117
  parent->kalloc = 0;
@@ -212,11 +213,7 @@ static void read_escaped_str(ParseInfo pi) {
212
213
  }
213
214
  while ('\"' != (c = reader_get(&pi->rd))) {
214
215
  if ('\0' == c) {
215
- oj_set_error_at(pi,
216
- oj_parse_error_class,
217
- __FILE__,
218
- __LINE__,
219
- "quoted string not terminated");
216
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
220
217
  buf_cleanup(&buf);
221
218
  return;
222
219
  } else if ('\\' == c) {
@@ -249,11 +246,7 @@ static void read_escaped_str(ParseInfo pi) {
249
246
  reader_backup(&pi->rd);
250
247
  break;
251
248
  }
252
- oj_set_error_at(pi,
253
- oj_parse_error_class,
254
- __FILE__,
255
- __LINE__,
256
- "invalid escaped character");
249
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
257
250
  buf_cleanup(&buf);
258
251
  return;
259
252
  }
@@ -277,11 +270,7 @@ static void read_escaped_str(ParseInfo pi) {
277
270
  buf_append(&buf, c);
278
271
  break;
279
272
  }
280
- oj_set_error_at(pi,
281
- oj_parse_error_class,
282
- __FILE__,
283
- __LINE__,
284
- "invalid escaped character");
273
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid escaped character");
285
274
  buf_cleanup(&buf);
286
275
  return;
287
276
  }
@@ -315,7 +304,7 @@ static void read_escaped_str(ParseInfo pi) {
315
304
  case NEXT_HASH_VALUE:
316
305
  pi->hash_set_cstr(pi, parent, buf.head, buf_len(&buf), pi->rd.str);
317
306
  if (parent->kalloc) {
318
- xfree((char *)parent->key);
307
+ OJ_R_FREE((char *)parent->key);
319
308
  }
320
309
  parent->key = 0;
321
310
  parent->kalloc = 0;
@@ -345,11 +334,7 @@ static void read_str(ParseInfo pi) {
345
334
  reader_protect(&pi->rd);
346
335
  while ('\"' != (c = reader_get(&pi->rd))) {
347
336
  if ('\0' == c) {
348
- oj_set_error_at(pi,
349
- oj_parse_error_class,
350
- __FILE__,
351
- __LINE__,
352
- "quoted string not terminated");
337
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "quoted string not terminated");
353
338
  return;
354
339
  } else if ('\\' == c) {
355
340
  reader_backup(&pi->rd);
@@ -386,7 +371,7 @@ static void read_str(ParseInfo pi) {
386
371
  case NEXT_HASH_VALUE:
387
372
  pi->hash_set_cstr(pi, parent, pi->rd.str, pi->rd.tail - pi->rd.str - 1, pi->rd.str);
388
373
  if (parent->kalloc) {
389
- xfree((char *)parent->key);
374
+ OJ_R_FREE((char *)parent->key);
390
375
  }
391
376
  parent->key = 0;
392
377
  parent->kalloc = 0;
@@ -429,7 +414,7 @@ static void read_num(ParseInfo pi) {
429
414
  ni.no_big = !pi->options.compat_bigdec;
430
415
  ni.bigdec_load = pi->options.compat_bigdec;
431
416
  } else {
432
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
417
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
433
418
  RubyDec == pi->options.bigdec_load);
434
419
  ni.bigdec_load = pi->options.bigdec_load;
435
420
  }
@@ -443,18 +428,10 @@ static void read_num(ParseInfo pi) {
443
428
  }
444
429
  if ('I' == c) {
445
430
  if (No == pi->options.allow_nan) {
446
- oj_set_error_at(pi,
447
- oj_parse_error_class,
448
- __FILE__,
449
- __LINE__,
450
- "not a number or other value");
431
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
451
432
  return;
452
433
  } else if (0 != reader_expect(&pi->rd, "nfinity")) {
453
- oj_set_error_at(pi,
454
- oj_parse_error_class,
455
- __FILE__,
456
- __LINE__,
457
- "not a number or other value");
434
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
458
435
  return;
459
436
  }
460
437
  ni.infinity = 1;
@@ -476,11 +453,7 @@ static void read_num(ParseInfo pi) {
476
453
 
477
454
  if (0 < d) {
478
455
  if (zero1 && CompatMode == pi->options.mode) {
479
- oj_set_error_at(pi,
480
- oj_parse_error_class,
481
- __FILE__,
482
- __LINE__,
483
- "not a number");
456
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
484
457
  return;
485
458
  }
486
459
  zero1 = false;
@@ -591,7 +564,7 @@ static void read_nan(ParseInfo pi) {
591
564
  ni.no_big = !pi->options.compat_bigdec;
592
565
  ni.bigdec_load = pi->options.compat_bigdec;
593
566
  } else {
594
- ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
567
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
595
568
  RubyDec == pi->options.bigdec_load);
596
569
  ni.bigdec_load = pi->options.bigdec_load;
597
570
  }
@@ -716,11 +689,7 @@ void oj_sparse2(ParseInfo pi) {
716
689
  case '"': read_str(pi); break;
717
690
  case '+':
718
691
  if (CompatMode == pi->options.mode) {
719
- oj_set_error_at(pi,
720
- oj_parse_error_class,
721
- __FILE__,
722
- __LINE__,
723
- "unexpected character");
692
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
724
693
  return;
725
694
  }
726
695
  pi->cur--;
@@ -745,11 +714,7 @@ void oj_sparse2(ParseInfo pi) {
745
714
  reader_backup(&pi->rd);
746
715
  read_num(pi);
747
716
  } else {
748
- oj_set_error_at(pi,
749
- oj_parse_error_class,
750
- __FILE__,
751
- __LINE__,
752
- "unexpected character");
717
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
753
718
  return;
754
719
  }
755
720
  break;
@@ -757,11 +722,7 @@ void oj_sparse2(ParseInfo pi) {
757
722
  if (Yes == pi->options.allow_nan) {
758
723
  read_nan(pi);
759
724
  } else {
760
- oj_set_error_at(pi,
761
- oj_parse_error_class,
762
- __FILE__,
763
- __LINE__,
764
- "unexpected character");
725
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character");
765
726
  return;
766
727
  }
767
728
  break;
@@ -799,8 +760,7 @@ void oj_sparse2(ParseInfo pi) {
799
760
  ni.no_big = !pi->options.compat_bigdec;
800
761
  ni.bigdec_load = pi->options.compat_bigdec;
801
762
  } else {
802
- ni.no_big = (FloatDec == pi->options.bigdec_load ||
803
- FastDec == pi->options.bigdec_load ||
763
+ ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load ||
804
764
  RubyDec == pi->options.bigdec_load);
805
765
  ni.bigdec_load = pi->options.bigdec_load;
806
766
  }
@@ -813,13 +773,7 @@ void oj_sparse2(ParseInfo pi) {
813
773
  case '/': skip_comment(pi); break;
814
774
  case '\0': return;
815
775
  default:
816
- oj_set_error_at(pi,
817
- oj_parse_error_class,
818
- __FILE__,
819
- __LINE__,
820
- "unexpected character '%c' [0x%02x]",
821
- c,
822
- c);
776
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "unexpected character '%c' [0x%02x]", c, c);
823
777
  return;
824
778
  }
825
779
  if (err_has(&pi->err)) {
@@ -878,8 +832,8 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
878
832
  } else {
879
833
  rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
880
834
  }
881
- } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) &&
882
- No == pi->options.nilnil && 0 == RSTRING_LEN(input)) {
835
+ } else if (CompatMode == pi->options.mode && T_STRING == rb_type(input) && No == pi->options.nilnil &&
836
+ 0 == RSTRING_LEN(input)) {
883
837
  rb_raise(oj_json_parser_error_class, "An empty string is not a valid JSON string.");
884
838
  }
885
839
  if (rb_block_given_p()) {
@@ -932,9 +886,7 @@ oj_pi_sparse(int argc, VALUE *argv, ParseInfo pi, int fd) {
932
886
  switch (v->next) {
933
887
  case NEXT_ARRAY_NEW:
934
888
  case NEXT_ARRAY_ELEMENT:
935
- case NEXT_ARRAY_COMMA:
936
- oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated");
937
- break;
889
+ case NEXT_ARRAY_COMMA: oj_set_error_at(pi, err_class, __FILE__, __LINE__, "Array not terminated"); break;
938
890
  case NEXT_HASH_NEW:
939
891
  case NEXT_HASH_KEY:
940
892
  case NEXT_HASH_COLON:
@@ -953,7 +905,11 @@ CLEANUP:
953
905
  }
954
906
  stack_cleanup(&pi->stack);
955
907
  if (0 != fd) {
908
+ #ifdef _WIN32
909
+ rb_w32_close(fd);
910
+ #else
956
911
  close(fd);
912
+ #endif
957
913
  }
958
914
  if (err_has(&pi->err)) {
959
915
  rb_set_errinfo(Qnil);
@@ -5,6 +5,7 @@
5
5
  #include <ruby.h>
6
6
 
7
7
  #include "encode.h"
8
+ #include "mem.h"
8
9
 
9
10
  extern VALUE Oj;
10
11
 
@@ -15,9 +16,9 @@ static void stream_writer_free(void *ptr) {
15
16
  return;
16
17
  }
17
18
  sw = (StreamWriter)ptr;
18
- xfree(sw->sw.out.buf);
19
- xfree(sw->sw.types);
20
- xfree(ptr);
19
+ OJ_R_FREE(sw->sw.out.buf);
20
+ OJ_R_FREE(sw->sw.types);
21
+ OJ_R_FREE(ptr);
21
22
  }
22
23
 
23
24
  static void stream_writer_reset_buf(StreamWriter sw) {
@@ -82,8 +83,8 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
82
83
  if (oj_stringio_class == clas) {
83
84
  type = STRING_IO;
84
85
  #if !IS_WINDOWS
85
- } else if (rb_respond_to(stream, oj_fileno_id) &&
86
- Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) && 0 != (fd = FIX2INT(s))) {
86
+ } else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
87
+ 0 != (fd = FIX2INT(s))) {
87
88
  type = FILE_IO;
88
89
  #endif
89
90
  } else if (rb_respond_to(stream, oj_write_id)) {
@@ -91,7 +92,7 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
91
92
  } else {
92
93
  rb_raise(rb_eArgError, "expected an IO Object.");
93
94
  }
94
- sw = ALLOC(struct _streamWriter);
95
+ sw = OJ_R_ALLOC(struct _streamWriter);
95
96
  if (2 == argc && T_HASH == rb_type(argv[1])) {
96
97
  volatile VALUE v;
97
98
  int buf_size = 0;
@@ -101,15 +102,10 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
101
102
  rb_gc_register_address(&buffer_size_sym);
102
103
  }
103
104
  if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
104
- #ifdef RUBY_INTEGER_UNIFICATION
105
105
  if (rb_cInteger != rb_obj_class(v)) {
106
+ OJ_R_FREE(sw);
106
107
  rb_raise(rb_eArgError, ":buffer size must be a Integer.");
107
108
  }
108
- #else
109
- if (T_FIXNUM != rb_type(v)) {
110
- rb_raise(rb_eArgError, ":buffer size must be a Integer.");
111
- }
112
- #endif
113
109
  buf_size = FIX2INT(v);
114
110
  }
115
111
  oj_str_writer_init(&sw->sw, buf_size);
@@ -139,7 +135,6 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
139
135
  static VALUE stream_writer_push_key(VALUE self, VALUE key) {
140
136
  StreamWriter sw = (StreamWriter)DATA_PTR(self);
141
137
 
142
- rb_check_type(key, T_STRING);
143
138
  oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
144
139
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
145
140
  stream_writer_write(sw);
@@ -164,7 +159,6 @@ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
164
159
  if (Qnil == argv[0]) {
165
160
  oj_str_writer_push_object(&sw->sw, 0);
166
161
  } else {
167
- rb_check_type(argv[0], T_STRING);
168
162
  oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
169
163
  }
170
164
  break;
@@ -193,7 +187,6 @@ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
193
187
  if (Qnil == argv[0]) {
194
188
  oj_str_writer_push_array(&sw->sw, 0);
195
189
  } else {
196
- rb_check_type(argv[0], T_STRING);
197
190
  oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
198
191
  }
199
192
  break;
@@ -221,7 +214,6 @@ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
221
214
  if (Qnil == argv[1]) {
222
215
  oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
223
216
  } else {
224
- rb_check_type(argv[1], T_STRING);
225
217
  oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
226
218
  }
227
219
  break;
@@ -245,17 +237,13 @@ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
245
237
  static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
246
238
  StreamWriter sw = (StreamWriter)DATA_PTR(self);
247
239
 
248
- rb_check_type(argv[0], T_STRING);
249
240
  switch (argc) {
250
241
  case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
251
242
  case 2:
252
243
  if (Qnil == argv[1]) {
253
244
  oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
254
245
  } else {
255
- rb_check_type(argv[1], T_STRING);
256
- oj_str_writer_push_json((StrWriter)DATA_PTR(self),
257
- StringValuePtr(*argv),
258
- StringValuePtr(argv[1]));
246
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
259
247
  }
260
248
  break;
261
249
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
@@ -315,8 +303,10 @@ static VALUE stream_writer_flush(VALUE self) {
315
303
  * will create that element in the JSON document and subsequent pushes will add
316
304
  * the elements to that array or object until a pop() is called.
317
305
  */
318
- void oj_stream_writer_init() {
306
+ void oj_stream_writer_init(void) {
319
307
  oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
308
+ rb_gc_register_address(&oj_stream_writer_class);
309
+ rb_undef_alloc_func(oj_stream_writer_class);
320
310
  rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
321
311
  rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
322
312
  rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);
data/ext/oj/strict.c CHANGED
@@ -17,7 +17,7 @@ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
17
  volatile VALUE rstr = Qnil;
18
18
 
19
19
  if (len < cache_str) {
20
- rstr = oj_str_intern(str, len);
20
+ rstr = oj_str_intern(str, len);
21
21
  } else {
22
22
  rstr = rb_str_new(str, len);
23
23
  rstr = oj_encode(rstr);
@@ -37,28 +37,24 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
37
37
  } else {
38
38
  rkey = rb_str_new(parent->key, parent->klen);
39
39
  rkey = oj_encode(rkey);
40
- OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
40
+ OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
41
41
  }
42
42
  return rkey;
43
43
  }
44
44
  if (Yes == pi->options.sym_key) {
45
- rkey = oj_sym_intern(parent->key, parent->klen);
45
+ rkey = oj_sym_intern(parent->key, parent->klen);
46
46
  } else {
47
- rkey = oj_str_intern(parent->key, parent->klen);
47
+ rkey = oj_str_intern(parent->key, parent->klen);
48
48
  }
49
49
  return rkey;
50
50
  }
51
51
 
52
52
  static void hash_end(ParseInfo pi) {
53
- if (Yes == pi->options.trace) {
54
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
55
- }
53
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
56
54
  }
57
55
 
58
56
  static void array_end(ParseInfo pi) {
59
- if (Yes == pi->options.trace) {
60
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
61
- }
57
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
62
58
  }
63
59
 
64
60
  static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
@@ -66,9 +62,7 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
66
62
  }
67
63
 
68
64
  static void add_value(ParseInfo pi, VALUE val) {
69
- if (Yes == pi->options.trace) {
70
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
71
- }
65
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, val);
72
66
  pi->stack.head->val = val;
73
67
  }
74
68
 
@@ -76,9 +70,7 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
76
70
  volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
77
71
 
78
72
  pi->stack.head->val = rstr;
79
- if (Yes == pi->options.trace) {
80
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
81
- }
73
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
82
74
  }
83
75
 
84
76
  static void add_num(ParseInfo pi, NumInfo ni) {
@@ -86,30 +78,22 @@ static void add_num(ParseInfo pi, NumInfo ni) {
86
78
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
87
79
  }
88
80
  pi->stack.head->val = oj_num_as_value(ni);
89
- if (Yes == pi->options.trace) {
90
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
91
- }
81
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
92
82
  }
93
83
 
94
84
  static VALUE start_hash(ParseInfo pi) {
95
85
  if (Qnil != pi->options.hash_class) {
96
86
  return rb_class_new_instance(0, NULL, pi->options.hash_class);
97
87
  }
98
- if (Yes == pi->options.trace) {
99
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
100
- }
88
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
101
89
  return rb_hash_new();
102
90
  }
103
91
 
104
92
  static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
105
93
  volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
106
94
 
107
- rb_hash_aset(stack_peek(&pi->stack)->val,
108
- oj_calc_hash_key(pi, parent),
109
- rstr);
110
- if (Yes == pi->options.trace) {
111
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
112
- }
95
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rstr);
96
+ TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
113
97
  }
114
98
 
115
99
  static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
@@ -119,27 +103,17 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
119
103
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
120
104
  }
121
105
  v = oj_num_as_value(ni);
122
- rb_hash_aset(stack_peek(&pi->stack)->val,
123
- oj_calc_hash_key(pi, parent),
124
- v);
125
- if (Yes == pi->options.trace) {
126
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
127
- }
106
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), v);
107
+ TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, v);
128
108
  }
129
109
 
130
110
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
131
- rb_hash_aset(stack_peek(&pi->stack)->val,
132
- oj_calc_hash_key(pi, parent),
133
- value);
134
- if (Yes == pi->options.trace) {
135
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
136
- }
111
+ rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
112
+ TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
137
113
  }
138
114
 
139
115
  static VALUE start_array(ParseInfo pi) {
140
- if (Yes == pi->options.trace) {
141
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
142
- }
116
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
143
117
  return rb_ary_new();
144
118
  }
145
119
 
@@ -147,9 +121,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
147
121
  volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
148
122
 
149
123
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
150
- if (Yes == pi->options.trace) {
151
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
152
- }
124
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
153
125
  }
154
126
 
155
127
  static void array_append_num(ParseInfo pi, NumInfo ni) {
@@ -160,16 +132,12 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
160
132
  }
161
133
  v = oj_num_as_value(ni);
162
134
  rb_ary_push(stack_peek(&pi->stack)->val, v);
163
- if (Yes == pi->options.trace) {
164
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
165
- }
135
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, v);
166
136
  }
167
137
 
168
138
  static void array_append_value(ParseInfo pi, VALUE value) {
169
139
  rb_ary_push(stack_peek(&pi->stack)->val, value);
170
- if (Yes == pi->options.trace) {
171
- oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
172
- }
140
+ TRACE_PARSE_CALL(pi->options.trace, "append_value", pi, value);
173
141
  }
174
142
 
175
143
  void oj_set_strict_callbacks(ParseInfo pi) {
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include "dump.h"
5
5
  #include "encode.h"
6
+ #include "mem.h"
6
7
 
7
8
  extern VALUE Oj;
8
9
 
@@ -20,7 +21,7 @@ static void push_type(StrWriter sw, DumpType type) {
20
21
  if (sw->types_end <= sw->types + sw->depth + 1) {
21
22
  size_t size = (sw->types_end - sw->types) * 2;
22
23
 
23
- REALLOC_N(sw->types, char, size);
24
+ OJ_R_REALLOC_N(sw->types, char, size);
24
25
  sw->types_end = sw->types + size;
25
26
  }
26
27
  sw->depth++;
@@ -43,7 +44,7 @@ static void maybe_comma(StrWriter sw) {
43
44
  void oj_str_writer_init(StrWriter sw, int buf_size) {
44
45
  sw->opts = oj_default_options;
45
46
  sw->depth = 0;
46
- sw->types = ALLOC_N(char, 256);
47
+ sw->types = OJ_R_ALLOC_N(char, 256);
47
48
  sw->types_end = sw->types + 256;
48
49
  *sw->types = '\0';
49
50
  sw->keyWritten = 0;
@@ -53,10 +54,13 @@ void oj_str_writer_init(StrWriter sw, int buf_size) {
53
54
  } else if (buf_size < 1024) {
54
55
  buf_size = 1024;
55
56
  }
56
- sw->out.buf = ALLOC_N(char, buf_size);
57
- sw->out.end = sw->out.buf + buf_size - 10;
58
- sw->out.allocated = true;
59
- sw->out.cur = sw->out.buf;
57
+ // Must be allocated. Using the out.stack_buffer results in double frees
58
+ // and I haven't figured out why yet.
59
+ sw->out.buf = OJ_R_ALLOC_N(char, buf_size);
60
+ sw->out.cur = sw->out.buf;
61
+ sw->out.end = sw->out.buf + buf_size - BUFFER_EXTRA;
62
+ sw->out.allocated = true;
63
+
60
64
  *sw->out.cur = '\0';
61
65
  sw->out.circ_cache = NULL;
62
66
  sw->out.circ_cnt = 0;
@@ -229,9 +233,11 @@ static void str_writer_free(void *ptr) {
229
233
  return;
230
234
  }
231
235
  sw = (StrWriter)ptr;
232
- xfree(sw->out.buf);
233
- xfree(sw->types);
234
- xfree(ptr);
236
+
237
+ oj_out_free(&sw->out);
238
+
239
+ OJ_R_FREE(sw->types);
240
+ OJ_R_FREE(ptr);
235
241
  }
236
242
 
237
243
  /* Document-method: new
@@ -251,7 +257,7 @@ static void str_writer_free(void *ptr) {
251
257
  * - *options* [_Hash_] formatting options
252
258
  */
253
259
  static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
254
- StrWriter sw = ALLOC(struct _strWriter);
260
+ StrWriter sw = OJ_R_ALLOC(struct _strWriter);
255
261
 
256
262
  oj_str_writer_init(sw, 0);
257
263
  if (1 == argc) {
@@ -275,7 +281,6 @@ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
275
281
  static VALUE str_writer_push_key(VALUE self, VALUE key) {
276
282
  StrWriter sw = (StrWriter)DATA_PTR(self);
277
283
 
278
- rb_check_type(key, T_STRING);
279
284
  oj_str_writer_push_key(sw, StringValuePtr(key));
280
285
 
281
286
  return Qnil;
@@ -297,7 +302,6 @@ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
297
302
  if (Qnil == argv[0]) {
298
303
  oj_str_writer_push_object(sw, 0);
299
304
  } else {
300
- rb_check_type(argv[0], T_STRING);
301
305
  oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
302
306
  }
303
307
  break;
@@ -326,7 +330,6 @@ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
326
330
  if (Qnil == argv[0]) {
327
331
  oj_str_writer_push_array(sw, 0);
328
332
  } else {
329
- rb_check_type(argv[0], T_STRING);
330
333
  oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
331
334
  }
332
335
  break;
@@ -353,7 +356,6 @@ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
353
356
  if (Qnil == argv[1]) {
354
357
  oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
355
358
  } else {
356
- rb_check_type(argv[1], T_STRING);
357
359
  oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
358
360
  }
359
361
  break;
@@ -372,17 +374,13 @@ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
372
374
  * - *key* [_String_] the key if adding to an object in the JSON document
373
375
  */
374
376
  static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
375
- rb_check_type(argv[0], T_STRING);
376
377
  switch (argc) {
377
378
  case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
378
379
  case 2:
379
380
  if (Qnil == argv[1]) {
380
381
  oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
381
382
  } else {
382
- rb_check_type(argv[1], T_STRING);
383
- oj_str_writer_push_json((StrWriter)DATA_PTR(self),
384
- StringValuePtr(*argv),
385
- StringValuePtr(argv[1]));
383
+ oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
386
384
  }
387
385
  break;
388
386
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
@@ -449,7 +447,7 @@ static VALUE str_writer_to_s(VALUE self) {
449
447
  * Returns the contents of the writer as a JSON element. If called from inside
450
448
  * an array or hash by Oj the raw buffer will be used othersize a more
451
449
  * inefficient parse of the contents and a return of the result is
452
- * completed. The parse uses the trict mode.
450
+ * completed. The parse uses the strict mode.
453
451
  *
454
452
  * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
455
453
  */
@@ -469,8 +467,10 @@ static VALUE str_writer_as_json(VALUE self) {
469
467
  * calling to_s() will return the JSON document. Note that calling to_s() before
470
468
  * construction is complete will return the document in it's current state.
471
469
  */
472
- void oj_string_writer_init() {
470
+ void oj_string_writer_init(void) {
473
471
  oj_string_writer_class = rb_define_class_under(Oj, "StringWriter", rb_cObject);
472
+ rb_gc_register_address(&oj_string_writer_class);
473
+ rb_undef_alloc_func(oj_string_writer_class);
474
474
  rb_define_module_function(oj_string_writer_class, "new", str_writer_new, -1);
475
475
  rb_define_method(oj_string_writer_class, "push_key", str_writer_push_key, 1);
476
476
  rb_define_method(oj_string_writer_class, "push_object", str_writer_push_object, -1);