oj 3.11.5 → 3.16.5

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 (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) {