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/rails.c CHANGED
@@ -5,6 +5,7 @@
5
5
 
6
6
  #include "code.h"
7
7
  #include "encode.h"
8
+ #include "mem.h"
8
9
  #include "trace.h"
9
10
  #include "util.h"
10
11
 
@@ -15,7 +16,7 @@ typedef struct _encoder {
15
16
  struct _rOptTable ropts;
16
17
  struct _options opts;
17
18
  VALUE arg;
18
- } * Encoder;
19
+ } *Encoder;
19
20
 
20
21
  bool oj_rails_hash_opt = false;
21
22
  bool oj_rails_array_opt = false;
@@ -76,7 +77,7 @@ static ROptTable copy_opts(ROptTable src, ROptTable dest) {
76
77
  if (NULL == src->table) {
77
78
  dest->table = NULL;
78
79
  } else {
79
- dest->table = ALLOC_N(struct _rOpt, dest->alen);
80
+ dest->table = OJ_R_ALLOC_N(struct _rOpt, dest->alen);
80
81
  memcpy(dest->table, src->table, sizeof(struct _rOpt) * dest->alen);
81
82
  }
82
83
  return NULL;
@@ -140,7 +141,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
140
141
  int cnt;
141
142
  int i;
142
143
  int len;
143
- const char * name;
144
+ const char *name;
144
145
 
145
146
  #ifdef RSTRUCT_LEN
146
147
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
@@ -157,9 +158,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
157
158
  assure_size(out, 2);
158
159
  *out->cur++ = '{';
159
160
  for (i = 0; i < cnt; i++) {
160
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
161
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
161
162
 
162
- name = rb_string_value_ptr((VALUE *)&s);
163
+ name = RSTRING_PTR(s);
163
164
  len = (int)RSTRING_LEN(s);
164
165
  assure_size(out, size + sep_len + 6);
165
166
  if (0 < i) {
@@ -167,17 +168,14 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
167
168
  }
168
169
  fill_indent(out, d3);
169
170
  *out->cur++ = '"';
170
- memcpy(out->cur, name, len);
171
- out->cur += len;
171
+ APPEND_CHARS(out->cur, name, len);
172
172
  *out->cur++ = '"';
173
173
  if (0 < out->opts->dump_opts.before_size) {
174
- strcpy(out->cur, out->opts->dump_opts.before_sep);
175
- out->cur += out->opts->dump_opts.before_size;
174
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
176
175
  }
177
176
  *out->cur++ = ':';
178
177
  if (0 < out->opts->dump_opts.after_size) {
179
- strcpy(out->cur, out->opts->dump_opts.after_sep);
180
- out->cur += out->opts->dump_opts.after_size;
178
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
181
179
  }
182
180
  #ifdef RSTRUCT_LEN
183
181
  v = RSTRUCT_GET(obj, i);
@@ -201,8 +199,8 @@ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
201
199
  }
202
200
 
203
201
  static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
204
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
205
- const char * str = rb_string_value_ptr((VALUE *)&rstr);
202
+ volatile VALUE rstr = oj_safe_string_convert(obj);
203
+ const char *str = RSTRING_PTR(rstr);
206
204
 
207
205
  if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
208
206
  oj_dump_nil(Qnil, depth, out, false);
@@ -265,14 +263,7 @@ static void dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
265
263
  tzmin);
266
264
  } else if (0 == out->opts->sec_prec) {
267
265
  if (0 == tzsecs && rb_funcall2(obj, oj_utcq_id, 0, 0)) {
268
- len = sprintf(buf,
269
- "%04d-%02d-%02dT%02d:%02d:%02dZ",
270
- ti.year,
271
- ti.mon,
272
- ti.day,
273
- ti.hour,
274
- ti.min,
275
- ti.sec);
266
+ len = sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02dZ", ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec);
276
267
  } else {
277
268
  len = sprintf(buf,
278
269
  "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
@@ -303,18 +294,7 @@ static void dump_sec_nano(VALUE obj, int64_t sec, long nsec, Out out) {
303
294
  format[32] = '0' + out->opts->sec_prec;
304
295
  len -= 9 - out->opts->sec_prec;
305
296
  }
306
- len = sprintf(buf,
307
- format,
308
- ti.year,
309
- ti.mon,
310
- ti.day,
311
- ti.hour,
312
- ti.min,
313
- ti.sec,
314
- nsec,
315
- tzsign,
316
- tzhour,
317
- tzmin);
297
+ len = sprintf(buf, format, ti.year, ti.mon, ti.day, ti.hour, ti.min, ti.sec, nsec, tzsign, tzhour, tzmin);
318
298
  }
319
299
  oj_dump_cstr(buf, len, 0, 0, out);
320
300
  }
@@ -323,20 +303,15 @@ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
323
303
  long long sec;
324
304
  long long nsec;
325
305
 
326
- #ifdef HAVE_RB_TIME_TIMESPEC
327
306
  if (16 <= sizeof(struct timespec)) {
328
307
  struct timespec ts = rb_time_timespec(obj);
329
308
 
330
309
  sec = (long long)ts.tv_sec;
331
310
  nsec = ts.tv_nsec;
332
311
  } else {
333
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
334
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
312
+ sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
313
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
335
314
  }
336
- #else
337
- sec = rb_num2ll(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
338
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
339
- #endif
340
315
  dump_sec_nano(obj, sec, nsec, out);
341
316
  }
342
317
 
@@ -345,17 +320,17 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
345
320
  long long nsec = 0;
346
321
 
347
322
  if (rb_respond_to(obj, oj_tv_nsec_id)) {
348
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
323
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
349
324
  } else if (rb_respond_to(obj, oj_tv_usec_id)) {
350
- nsec = rb_num2ll(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
325
+ nsec = NUM2LL(rb_funcall2(obj, oj_tv_usec_id, 0, 0)) * 1000;
351
326
  }
352
327
  dump_sec_nano(obj, sec, nsec, out);
353
328
  }
354
329
 
355
330
  static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
356
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
331
+ volatile VALUE rstr = oj_safe_string_convert(obj);
357
332
 
358
- oj_dump_cstr(rb_string_value_ptr((VALUE *)&rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
333
+ oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
359
334
  }
360
335
 
361
336
  static ID parameters_id = 0;
@@ -363,7 +338,7 @@ static ID parameters_id = 0;
363
338
  typedef struct _strLen {
364
339
  const char *str;
365
340
  int len;
366
- } * StrLen;
341
+ } *StrLen;
367
342
 
368
343
  static void dump_actioncontroller_parameters(VALUE obj, int depth, Out out, bool as_ok) {
369
344
  if (0 == parameters_id) {
@@ -381,11 +356,11 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
381
356
  int cnt = (int)RARRAY_LEN(rcols);
382
357
 
383
358
  *ccnt = cnt;
384
- cols = ALLOC_N(struct _strLen, cnt);
359
+ cols = OJ_R_ALLOC_N(struct _strLen, cnt);
385
360
  for (i = 0, cp = cols; i < cnt; i++, cp++) {
386
- v = rb_ary_entry(rcols, i);
361
+ v = RARRAY_AREF(rcols, i);
387
362
  if (T_STRING != rb_type(v)) {
388
- v = rb_funcall(v, oj_to_s_id, 0);
363
+ v = oj_safe_string_convert(v);
389
364
  }
390
365
  cp->str = StringValuePtr(v);
391
366
  cp->len = (int)RSTRING_LEN(v);
@@ -405,14 +380,12 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
405
380
  assure_size(out, size);
406
381
  if (out->opts->dump_opts.use) {
407
382
  if (0 < out->opts->dump_opts.array_size) {
408
- strcpy(out->cur, out->opts->dump_opts.array_nl);
409
- out->cur += out->opts->dump_opts.array_size;
383
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
410
384
  }
411
385
  if (0 < out->opts->dump_opts.indent_size) {
412
386
  int i;
413
387
  for (i = d2; 0 < i; i--) {
414
- strcpy(out->cur, out->opts->dump_opts.indent_str);
415
- out->cur += out->opts->dump_opts.indent_size;
388
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
416
389
  }
417
390
  }
418
391
  } else {
@@ -420,7 +393,7 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
420
393
  }
421
394
  oj_dump_cstr(cols->str, cols->len, 0, 0, out);
422
395
  *out->cur++ = ':';
423
- dump_rails_val(rb_ary_entry(row, i), depth, out, true);
396
+ dump_rails_val(RARRAY_AREF(row, i), depth, out, true);
424
397
  if (i < ccnt - 1) {
425
398
  *out->cur++ = ',';
426
399
  }
@@ -429,15 +402,13 @@ static void dump_row(VALUE row, StrLen cols, int ccnt, int depth, Out out) {
429
402
  assure_size(out, size);
430
403
  if (out->opts->dump_opts.use) {
431
404
  if (0 < out->opts->dump_opts.array_size) {
432
- strcpy(out->cur, out->opts->dump_opts.array_nl);
433
- out->cur += out->opts->dump_opts.array_size;
405
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
434
406
  }
435
407
  if (0 < out->opts->dump_opts.indent_size) {
436
408
  int i;
437
409
 
438
410
  for (i = depth; 0 < i; i--) {
439
- strcpy(out->cur, out->opts->dump_opts.indent_str);
440
- out->cur += out->opts->dump_opts.indent_size;
411
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
441
412
  }
442
413
  }
443
414
  } else {
@@ -477,38 +448,34 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
477
448
  assure_size(out, size);
478
449
  if (out->opts->dump_opts.use) {
479
450
  if (0 < out->opts->dump_opts.array_size) {
480
- strcpy(out->cur, out->opts->dump_opts.array_nl);
481
- out->cur += out->opts->dump_opts.array_size;
451
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
482
452
  }
483
453
  if (0 < out->opts->dump_opts.indent_size) {
484
454
  int i;
485
455
  for (i = d2; 0 < i; i--) {
486
- strcpy(out->cur, out->opts->dump_opts.indent_str);
487
- out->cur += out->opts->dump_opts.indent_size;
456
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
488
457
  }
489
458
  }
490
459
  } else {
491
460
  fill_indent(out, d2);
492
461
  }
493
- dump_row(rb_ary_entry(rows, i), cols, ccnt, d2, out);
462
+ dump_row(RARRAY_AREF(rows, i), cols, ccnt, d2, out);
494
463
  if (i < rcnt - 1) {
495
464
  *out->cur++ = ',';
496
465
  }
497
466
  }
498
- xfree(cols);
467
+ OJ_R_FREE(cols);
499
468
  size = depth * out->indent + 1;
500
469
  assure_size(out, size);
501
470
  if (out->opts->dump_opts.use) {
502
471
  if (0 < out->opts->dump_opts.array_size) {
503
- strcpy(out->cur, out->opts->dump_opts.array_nl);
504
- out->cur += out->opts->dump_opts.array_size;
472
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
505
473
  }
506
474
  if (0 < out->opts->dump_opts.indent_size) {
507
475
  int i;
508
476
 
509
477
  for (i = depth; 0 < i; i--) {
510
- strcpy(out->cur, out->opts->dump_opts.indent_str);
511
- out->cur += out->opts->dump_opts.indent_size;
478
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
512
479
  }
513
480
  }
514
481
  } else {
@@ -520,7 +487,7 @@ static void dump_activerecord_result(VALUE obj, int depth, Out out, bool as_ok)
520
487
  typedef struct _namedFunc {
521
488
  const char *name;
522
489
  DumpFunc func;
523
- } * NamedFunc;
490
+ } *NamedFunc;
524
491
 
525
492
  static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
526
493
  if (oj_code_dump(oj_compat_codes, obj, depth, out)) {
@@ -533,9 +500,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
533
500
  static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
534
501
  volatile VALUE ja;
535
502
 
536
- if (Yes == out->opts->trace) {
537
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
538
- }
503
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
539
504
  // Some classes elect to not take an options argument so check the arity
540
505
  // of as_json.
541
506
  if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
@@ -543,9 +508,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
543
508
  } else {
544
509
  ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
545
510
  }
546
- if (Yes == out->opts->trace) {
547
- oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
548
- }
511
+ TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
549
512
 
550
513
  out->argc = 0;
551
514
  if (ja == obj || !as_ok) {
@@ -603,11 +566,11 @@ static ROpt create_opt(ROptTable rot, VALUE clas) {
603
566
  rot->len++;
604
567
  if (NULL == rot->table) {
605
568
  rot->alen = 256;
606
- rot->table = ALLOC_N(struct _rOpt, rot->alen);
569
+ rot->table = OJ_R_ALLOC_N(struct _rOpt, rot->alen);
607
570
  memset(rot->table, 0, sizeof(struct _rOpt) * rot->alen);
608
571
  } else if (rot->alen <= rot->len) {
609
572
  rot->alen *= 2;
610
- REALLOC_N(rot->table, struct _rOpt, rot->alen);
573
+ OJ_R_REALLOC_N(rot->table, struct _rOpt, rot->alen);
611
574
  memset(rot->table + olen, 0, sizeof(struct _rOpt) * olen);
612
575
  }
613
576
  if (0 == olen) {
@@ -660,9 +623,9 @@ static void encoder_free(void *ptr) {
660
623
  Encoder e = (Encoder)ptr;
661
624
 
662
625
  if (NULL != e->ropts.table) {
663
- xfree(e->ropts.table);
626
+ OJ_R_FREE(e->ropts.table);
664
627
  }
665
- xfree(ptr);
628
+ OJ_R_FREE(ptr);
666
629
  }
667
630
  }
668
631
 
@@ -676,6 +639,17 @@ static void encoder_mark(void *ptr) {
676
639
  }
677
640
  }
678
641
 
642
+ static const rb_data_type_t oj_encoder_type = {
643
+ "Oj/encoder",
644
+ {
645
+ encoder_mark,
646
+ encoder_free,
647
+ NULL,
648
+ },
649
+ 0,
650
+ 0,
651
+ };
652
+
679
653
  /* Document-method: new
680
654
  * call-seq: new(options=nil)
681
655
  *
@@ -683,7 +657,7 @@ static void encoder_mark(void *ptr) {
683
657
  * - *options* [_Hash_] formatting options
684
658
  */
685
659
  static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
686
- Encoder e = ALLOC(struct _encoder);
660
+ Encoder e = OJ_R_ALLOC(struct _encoder);
687
661
 
688
662
  e->opts = oj_default_options;
689
663
  e->arg = Qnil;
@@ -693,14 +667,14 @@ static VALUE encoder_new(int argc, VALUE *argv, VALUE self) {
693
667
  oj_parse_options(*argv, &e->opts);
694
668
  e->arg = *argv;
695
669
  }
696
- return Data_Wrap_Struct(encoder_class, encoder_mark, encoder_free, e);
670
+ return TypedData_Wrap_Struct(encoder_class, &oj_encoder_type, e);
697
671
  }
698
672
 
699
673
  static VALUE resolve_classpath(const char *name) {
700
674
  char class_name[1024];
701
675
  VALUE clas;
702
- char * end = class_name + sizeof(class_name) - 1;
703
- char * s;
676
+ char *end = class_name + sizeof(class_name) - 1;
677
+ char *s;
704
678
  const char *n = name;
705
679
  ID cid;
706
680
 
@@ -766,8 +740,7 @@ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
766
740
  oj_rails_float_opt = on;
767
741
  } else if (oj_string_writer_class == *argv) {
768
742
  string_writer_optimized = on;
769
- } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) ||
770
- NULL != (ro = create_opt(rot, *argv))) {
743
+ } else if (NULL != (ro = oj_rails_get_opt(rot, *argv)) || NULL != (ro = create_opt(rot, *argv))) {
771
744
  ro->on = on;
772
745
  }
773
746
  }
@@ -786,7 +759,8 @@ static void optimize(int argc, VALUE *argv, ROptTable rot, bool on) {
786
759
  * - *classes* [_Class_] a list of classes to optimize
787
760
  */
788
761
  static VALUE encoder_optimize(int argc, VALUE *argv, VALUE self) {
789
- Encoder e = (Encoder)DATA_PTR(self);
762
+ Encoder e;
763
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
790
764
 
791
765
  optimize(argc, argv, &e->ropts, true);
792
766
 
@@ -828,6 +802,7 @@ rails_mimic_json(VALUE self) {
828
802
  json = rb_define_module("JSON");
829
803
  }
830
804
  oj_mimic_json_methods(json);
805
+ // Setting the default mode breaks the prmoise in the docs not to.
831
806
  // oj_default_options.mode = RailsMode;
832
807
 
833
808
  return Qnil;
@@ -841,7 +816,8 @@ rails_mimic_json(VALUE self) {
841
816
  * - *classes* [_Class_] a list of classes to deoptimize
842
817
  */
843
818
  static VALUE encoder_deoptimize(int argc, VALUE *argv, VALUE self) {
844
- Encoder e = (Encoder)DATA_PTR(self);
819
+ Encoder e;
820
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
845
821
 
846
822
  optimize(argc, argv, &e->ropts, false);
847
823
 
@@ -870,8 +846,11 @@ static VALUE rails_deoptimize(int argc, VALUE *argv, VALUE self) {
870
846
  * @return true if the class is being optimized for rails and false otherwise
871
847
  */
872
848
  static VALUE encoder_optimized(VALUE self, VALUE clas) {
873
- Encoder e = (Encoder)DATA_PTR(self);
874
- ROpt ro = oj_rails_get_opt(&e->ropts, clas);
849
+ Encoder e;
850
+ ROpt ro;
851
+
852
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
853
+ ro = oj_rails_get_opt(&e->ropts, clas);
875
854
 
876
855
  if (NULL == ro) {
877
856
  return Qfalse;
@@ -896,7 +875,7 @@ static VALUE rails_optimized(VALUE self, VALUE clas) {
896
875
  typedef struct _oo {
897
876
  Out out;
898
877
  VALUE obj;
899
- } * OO;
878
+ } *OO;
900
879
 
901
880
  static VALUE protect_dump(VALUE ov) {
902
881
  OO oo = (OO)ov;
@@ -907,7 +886,6 @@ static VALUE protect_dump(VALUE ov) {
907
886
  }
908
887
 
909
888
  static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *argv) {
910
- char buf[4096];
911
889
  struct _out out;
912
890
  struct _options copts = *opts;
913
891
  volatile VALUE rstr = Qnil;
@@ -924,19 +902,18 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
924
902
  } else {
925
903
  copts.escape_mode = RailsEsc;
926
904
  }
927
- out.buf = buf;
928
- out.end = buf + sizeof(buf) - 10;
929
- out.allocated = false;
930
- out.omit_nil = copts.dump_opts.omit_nil;
931
- out.caller = 0;
932
- out.cur = out.buf;
933
- out.circ_cnt = 0;
934
- out.opts = &copts;
935
- out.hash_cnt = 0;
936
- out.indent = copts.indent;
937
- out.argc = argc;
938
- out.argv = argv;
939
- out.ropts = ropts;
905
+
906
+ oj_out_init(&out);
907
+
908
+ out.omit_nil = copts.dump_opts.omit_nil;
909
+ out.cur = out.buf;
910
+ out.circ_cnt = 0;
911
+ out.opts = &copts;
912
+ out.hash_cnt = 0;
913
+ out.indent = copts.indent;
914
+ out.argc = argc;
915
+ out.argv = argv;
916
+ out.ropts = ropts;
940
917
  if (Yes == copts.circular) {
941
918
  oj_cache8_new(&out.circ_cache);
942
919
  }
@@ -962,9 +939,9 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
962
939
  if (Yes == copts.circular) {
963
940
  oj_cache8_delete(out.circ_cache);
964
941
  }
965
- if (out.allocated) {
966
- xfree(out.buf);
967
- }
942
+
943
+ oj_out_free(&out);
944
+
968
945
  if (0 != line) {
969
946
  rb_jump_tag(line);
970
947
  }
@@ -979,7 +956,8 @@ static VALUE encode(VALUE obj, ROptTable ropts, Options opts, int argc, VALUE *a
979
956
  * Returns encoded object as a JSON string.
980
957
  */
981
958
  static VALUE encoder_encode(VALUE self, VALUE obj) {
982
- Encoder e = (Encoder)DATA_PTR(self);
959
+ Encoder e;
960
+ TypedData_Get_Struct(self, struct _encoder, &oj_encoder_type, e);
983
961
 
984
962
  if (Qnil != e->arg) {
985
963
  VALUE argv[1] = {e->arg};
@@ -1081,28 +1059,16 @@ static VALUE rails_set_encoder(VALUE self) {
1081
1059
  verbose = rb_gv_get("$VERBOSE");
1082
1060
  rb_gv_set("$VERBOSE", Qfalse);
1083
1061
  rb_undef_method(encoding, "use_standard_json_time_format=");
1084
- rb_define_module_function(encoding,
1085
- "use_standard_json_time_format=",
1086
- rails_use_standard_json_time_format,
1087
- 1);
1062
+ rb_define_module_function(encoding, "use_standard_json_time_format=", rails_use_standard_json_time_format, 1);
1088
1063
  rb_undef_method(encoding, "use_standard_json_time_format");
1089
- rb_define_module_function(encoding,
1090
- "use_standard_json_time_format",
1091
- rails_use_standard_json_time_format_get,
1092
- 0);
1064
+ rb_define_module_function(encoding, "use_standard_json_time_format", rails_use_standard_json_time_format_get, 0);
1093
1065
 
1094
1066
  pv = rb_iv_get(encoding, "@escape_html_entities_in_json");
1095
1067
  escape_html = Qtrue == pv;
1096
1068
  rb_undef_method(encoding, "escape_html_entities_in_json=");
1097
- rb_define_module_function(encoding,
1098
- "escape_html_entities_in_json=",
1099
- rails_escape_html_entities_in_json,
1100
- 1);
1069
+ rb_define_module_function(encoding, "escape_html_entities_in_json=", rails_escape_html_entities_in_json, 1);
1101
1070
  rb_undef_method(encoding, "escape_html_entities_in_json");
1102
- rb_define_module_function(encoding,
1103
- "escape_html_entities_in_json",
1104
- rails_escape_html_entities_in_json_get,
1105
- 0);
1071
+ rb_define_module_function(encoding, "escape_html_entities_in_json", rails_escape_html_entities_in_json_get, 0);
1106
1072
 
1107
1073
  pv = rb_iv_get(encoding, "@time_precision");
1108
1074
  oj_default_options.sec_prec = NUM2INT(pv);
@@ -1174,12 +1140,15 @@ oj_optimize_rails(VALUE self) {
1174
1140
  *
1175
1141
  * The Oj ActiveSupport compliant encoder.
1176
1142
  */
1177
- void oj_mimic_rails_init() {
1143
+ void oj_mimic_rails_init(void) {
1178
1144
  VALUE rails = rb_define_module_under(Oj, "Rails");
1179
1145
 
1180
1146
  rb_define_module_function(rails, "encode", rails_encode, -1);
1181
1147
 
1182
1148
  encoder_class = rb_define_class_under(rails, "Encoder", rb_cObject);
1149
+ rb_gc_register_address(&encoder_class);
1150
+ rb_undef_alloc_func(encoder_class);
1151
+
1183
1152
  rb_define_module_function(encoder_class, "new", encoder_new, -1);
1184
1153
  rb_define_module_function(rails, "optimize", rails_optimize, -1);
1185
1154
  rb_define_module_function(rails, "deoptimize", rails_deoptimize, -1);
@@ -1201,7 +1170,7 @@ static void dump_to_hash(VALUE obj, int depth, Out out) {
1201
1170
 
1202
1171
  static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1203
1172
  char buf[64];
1204
- char * b;
1173
+ char *b;
1205
1174
  double d = rb_num2dbl(obj);
1206
1175
  int cnt = 0;
1207
1176
 
@@ -1221,9 +1190,9 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
1221
1190
  } else if (oj_rails_float_opt) {
1222
1191
  cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
1223
1192
  } else {
1224
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
1193
+ volatile VALUE rstr = oj_safe_string_convert(obj);
1225
1194
 
1226
- strcpy(buf, rb_string_value_ptr((VALUE *)&rstr));
1195
+ strcpy(buf, RSTRING_PTR(rstr));
1227
1196
  cnt = (int)RSTRING_LEN(rstr);
1228
1197
  }
1229
1198
  }
@@ -1262,25 +1231,23 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1262
1231
  } else {
1263
1232
  size = d2 * out->indent + 2;
1264
1233
  }
1234
+ assure_size(out, size * cnt);
1265
1235
  cnt--;
1266
1236
  for (i = 0; i <= cnt; i++) {
1267
- assure_size(out, size);
1268
1237
  if (out->opts->dump_opts.use) {
1269
1238
  if (0 < out->opts->dump_opts.array_size) {
1270
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1271
- out->cur += out->opts->dump_opts.array_size;
1239
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1272
1240
  }
1273
1241
  if (0 < out->opts->dump_opts.indent_size) {
1274
1242
  int i;
1275
1243
  for (i = d2; 0 < i; i--) {
1276
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1277
- out->cur += out->opts->dump_opts.indent_size;
1244
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1278
1245
  }
1279
1246
  }
1280
1247
  } else {
1281
1248
  fill_indent(out, d2);
1282
1249
  }
1283
- dump_rails_val(rb_ary_entry(a, i), d2, out, true);
1250
+ dump_rails_val(RARRAY_AREF(a, i), d2, out, true);
1284
1251
  if (i < cnt) {
1285
1252
  *out->cur++ = ',';
1286
1253
  }
@@ -1289,15 +1256,13 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
1289
1256
  assure_size(out, size);
1290
1257
  if (out->opts->dump_opts.use) {
1291
1258
  if (0 < out->opts->dump_opts.array_size) {
1292
- strcpy(out->cur, out->opts->dump_opts.array_nl);
1293
- out->cur += out->opts->dump_opts.array_size;
1259
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
1294
1260
  }
1295
1261
  if (0 < out->opts->dump_opts.indent_size) {
1296
1262
  int i;
1297
1263
 
1298
1264
  for (i = depth; 0 < i; i--) {
1299
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1300
- out->cur += out->opts->dump_opts.indent_size;
1265
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1301
1266
  }
1302
1267
  }
1303
1268
  } else {
@@ -1318,7 +1283,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1318
1283
  return ST_CONTINUE;
1319
1284
  }
1320
1285
  if (rtype != T_STRING && rtype != T_SYMBOL) {
1321
- key = rb_funcall(key, oj_to_s_id, 0);
1286
+ key = oj_safe_string_convert(key);
1322
1287
  rtype = rb_type(key);
1323
1288
  }
1324
1289
  if (!out->opts->dump_opts.use) {
@@ -1335,14 +1300,12 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1335
1300
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1336
1301
  assure_size(out, size);
1337
1302
  if (0 < out->opts->dump_opts.hash_size) {
1338
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1339
- out->cur += out->opts->dump_opts.hash_size;
1303
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1340
1304
  }
1341
1305
  if (0 < out->opts->dump_opts.indent_size) {
1342
1306
  int i;
1343
1307
  for (i = depth; 0 < i; i--) {
1344
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1345
- out->cur += out->opts->dump_opts.indent_size;
1308
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1346
1309
  }
1347
1310
  }
1348
1311
  if (rtype == T_STRING) {
@@ -1353,13 +1316,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
1353
1316
  size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
1354
1317
  assure_size(out, size);
1355
1318
  if (0 < out->opts->dump_opts.before_size) {
1356
- strcpy(out->cur, out->opts->dump_opts.before_sep);
1357
- out->cur += out->opts->dump_opts.before_size;
1319
+ APPEND_CHARS(out->cur, out->opts->dump_opts.before_sep, out->opts->dump_opts.before_size);
1358
1320
  }
1359
1321
  *out->cur++ = ':';
1360
1322
  if (0 < out->opts->dump_opts.after_size) {
1361
- strcpy(out->cur, out->opts->dump_opts.after_sep);
1362
- out->cur += out->opts->dump_opts.after_size;
1323
+ APPEND_CHARS(out->cur, out->opts->dump_opts.after_sep, out->opts->dump_opts.after_size);
1363
1324
  }
1364
1325
  }
1365
1326
  dump_rails_val(value, depth, out, true);
@@ -1402,15 +1363,13 @@ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
1402
1363
  size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
1403
1364
  assure_size(out, size);
1404
1365
  if (0 < out->opts->dump_opts.hash_size) {
1405
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
1406
- out->cur += out->opts->dump_opts.hash_size;
1366
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
1407
1367
  }
1408
1368
  if (0 < out->opts->dump_opts.indent_size) {
1409
1369
  int i;
1410
1370
 
1411
1371
  for (i = depth; 0 < i; i--) {
1412
- strcpy(out->cur, out->opts->dump_opts.indent_str);
1413
- out->cur += out->opts->dump_opts.indent_size;
1372
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
1414
1373
  }
1415
1374
  }
1416
1375
  }
@@ -1487,9 +1446,7 @@ static DumpFunc rails_funcs[] = {
1487
1446
  static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1488
1447
  int type = rb_type(obj);
1489
1448
 
1490
- if (Yes == out->opts->trace) {
1491
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1492
- }
1449
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
1493
1450
  if (MAX_DEPTH < depth) {
1494
1451
  rb_raise(rb_eNoMemError, "Too deeply nested.\n");
1495
1452
  }
@@ -1498,16 +1455,12 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1498
1455
 
1499
1456
  if (NULL != f) {
1500
1457
  f(obj, depth, out, as_ok);
1501
- if (Yes == out->opts->trace) {
1502
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1503
- }
1458
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
1504
1459
  return;
1505
1460
  }
1506
1461
  }
1507
1462
  oj_dump_nil(Qnil, depth, out, false);
1508
- if (Yes == out->opts->trace) {
1509
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1510
- }
1463
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
1511
1464
  }
1512
1465
 
1513
1466
  void oj_dump_rails_val(VALUE obj, int depth, Out out) {