oj 3.7.4 → 3.13.21

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 (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +809 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. data/ext/oj/hash_test.c +0 -512
data/ext/oj/dump_compat.c CHANGED
@@ -1,7 +1,5 @@
1
- /* dump_object.c
2
- * Copyright (c) 2012, 2017, Peter Ohler
3
- * All rights reserved.
4
- */
1
+ // Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
2
+ // Licensed under the MIT License. See LICENSE file in the project root for license details.
5
3
 
6
4
  #include "code.h"
7
5
  #include "dump.h"
@@ -34,21 +32,17 @@ dump_obj_classname(const char *classname, int depth, Out out) {
34
32
  *out->cur++ = '{';
35
33
  fill_indent(out, d2);
36
34
  *out->cur++ = '"';
37
- memcpy(out->cur, out->opts->create_id, out->opts->create_id_len);
38
- out->cur += out->opts->create_id_len;
35
+ APPEND_CHARS(out->cur, out->opts->create_id, out->opts->create_id_len);
39
36
  *out->cur++ = '"';
40
37
  if (0 < out->opts->dump_opts.before_size) {
41
- strcpy(out->cur, out->opts->dump_opts.before_sep);
42
- out->cur += out->opts->dump_opts.before_size;
38
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
43
39
  }
44
40
  *out->cur++ = ':';
45
41
  if (0 < out->opts->dump_opts.after_size) {
46
- strcpy(out->cur, out->opts->dump_opts.after_sep);
47
- out->cur += out->opts->dump_opts.after_size;
42
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
48
43
  }
49
44
  *out->cur++ = '"';
50
- memcpy(out->cur, classname, len);
51
- out->cur += len;
45
+ APPEND_CHARS(out->cur, classname, len);
52
46
  *out->cur++ = '"';
53
47
  }
54
48
 
@@ -64,25 +58,22 @@ dump_values_array(VALUE *values, int depth, Out out) {
64
58
  } else {
65
59
  if (out->opts->dump_opts.use) {
66
60
  size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 2;
67
- } else {
68
- size = d2 * out->indent + 3;
69
- }
70
- if (out->opts->dump_opts.use) {
71
61
  size += out->opts->dump_opts.array_size;
72
62
  size += out->opts->dump_opts.indent_size;
63
+ } else {
64
+ size = d2 * out->indent + 3;
73
65
  }
74
66
  for (; Qundef != *values; values++) {
75
67
  assure_size(out, size);
76
68
  if (out->opts->dump_opts.use) {
77
69
  if (0 < out->opts->dump_opts.array_size) {
78
- strcpy(out->cur, out->opts->dump_opts.array_nl);
79
- out->cur += out->opts->dump_opts.array_size;
70
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
80
71
  }
81
72
  if (0 < out->opts->dump_opts.indent_size) {
82
73
  int i;
74
+
83
75
  for (i = d2; 0 < i; i--) {
84
- strcpy(out->cur, out->opts->dump_opts.indent_str);
85
- out->cur += out->opts->dump_opts.indent_size;
76
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
86
77
  }
87
78
  }
88
79
  } else {
@@ -96,15 +87,13 @@ dump_values_array(VALUE *values, int depth, Out out) {
96
87
  assure_size(out, size);
97
88
  if (out->opts->dump_opts.use) {
98
89
  if (0 < out->opts->dump_opts.array_size) {
99
- strcpy(out->cur, out->opts->dump_opts.array_nl);
100
- out->cur += out->opts->dump_opts.array_size;
90
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
101
91
  }
102
92
  if (0 < out->opts->dump_opts.indent_size) {
103
93
  int i;
104
94
 
105
95
  for (i = depth; 0 < i; i--) {
106
- strcpy(out->cur, out->opts->dump_opts.indent_str);
107
- out->cur += out->opts->dump_opts.indent_size;
96
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
108
97
  }
109
98
  }
110
99
  } else {
@@ -120,7 +109,7 @@ dump_to_json(VALUE obj, Out out) {
120
109
  const char *s;
121
110
  int len;
122
111
 
123
- if (Yes == out->opts->trace) {
112
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
124
113
  oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
125
114
  }
126
115
  if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
@@ -128,16 +117,15 @@ dump_to_json(VALUE obj, Out out) {
128
117
  } else {
129
118
  rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
130
119
  }
131
- if (Yes == out->opts->trace) {
120
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
132
121
  oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
133
122
  }
134
123
 
135
- s = rb_string_value_ptr((VALUE*)&rs);
124
+ s = RSTRING_PTR(rs);
136
125
  len = (int)RSTRING_LEN(rs);
137
126
 
138
127
  assure_size(out, len + 1);
139
- memcpy(out->cur, s, len);
140
- out->cur += len;
128
+ APPEND_CHARS(out->cur, s, len);
141
129
  *out->cur = '\0';
142
130
  }
143
131
 
@@ -155,7 +143,7 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
155
143
  if (as_ok && !oj_use_hash_alt && rb_obj_class(a) != rb_cArray && rb_respond_to(a, oj_to_json_id)) {
156
144
  dump_to_json(a, out);
157
145
  return;
158
- }
146
+ }
159
147
  cnt = (int)RARRAY_LEN(a);
160
148
  *out->cur++ = '[';
161
149
  assure_size(out, 2);
@@ -167,45 +155,43 @@ dump_array(VALUE a, int depth, Out out, bool as_ok) {
167
155
  } else {
168
156
  size = d2 * out->indent + 2;
169
157
  }
158
+ assure_size(out, size * cnt);
170
159
  cnt--;
171
160
  for (i = 0; i <= cnt; i++) {
172
- assure_size(out, size);
173
161
  if (out->opts->dump_opts.use) {
174
162
  if (0 < out->opts->dump_opts.array_size) {
175
- strcpy(out->cur, out->opts->dump_opts.array_nl);
176
- out->cur += out->opts->dump_opts.array_size;
163
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
177
164
  }
178
165
  if (0 < out->opts->dump_opts.indent_size) {
179
166
  int i;
180
167
  for (i = d2; 0 < i; i--) {
181
- strcpy(out->cur, out->opts->dump_opts.indent_str);
182
- out->cur += out->opts->dump_opts.indent_size;
168
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
183
169
  }
184
170
  }
185
171
  } else {
186
172
  fill_indent(out, d2);
187
173
  }
188
- oj_dump_compat_val(rb_ary_entry(a, i), d2, out, true);
174
+ oj_dump_compat_val(RARRAY_AREF(a, i), d2, out, true);
189
175
  if (i < cnt) {
190
176
  *out->cur++ = ',';
191
177
  }
192
178
  }
193
- size = depth * out->indent + 1;
194
- assure_size(out, size);
195
179
  if (out->opts->dump_opts.use) {
180
+ size = out->opts->dump_opts.array_size + out->opts->dump_opts.indent_size * depth + 1;
181
+ assure_size(out, size);
196
182
  if (0 < out->opts->dump_opts.array_size) {
197
- strcpy(out->cur, out->opts->dump_opts.array_nl);
198
- out->cur += out->opts->dump_opts.array_size;
183
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
199
184
  }
200
185
  if (0 < out->opts->dump_opts.indent_size) {
201
186
  int i;
202
187
 
203
188
  for (i = depth; 0 < i; i--) {
204
- strcpy(out->cur, out->opts->dump_opts.indent_str);
205
- out->cur += out->opts->dump_opts.indent_size;
189
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
206
190
  }
207
191
  }
208
192
  } else {
193
+ size = depth * out->indent + 1;
194
+ assure_size(out, size);
209
195
  fill_indent(out, depth);
210
196
  }
211
197
  *out->cur++ = ']';
@@ -217,7 +203,7 @@ static ID _dump_id = 0;
217
203
 
218
204
  static void
219
205
  bigdecimal_alt(VALUE obj, int depth, Out out) {
220
- struct _Attr attrs[] = {
206
+ struct _attr attrs[] = {
221
207
  { "b", 1, Qnil },
222
208
  { NULL, 0, Qnil },
223
209
  };
@@ -235,7 +221,7 @@ static ID imag_id = 0;
235
221
 
236
222
  static void
237
223
  complex_alt(VALUE obj, int depth, Out out) {
238
- struct _Attr attrs[] = {
224
+ struct _attr attrs[] = {
239
225
  { "r", 1, Qnil },
240
226
  { "i", 1, Qnil },
241
227
  { NULL, 0, Qnil },
@@ -258,7 +244,7 @@ static ID start_id = 0;
258
244
 
259
245
  static void
260
246
  date_alt(VALUE obj, int depth, Out out) {
261
- struct _Attr attrs[] = {
247
+ struct _attr attrs[] = {
262
248
  { "y", 1, Qnil },
263
249
  { "m", 1, Qnil },
264
250
  { "d", 1, Qnil },
@@ -286,7 +272,7 @@ static ID offset_id = 0;
286
272
 
287
273
  static void
288
274
  datetime_alt(VALUE obj, int depth, Out out) {
289
- struct _Attr attrs[] = {
275
+ struct _attr attrs[] = {
290
276
  { "y", 1, Qnil },
291
277
  { "m", 1, Qnil },
292
278
  { "d", 1, Qnil },
@@ -337,33 +323,25 @@ exception_alt(VALUE obj, int depth, Out out) {
337
323
  assure_size(out, size + sep_len + 6);
338
324
  *out->cur++ = ',';
339
325
  fill_indent(out, d3);
340
- *out->cur++ = '"';
341
- *out->cur++ = 'm';
342
- *out->cur++ = '"';
326
+ APPEND_CHARS(out->cur, "\"m\"", 3);
343
327
  if (0 < out->opts->dump_opts.before_size) {
344
- strcpy(out->cur, out->opts->dump_opts.before_sep);
345
- out->cur += out->opts->dump_opts.before_size;
328
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
346
329
  }
347
330
  *out->cur++ = ':';
348
331
  if (0 < out->opts->dump_opts.after_size) {
349
- strcpy(out->cur, out->opts->dump_opts.after_sep);
350
- out->cur += out->opts->dump_opts.after_size;
332
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
351
333
  }
352
334
  oj_dump_str(rb_funcall(obj, message_id, 0), 0, out, false);
353
335
  assure_size(out, size + sep_len + 6);
354
336
  *out->cur++ = ',';
355
337
  fill_indent(out, d3);
356
- *out->cur++ = '"';
357
- *out->cur++ = 'b';
358
- *out->cur++ = '"';
338
+ APPEND_CHARS(out->cur, "\"b\"", 3);
359
339
  if (0 < out->opts->dump_opts.before_size) {
360
- strcpy(out->cur, out->opts->dump_opts.before_sep);
361
- out->cur += out->opts->dump_opts.before_size;
340
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
362
341
  }
363
342
  *out->cur++ = ':';
364
343
  if (0 < out->opts->dump_opts.after_size) {
365
- strcpy(out->cur, out->opts->dump_opts.after_sep);
366
- out->cur += out->opts->dump_opts.after_size;
344
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
367
345
  }
368
346
  dump_array(rb_funcall(obj, backtrace_id, 0), depth, out, false);
369
347
  fill_indent(out, depth);
@@ -375,7 +353,7 @@ static ID table_id = 0;
375
353
 
376
354
  static void
377
355
  openstruct_alt(VALUE obj, int depth, Out out) {
378
- struct _Attr attrs[] = {
356
+ struct _attr attrs[] = {
379
357
  { "t", 1, Qnil },
380
358
  { NULL, 0, Qnil },
381
359
  };
@@ -399,17 +377,13 @@ range_alt(VALUE obj, int depth, Out out) {
399
377
  assure_size(out, size + sep_len + 6);
400
378
  *out->cur++ = ',';
401
379
  fill_indent(out, d3);
402
- *out->cur++ = '"';
403
- *out->cur++ = 'a';
404
- *out->cur++ = '"';
380
+ APPEND_CHARS(out->cur, "\"a\"", 3);
405
381
  if (0 < out->opts->dump_opts.before_size) {
406
- strcpy(out->cur, out->opts->dump_opts.before_sep);
407
- out->cur += out->opts->dump_opts.before_size;
382
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
408
383
  }
409
384
  *out->cur++ = ':';
410
385
  if (0 < out->opts->dump_opts.after_size) {
411
- strcpy(out->cur, out->opts->dump_opts.after_sep);
412
- out->cur += out->opts->dump_opts.after_size;
386
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
413
387
  }
414
388
  args[0] = rb_funcall(obj, oj_begin_id, 0);
415
389
  args[1] = rb_funcall(obj, oj_end_id, 0);
@@ -425,7 +399,7 @@ static ID denominator_id = 0;
425
399
 
426
400
  static void
427
401
  rational_alt(VALUE obj, int depth, Out out) {
428
- struct _Attr attrs[] = {
402
+ struct _attr attrs[] = {
429
403
  { "n", 1, Qnil },
430
404
  { "d", 1, Qnil },
431
405
  { NULL, 0, Qnil },
@@ -445,7 +419,7 @@ static ID source_id = 0;
445
419
 
446
420
  static void
447
421
  regexp_alt(VALUE obj, int depth, Out out) {
448
- struct _Attr attrs[] = {
422
+ struct _attr attrs[] = {
449
423
  { "o", 1, Qnil },
450
424
  { "s", 1, Qnil },
451
425
  { NULL, 0, Qnil },
@@ -462,7 +436,7 @@ regexp_alt(VALUE obj, int depth, Out out) {
462
436
 
463
437
  static void
464
438
  time_alt(VALUE obj, int depth, Out out) {
465
- struct _Attr attrs[] = {
439
+ struct _attr attrs[] = {
466
440
  { "s", 1, Qundef, 0, Qundef },
467
441
  { "n", 1, Qundef, 0, Qundef },
468
442
  { NULL, 0, Qnil },
@@ -470,16 +444,15 @@ time_alt(VALUE obj, int depth, Out out) {
470
444
  time_t sec;
471
445
  long long nsec;
472
446
 
473
- #ifdef HAVE_RB_TIME_TIMESPEC
474
- {
447
+ if (16 <= sizeof(struct timespec)) {
475
448
  struct timespec ts = rb_time_timespec(obj);
476
- sec = ts.tv_sec;
449
+
450
+ sec = (long long)ts.tv_sec;
477
451
  nsec = ts.tv_nsec;
452
+ } else {
453
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
454
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
478
455
  }
479
- #else
480
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
481
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
482
- #endif
483
456
 
484
457
  attrs[0].num = sec;
485
458
  attrs[1].num = nsec;
@@ -487,7 +460,7 @@ time_alt(VALUE obj, int depth, Out out) {
487
460
  oj_code_attrs(obj, attrs, depth, out, true);
488
461
  }
489
462
 
490
- struct _Code oj_compat_codes[] = {
463
+ struct _code oj_compat_codes[] = {
491
464
  { "BigDecimal", Qnil, bigdecimal_alt, NULL, false },
492
465
  { "Complex", Qnil, complex_alt, NULL, false },
493
466
  { "Date", Qnil, date_alt, false },
@@ -610,18 +583,21 @@ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
610
583
  } else if (OJ_INFINITY == d) {
611
584
  if (WordNan == out->opts->dump_opts.nan_dump) {
612
585
  strcpy(buf, "Infinity");
586
+ cnt = 8;
613
587
  } else {
614
588
  raise_json_err("Infinity not allowed in JSON.", "GeneratorError");
615
589
  }
616
590
  } else if (-OJ_INFINITY == d) {
617
591
  if (WordNan == out->opts->dump_opts.nan_dump) {
618
592
  strcpy(buf, "-Infinity");
593
+ cnt = 9;
619
594
  } else {
620
595
  raise_json_err("-Infinity not allowed in JSON.", "GeneratorError");
621
596
  }
622
597
  } else if (isnan(d)) {
623
598
  if (WordNan == out->opts->dump_opts.nan_dump) {
624
599
  strcpy(buf, "NaN");
600
+ cnt = 3;
625
601
  } else {
626
602
  raise_json_err("NaN not allowed in JSON.", "GeneratorError");
627
603
  }
@@ -632,18 +608,17 @@ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
632
608
  } else {
633
609
  volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
634
610
 
635
- strcpy(buf, rb_string_value_ptr((VALUE*)&rstr));
611
+ strcpy(buf, RSTRING_PTR(rstr));
636
612
  cnt = (int)RSTRING_LEN(rstr);
637
613
  }
638
614
  assure_size(out, cnt);
639
- for (b = buf; '\0' != *b; b++) {
640
- *out->cur++ = *b;
641
- }
615
+ APPEND_CHARS(out->cur, buf, cnt);
642
616
  *out->cur = '\0';
643
617
  }
644
618
 
645
619
  static int
646
- hash_cb(VALUE key, VALUE value, Out out) {
620
+ hash_cb(VALUE key, VALUE value, VALUE ov) {
621
+ Out out = (Out)ov;
647
622
  int depth = out->depth;
648
623
 
649
624
  if (out->omit_nil && Qnil == value) {
@@ -655,14 +630,12 @@ hash_cb(VALUE key, VALUE value, Out out) {
655
630
  } else {
656
631
  assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
657
632
  if (0 < out->opts->dump_opts.hash_size) {
658
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
659
- out->cur += out->opts->dump_opts.hash_size;
633
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
660
634
  }
661
635
  if (0 < out->opts->dump_opts.indent_size) {
662
636
  int i;
663
637
  for (i = depth; 0 < i; i--) {
664
- strcpy(out->cur, out->opts->dump_opts.indent_str);
665
- out->cur += out->opts->dump_opts.indent_size;
638
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
666
639
  }
667
640
  }
668
641
  }
@@ -683,13 +656,11 @@ hash_cb(VALUE key, VALUE value, Out out) {
683
656
  } else {
684
657
  assure_size(out, out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2);
685
658
  if (0 < out->opts->dump_opts.before_size) {
686
- strcpy(out->cur, out->opts->dump_opts.before_sep);
687
- out->cur += out->opts->dump_opts.before_size;
659
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
688
660
  }
689
661
  *out->cur++ = ':';
690
662
  if (0 < out->opts->dump_opts.after_size) {
691
- strcpy(out->cur, out->opts->dump_opts.after_sep);
692
- out->cur += out->opts->dump_opts.after_size;
663
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
693
664
  }
694
665
  }
695
666
  oj_dump_compat_val(value, depth, out, true);
@@ -711,12 +682,11 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
711
682
  if (as_ok && !oj_use_hash_alt && rb_obj_class(obj) != rb_cHash && rb_respond_to(obj, oj_to_json_id)) {
712
683
  dump_to_json(obj, out);
713
684
  return;
714
- }
685
+ }
715
686
  cnt = (int)RHASH_SIZE(obj);
716
687
  assure_size(out, 2);
717
688
  if (0 == cnt) {
718
- *out->cur++ = '{';
719
- *out->cur++ = '}';
689
+ APPEND_CHARS(out->cur, "{}", 2);
720
690
  } else {
721
691
  *out->cur++ = '{';
722
692
  out->depth = depth + 1;
@@ -730,15 +700,13 @@ dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
730
700
  } else {
731
701
  assure_size(out, depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1);
732
702
  if (0 < out->opts->dump_opts.hash_size) {
733
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
734
- out->cur += out->opts->dump_opts.hash_size;
703
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
735
704
  }
736
705
  if (0 < out->opts->dump_opts.indent_size) {
737
706
  int i;
738
707
 
739
708
  for (i = depth; 0 < i; i--) {
740
- strcpy(out->cur, out->opts->dump_opts.indent_str);
741
- out->cur += out->opts->dump_opts.indent_size;
709
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
742
710
  }
743
711
  }
744
712
  }
@@ -758,9 +726,12 @@ dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
758
726
  exception_alt(obj, depth, out);
759
727
  return;
760
728
  }
729
+ if (Yes == out->opts->raw_json && rb_respond_to(obj, oj_raw_json_id)) {
730
+ oj_dump_raw_json(obj, depth, out);
731
+ return;
732
+ }
761
733
  if (as_ok && rb_respond_to(obj, oj_to_json_id)) {
762
734
  dump_to_json(obj, out);
763
-
764
735
  return;
765
736
  }
766
737
  // Nothing else matched so encode as a JSON object with Ruby obj members
@@ -779,8 +750,7 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
779
750
  *out->cur++ = '"';
780
751
  oj_dump_compat_val(rb_funcall(obj, oj_begin_id, 0), 0, out, false);
781
752
  assure_size(out, 3);
782
- *out->cur++ = '.';
783
- *out->cur++ = '.';
753
+ APPEND_CHARS(out->cur, "..", 2);
784
754
  if (Qtrue == rb_funcall(obj, oj_exclude_end_id, 0)) {
785
755
  *out->cur++ = '.';
786
756
  }
@@ -826,17 +796,13 @@ dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
826
796
  assure_size(out, size + sep_len + 6);
827
797
  *out->cur++ = ',';
828
798
  fill_indent(out, d3);
829
- *out->cur++ = '"';
830
- *out->cur++ = 'v';
831
- *out->cur++ = '"';
799
+ APPEND_CHARS(out->cur, "\"v\"", 3);
832
800
  if (0 < out->opts->dump_opts.before_size) {
833
- strcpy(out->cur, out->opts->dump_opts.before_sep);
834
- out->cur += out->opts->dump_opts.before_size;
801
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
835
802
  }
836
803
  *out->cur++ = ':';
837
804
  if (0 < out->opts->dump_opts.after_size) {
838
- strcpy(out->cur, out->opts->dump_opts.after_sep);
839
- out->cur += out->opts->dump_opts.after_size;
805
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
840
806
  }
841
807
  for (i = 0; i < cnt; i++) {
842
808
  #ifdef RSTRUCT_LEN
@@ -862,7 +828,7 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
862
828
  // this must use to_s to pass the json gem unit tests.
863
829
  volatile VALUE rs;
864
830
  int cnt;
865
- bool dump_as_string = false;
831
+ bool dump_as_string = false;
866
832
 
867
833
  if (use_bignum_alt) {
868
834
  rs = rb_big2str(obj, 10);
@@ -872,21 +838,17 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
872
838
  rb_check_type(rs, T_STRING);
873
839
  cnt = (int)RSTRING_LEN(rs);
874
840
 
875
- if (out->opts->integer_range_min != 0 || out->opts->integer_range_max != 0) {
841
+ if (out->opts->int_range_min != 0 || out->opts->int_range_max != 0) {
876
842
  dump_as_string = true; // Bignum cannot be inside of Fixnum range
877
843
  assure_size(out, cnt + 2);
878
844
  *out->cur++ = '"';
879
- } else {
845
+ } else {
880
846
  assure_size(out, cnt);
881
- }
882
-
883
- memcpy(out->cur, rb_string_value_ptr((VALUE*)&rs), cnt);
884
- out->cur += cnt;
885
-
886
- if(dump_as_string) {
847
+ }
848
+ APPEND_CHARS(out->cur, RSTRING_PTR(rs), cnt);
849
+ if (dump_as_string) {
887
850
  *out->cur++ = '"';
888
- }
889
-
851
+ }
890
852
  *out->cur = '\0';
891
853
  }
892
854
 
@@ -931,7 +893,7 @@ void
931
893
  oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
932
894
  int type = rb_type(obj);
933
895
 
934
- if (Yes == out->opts->trace) {
896
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
935
897
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
936
898
  }
937
899
  if (out->opts->dump_opts.max_depth <= depth) {
@@ -956,14 +918,14 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
956
918
 
957
919
  if (NULL != f) {
958
920
  f(obj, depth, out, as_ok);
959
- if (Yes == out->opts->trace) {
921
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
960
922
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
961
923
  }
962
924
  return;
963
925
  }
964
926
  }
965
927
  oj_dump_nil(Qnil, depth, out, false);
966
- if (Yes == out->opts->trace) {
928
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
967
929
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
968
930
  }
969
931
  }