oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/sparse.c CHANGED
@@ -9,7 +9,8 @@
9
9
 
10
10
  #include "buf.h"
11
11
  #include "encode.h"
12
- #include "hash.h" // for oj_strndup()
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;
@@ -494,7 +467,7 @@ static void read_num(ParseInfo pi) {
494
467
  if ('.' == c) {
495
468
  c = reader_get(&pi->rd);
496
469
  // A trailing . is not a valid decimal but if encountered allow it
497
- // except when mimicing the JSON gem.
470
+ // except when mimicking the JSON gem.
498
471
  if (CompatMode == pi->options.mode) {
499
472
  if (c < '0' || '9' < c) {
500
473
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
@@ -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,11 +16,22 @@ 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
 
24
+ static const rb_data_type_t oj_stream_writer_type = {
25
+ "Oj/stream_writer",
26
+ {
27
+ NULL,
28
+ stream_writer_free,
29
+ NULL,
30
+ },
31
+ 0,
32
+ 0,
33
+ };
34
+
23
35
  static void stream_writer_reset_buf(StreamWriter sw) {
24
36
  sw->sw.out.cur = sw->sw.out.buf;
25
37
  *sw->sw.out.cur = '\0';
@@ -56,9 +68,9 @@ static VALUE buffer_size_sym = Qundef;
56
68
  /* Document-method: new
57
69
  * call-seq: new(io, options)
58
70
  *
59
- * Creates a new StreamWriter. Options are supported according the the
60
- * specified mode or the mode in the default options. Note that if mimic_JSON
61
- * or Oj.optimize_rails has not been called then the behavior of the modes may
71
+ * Creates a new StreamWriter. Options are supported according the specified
72
+ * mode or the mode in the default options. Note that if mimic_JSON or
73
+ * Oj.optimize_rails has not been called then the behavior of the modes may
62
74
  * not be the same as if they were.
63
75
  *
64
76
  * In addition to the regular dump options for the various modes a
@@ -67,7 +79,7 @@ static VALUE buffer_size_sym = Qundef;
67
79
  * should be and also a hint on when to flush.
68
80
  *
69
81
  * - *io* [_IO_] stream to write to
70
- * - *options* [_Hash_] formating options
82
+ * - *options* [_Hash_] formatting options
71
83
  */
72
84
  static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
73
85
  StreamWriterType type = STREAM_IO;
@@ -82,8 +94,8 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
82
94
  if (oj_stringio_class == clas) {
83
95
  type = STRING_IO;
84
96
  #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))) {
97
+ } else if (rb_respond_to(stream, oj_fileno_id) && Qnil != (s = rb_funcall(stream, oj_fileno_id, 0)) &&
98
+ 0 != (fd = FIX2INT(s))) {
87
99
  type = FILE_IO;
88
100
  #endif
89
101
  } else if (rb_respond_to(stream, oj_write_id)) {
@@ -91,7 +103,7 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
91
103
  } else {
92
104
  rb_raise(rb_eArgError, "expected an IO Object.");
93
105
  }
94
- sw = ALLOC(struct _streamWriter);
106
+ sw = OJ_R_ALLOC(struct _streamWriter);
95
107
  if (2 == argc && T_HASH == rb_type(argv[1])) {
96
108
  volatile VALUE v;
97
109
  int buf_size = 0;
@@ -101,15 +113,10 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
101
113
  rb_gc_register_address(&buffer_size_sym);
102
114
  }
103
115
  if (Qnil != (v = rb_hash_lookup(argv[1], buffer_size_sym))) {
104
- #ifdef RUBY_INTEGER_UNIFICATION
105
116
  if (rb_cInteger != rb_obj_class(v)) {
117
+ OJ_R_FREE(sw);
106
118
  rb_raise(rb_eArgError, ":buffer size must be a Integer.");
107
119
  }
108
- #else
109
- if (T_FIXNUM != rb_type(v)) {
110
- rb_raise(rb_eArgError, ":buffer size must be a Integer.");
111
- }
112
- #endif
113
120
  buf_size = FIX2INT(v);
114
121
  }
115
122
  oj_str_writer_init(&sw->sw, buf_size);
@@ -124,7 +131,7 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
124
131
  sw->type = type;
125
132
  sw->fd = fd;
126
133
 
127
- return Data_Wrap_Struct(oj_stream_writer_class, 0, stream_writer_free, sw);
134
+ return TypedData_Wrap_Struct(oj_stream_writer_class, &oj_stream_writer_type, sw);
128
135
  }
129
136
 
130
137
  /* Document-method: push_key
@@ -137,9 +144,9 @@ static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
137
144
  * - *key* [_String_] the key pending for the next push
138
145
  */
139
146
  static VALUE stream_writer_push_key(VALUE self, VALUE key) {
140
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
147
+ StreamWriter sw;
148
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
141
149
 
142
- rb_check_type(key, T_STRING);
143
150
  oj_str_writer_push_key(&sw->sw, StringValuePtr(key));
144
151
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
145
152
  stream_writer_write(sw);
@@ -156,7 +163,8 @@ static VALUE stream_writer_push_key(VALUE self, VALUE key) {
156
163
  * - *key* [_String_] the key if adding to an object in the JSON document
157
164
  */
158
165
  static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
159
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
166
+ StreamWriter sw;
167
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
160
168
 
161
169
  switch (argc) {
162
170
  case 0: oj_str_writer_push_object(&sw->sw, 0); break;
@@ -164,7 +172,6 @@ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
164
172
  if (Qnil == argv[0]) {
165
173
  oj_str_writer_push_object(&sw->sw, 0);
166
174
  } else {
167
- rb_check_type(argv[0], T_STRING);
168
175
  oj_str_writer_push_object(&sw->sw, StringValuePtr(argv[0]));
169
176
  }
170
177
  break;
@@ -185,7 +192,8 @@ static VALUE stream_writer_push_object(int argc, VALUE *argv, VALUE self) {
185
192
  * - *key* [_String_] the key if adding to an object in the JSON document
186
193
  */
187
194
  static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
188
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
195
+ StreamWriter sw;
196
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
189
197
 
190
198
  switch (argc) {
191
199
  case 0: oj_str_writer_push_array(&sw->sw, 0); break;
@@ -193,7 +201,6 @@ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
193
201
  if (Qnil == argv[0]) {
194
202
  oj_str_writer_push_array(&sw->sw, 0);
195
203
  } else {
196
- rb_check_type(argv[0], T_STRING);
197
204
  oj_str_writer_push_array(&sw->sw, StringValuePtr(argv[0]));
198
205
  }
199
206
  break;
@@ -213,16 +220,16 @@ static VALUE stream_writer_push_array(int argc, VALUE *argv, VALUE self) {
213
220
  * - *key* [_String_] the key if adding to an object in the JSON document
214
221
  */
215
222
  static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
216
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
223
+ StreamWriter sw;
224
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
217
225
 
218
226
  switch (argc) {
219
- case 1: oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0); break;
227
+ case 1: oj_str_writer_push_value((StrWriter)sw, *argv, 0); break;
220
228
  case 2:
221
229
  if (Qnil == argv[1]) {
222
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
230
+ oj_str_writer_push_value((StrWriter)sw, *argv, 0);
223
231
  } else {
224
- rb_check_type(argv[1], T_STRING);
225
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
232
+ oj_str_writer_push_value((StrWriter)sw, *argv, StringValuePtr(argv[1]));
226
233
  }
227
234
  break;
228
235
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
@@ -243,19 +250,16 @@ static VALUE stream_writer_push_value(int argc, VALUE *argv, VALUE self) {
243
250
  * - *key* [_String_] the key if adding to an object in the JSON document
244
251
  */
245
252
  static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
246
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
253
+ StreamWriter sw;
254
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
247
255
 
248
- rb_check_type(argv[0], T_STRING);
249
256
  switch (argc) {
250
- case 1: oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0); break;
257
+ case 1: oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), 0); break;
251
258
  case 2:
252
259
  if (Qnil == argv[1]) {
253
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
260
+ oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), 0);
254
261
  } 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]));
262
+ oj_str_writer_push_json((StrWriter)sw, StringValuePtr(*argv), StringValuePtr(argv[1]));
259
263
  }
260
264
  break;
261
265
  default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
@@ -273,7 +277,8 @@ static VALUE stream_writer_push_json(int argc, VALUE *argv, VALUE self) {
273
277
  * currently open.
274
278
  */
275
279
  static VALUE stream_writer_pop(VALUE self) {
276
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
280
+ StreamWriter sw;
281
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
277
282
 
278
283
  oj_str_writer_pop(&sw->sw);
279
284
  if (sw->flush_limit < sw->sw.out.cur - sw->sw.out.buf) {
@@ -289,7 +294,8 @@ static VALUE stream_writer_pop(VALUE self) {
289
294
  * currently open.
290
295
  */
291
296
  static VALUE stream_writer_pop_all(VALUE self) {
292
- StreamWriter sw = (StreamWriter)DATA_PTR(self);
297
+ StreamWriter sw;
298
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
293
299
 
294
300
  oj_str_writer_pop_all(&sw->sw);
295
301
  stream_writer_write(sw);
@@ -303,7 +309,9 @@ static VALUE stream_writer_pop_all(VALUE self) {
303
309
  * Flush any remaining characters in the buffer.
304
310
  */
305
311
  static VALUE stream_writer_flush(VALUE self) {
306
- stream_writer_write((StreamWriter)DATA_PTR(self));
312
+ StreamWriter sw;
313
+ TypedData_Get_Struct(self, struct _streamWriter, &oj_stream_writer_type, sw);
314
+ stream_writer_write(sw);
307
315
 
308
316
  return Qnil;
309
317
  }
@@ -315,8 +323,10 @@ static VALUE stream_writer_flush(VALUE self) {
315
323
  * will create that element in the JSON document and subsequent pushes will add
316
324
  * the elements to that array or object until a pop() is called.
317
325
  */
318
- void oj_stream_writer_init() {
326
+ void oj_stream_writer_init(void) {
319
327
  oj_stream_writer_class = rb_define_class_under(Oj, "StreamWriter", rb_cObject);
328
+ rb_gc_register_address(&oj_stream_writer_class);
329
+ rb_undef_alloc_func(oj_stream_writer_class);
320
330
  rb_define_module_function(oj_stream_writer_class, "new", stream_writer_new, -1);
321
331
  rb_define_method(oj_stream_writer_class, "push_key", stream_writer_push_key, 1);
322
332
  rb_define_method(oj_stream_writer_class, "push_object", stream_writer_push_object, -1);
data/ext/oj/strict.c CHANGED
@@ -8,20 +8,53 @@
8
8
 
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
+ #include "intern.h"
11
12
  #include "oj.h"
12
13
  #include "parse.h"
13
14
  #include "trace.h"
14
15
 
15
- static void hash_end(ParseInfo pi) {
16
- if (Yes == pi->options.trace) {
17
- oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
16
+ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
+ volatile VALUE rstr = Qnil;
18
+
19
+ if (len < cache_str) {
20
+ rstr = oj_str_intern(str, len);
21
+ } else {
22
+ rstr = rb_str_new(str, len);
23
+ rstr = oj_encode(rstr);
18
24
  }
25
+ return rstr;
19
26
  }
20
27
 
21
- static void array_end(ParseInfo pi) {
22
- if (Yes == pi->options.trace) {
23
- oj_trace_parse_array_end(pi, __FILE__, __LINE__);
28
+ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
29
+ volatile VALUE rkey = parent->key_val;
30
+
31
+ if (Qundef != rkey) {
32
+ return rkey;
33
+ }
34
+ if (Yes != pi->options.cache_keys) {
35
+ if (Yes == pi->options.sym_key) {
36
+ rkey = ID2SYM(rb_intern3(parent->key, parent->klen, oj_utf8_encoding));
37
+ } else {
38
+ rkey = rb_str_new(parent->key, parent->klen);
39
+ rkey = oj_encode(rkey);
40
+ OBJ_FREEZE(rkey); // frozen when used as a Hash key anyway
41
+ }
42
+ return rkey;
43
+ }
44
+ if (Yes == pi->options.sym_key) {
45
+ rkey = oj_sym_intern(parent->key, parent->klen);
46
+ } else {
47
+ rkey = oj_str_intern(parent->key, parent->klen);
24
48
  }
49
+ return rkey;
50
+ }
51
+
52
+ static void hash_end(ParseInfo pi) {
53
+ TRACE_PARSE_HASH_END(pi->options.trace, pi);
54
+ }
55
+
56
+ static void array_end(ParseInfo pi) {
57
+ TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
25
58
  }
26
59
 
27
60
  static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
@@ -29,20 +62,15 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
29
62
  }
30
63
 
31
64
  static void add_value(ParseInfo pi, VALUE val) {
32
- if (Yes == pi->options.trace) {
33
- oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, val);
34
- }
65
+ TRACE_PARSE_CALL(pi->options.trace, "add_value", pi, val);
35
66
  pi->stack.head->val = val;
36
67
  }
37
68
 
38
69
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
39
- volatile VALUE rstr = rb_str_new(str, len);
70
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
40
71
 
41
- rstr = oj_encode(rstr);
42
72
  pi->stack.head->val = rstr;
43
- if (Yes == pi->options.trace) {
44
- oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
45
- }
73
+ TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
46
74
  }
47
75
 
48
76
  static void add_num(ParseInfo pi, NumInfo ni) {
@@ -50,42 +78,22 @@ static void add_num(ParseInfo pi, NumInfo ni) {
50
78
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
51
79
  }
52
80
  pi->stack.head->val = oj_num_as_value(ni);
53
- if (Yes == pi->options.trace) {
54
- oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
55
- }
81
+ TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
56
82
  }
57
83
 
58
84
  static VALUE start_hash(ParseInfo pi) {
59
85
  if (Qnil != pi->options.hash_class) {
60
86
  return rb_class_new_instance(0, NULL, pi->options.hash_class);
61
87
  }
62
- if (Yes == pi->options.trace) {
63
- oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
64
- }
88
+ TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
65
89
  return rb_hash_new();
66
90
  }
67
91
 
68
- static VALUE calc_hash_key(ParseInfo pi, Val parent) {
69
- volatile VALUE rkey = parent->key_val;
70
-
71
- if (Qundef == rkey) {
72
- rkey = rb_str_new(parent->key, parent->klen);
73
- }
74
- rkey = oj_encode(rkey);
75
- if (Yes == pi->options.sym_key) {
76
- rkey = rb_str_intern(rkey);
77
- }
78
- return rkey;
79
- }
80
-
81
92
  static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
82
- volatile VALUE rstr = rb_str_new(str, len);
93
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
83
94
 
84
- rstr = oj_encode(rstr);
85
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), rstr);
86
- if (Yes == pi->options.trace) {
87
- oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
88
- }
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);
89
97
  }
90
98
 
91
99
  static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
@@ -95,34 +103,25 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
95
103
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
96
104
  }
97
105
  v = oj_num_as_value(ni);
98
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), v);
99
- if (Yes == pi->options.trace) {
100
- oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, v);
101
- }
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);
102
108
  }
103
109
 
104
110
  static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
105
- rb_hash_aset(stack_peek(&pi->stack)->val, calc_hash_key(pi, parent), value);
106
- if (Yes == pi->options.trace) {
107
- oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
108
- }
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);
109
113
  }
110
114
 
111
115
  static VALUE start_array(ParseInfo pi) {
112
- if (Yes == pi->options.trace) {
113
- oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
114
- }
116
+ TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
115
117
  return rb_ary_new();
116
118
  }
117
119
 
118
120
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
119
- volatile VALUE rstr = rb_str_new(str, len);
121
+ volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
120
122
 
121
- rstr = oj_encode(rstr);
122
123
  rb_ary_push(stack_peek(&pi->stack)->val, rstr);
123
- if (Yes == pi->options.trace) {
124
- oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
125
- }
124
+ TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
126
125
  }
127
126
 
128
127
  static void array_append_num(ParseInfo pi, NumInfo ni) {
@@ -133,16 +132,12 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
133
132
  }
134
133
  v = oj_num_as_value(ni);
135
134
  rb_ary_push(stack_peek(&pi->stack)->val, v);
136
- if (Yes == pi->options.trace) {
137
- oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, v);
138
- }
135
+ TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, v);
139
136
  }
140
137
 
141
138
  static void array_append_value(ParseInfo pi, VALUE value) {
142
139
  rb_ary_push(stack_peek(&pi->stack)->val, value);
143
- if (Yes == pi->options.trace) {
144
- oj_trace_parse_call("append_value", pi, __FILE__, __LINE__, value);
145
- }
140
+ TRACE_PARSE_CALL(pi->options.trace, "append_value", pi, value);
146
141
  }
147
142
 
148
143
  void oj_set_strict_callbacks(ParseInfo pi) {