oj 3.7.4 → 3.13.21

Sign up to get free protection for your applications and to get access to all the features.
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
  }