oj 3.9.1 → 3.16.11

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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1452 -0
  3. data/README.md +21 -6
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +50 -68
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +9 -36
  10. data/ext/oj/circarray.c +38 -42
  11. data/ext/oj/circarray.h +12 -13
  12. data/ext/oj/code.c +158 -179
  13. data/ext/oj/code.h +20 -22
  14. data/ext/oj/compat.c +145 -205
  15. data/ext/oj/custom.c +740 -880
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +1145 -844
  18. data/ext/oj/dump.h +71 -57
  19. data/ext/oj/dump_compat.c +575 -655
  20. data/ext/oj/dump_leaf.c +96 -186
  21. data/ext/oj/dump_object.c +533 -660
  22. data/ext/oj/dump_strict.c +306 -340
  23. data/ext/oj/encode.h +4 -33
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +28 -28
  26. data/ext/oj/err.h +39 -42
  27. data/ext/oj/extconf.rb +28 -7
  28. data/ext/oj/fast.c +1052 -1113
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +471 -430
  34. data/ext/oj/object.c +532 -580
  35. data/ext/oj/odd.c +156 -142
  36. data/ext/oj/odd.h +25 -26
  37. data/ext/oj/oj.c +1346 -961
  38. data/ext/oj/oj.h +307 -290
  39. data/ext/oj/parse.c +954 -858
  40. data/ext/oj/parse.h +74 -72
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +103 -0
  43. data/ext/oj/rails.c +819 -836
  44. data/ext/oj/rails.h +8 -11
  45. data/ext/oj/reader.c +136 -147
  46. data/ext/oj/reader.h +69 -83
  47. data/ext/oj/resolve.c +41 -63
  48. data/ext/oj/resolve.h +4 -6
  49. data/ext/oj/rxclass.c +69 -72
  50. data/ext/oj/rxclass.h +12 -13
  51. data/ext/oj/saj.c +440 -485
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +79 -118
  55. data/ext/oj/simd.h +10 -0
  56. data/ext/oj/sparse.c +739 -709
  57. data/ext/oj/stream_writer.c +141 -175
  58. data/ext/oj/strict.c +103 -128
  59. data/ext/oj/string_writer.c +244 -261
  60. data/ext/oj/trace.c +34 -41
  61. data/ext/oj/trace.h +42 -15
  62. data/ext/oj/usual.c +1218 -0
  63. data/ext/oj/usual.h +69 -0
  64. data/ext/oj/util.c +107 -107
  65. data/ext/oj/util.h +4 -3
  66. data/ext/oj/val_stack.c +61 -78
  67. data/ext/oj/val_stack.h +80 -114
  68. data/ext/oj/validate.c +46 -0
  69. data/ext/oj/wab.c +316 -361
  70. data/lib/oj/active_support_helper.rb +1 -3
  71. data/lib/oj/bag.rb +8 -1
  72. data/lib/oj/easy_hash.rb +9 -9
  73. data/lib/oj/error.rb +1 -2
  74. data/lib/oj/json.rb +162 -150
  75. data/lib/oj/mimic.rb +54 -20
  76. data/lib/oj/saj.rb +20 -6
  77. data/lib/oj/schandler.rb +5 -4
  78. data/lib/oj/state.rb +12 -8
  79. data/lib/oj/version.rb +1 -2
  80. data/lib/oj.rb +2 -8
  81. data/pages/Compatibility.md +1 -1
  82. data/pages/Encoding.md +1 -1
  83. data/pages/InstallOptions.md +20 -0
  84. data/pages/JsonGem.md +15 -0
  85. data/pages/Modes.md +9 -3
  86. data/pages/Options.md +62 -12
  87. data/pages/Parser.md +309 -0
  88. data/pages/Rails.md +73 -22
  89. metadata +68 -192
  90. data/ext/oj/hash.c +0 -163
  91. data/ext/oj/hash.h +0 -46
  92. data/ext/oj/hash_test.c +0 -512
  93. data/test/_test_active.rb +0 -76
  94. data/test/_test_active_mimic.rb +0 -96
  95. data/test/_test_mimic_rails.rb +0 -126
  96. data/test/activerecord/result_test.rb +0 -27
  97. data/test/activesupport4/decoding_test.rb +0 -108
  98. data/test/activesupport4/encoding_test.rb +0 -531
  99. data/test/activesupport4/test_helper.rb +0 -41
  100. data/test/activesupport5/decoding_test.rb +0 -125
  101. data/test/activesupport5/encoding_test.rb +0 -485
  102. data/test/activesupport5/encoding_test_cases.rb +0 -90
  103. data/test/activesupport5/test_helper.rb +0 -50
  104. data/test/activesupport5/time_zone_test_helpers.rb +0 -24
  105. data/test/bar.rb +0 -25
  106. data/test/files.rb +0 -29
  107. data/test/foo.rb +0 -21
  108. data/test/helper.rb +0 -26
  109. data/test/isolated/shared.rb +0 -308
  110. data/test/isolated/test_mimic_after.rb +0 -13
  111. data/test/isolated/test_mimic_alone.rb +0 -12
  112. data/test/isolated/test_mimic_as_json.rb +0 -45
  113. data/test/isolated/test_mimic_before.rb +0 -13
  114. data/test/isolated/test_mimic_define.rb +0 -28
  115. data/test/isolated/test_mimic_rails_after.rb +0 -22
  116. data/test/isolated/test_mimic_rails_before.rb +0 -21
  117. data/test/isolated/test_mimic_redefine.rb +0 -15
  118. data/test/json_gem/json_addition_test.rb +0 -216
  119. data/test/json_gem/json_common_interface_test.rb +0 -148
  120. data/test/json_gem/json_encoding_test.rb +0 -107
  121. data/test/json_gem/json_ext_parser_test.rb +0 -20
  122. data/test/json_gem/json_fixtures_test.rb +0 -35
  123. data/test/json_gem/json_generator_test.rb +0 -383
  124. data/test/json_gem/json_generic_object_test.rb +0 -90
  125. data/test/json_gem/json_parser_test.rb +0 -470
  126. data/test/json_gem/json_string_matching_test.rb +0 -42
  127. data/test/json_gem/test_helper.rb +0 -18
  128. data/test/perf.rb +0 -107
  129. data/test/perf_compat.rb +0 -130
  130. data/test/perf_fast.rb +0 -164
  131. data/test/perf_file.rb +0 -64
  132. data/test/perf_object.rb +0 -138
  133. data/test/perf_saj.rb +0 -109
  134. data/test/perf_scp.rb +0 -151
  135. data/test/perf_simple.rb +0 -287
  136. data/test/perf_strict.rb +0 -145
  137. data/test/perf_wab.rb +0 -131
  138. data/test/sample/change.rb +0 -14
  139. data/test/sample/dir.rb +0 -19
  140. data/test/sample/doc.rb +0 -36
  141. data/test/sample/file.rb +0 -48
  142. data/test/sample/group.rb +0 -16
  143. data/test/sample/hasprops.rb +0 -16
  144. data/test/sample/layer.rb +0 -12
  145. data/test/sample/line.rb +0 -20
  146. data/test/sample/oval.rb +0 -10
  147. data/test/sample/rect.rb +0 -10
  148. data/test/sample/shape.rb +0 -35
  149. data/test/sample/text.rb +0 -20
  150. data/test/sample.rb +0 -54
  151. data/test/sample_json.rb +0 -37
  152. data/test/test_compat.rb +0 -509
  153. data/test/test_custom.rb +0 -503
  154. data/test/test_debian.rb +0 -53
  155. data/test/test_fast.rb +0 -470
  156. data/test/test_file.rb +0 -239
  157. data/test/test_gc.rb +0 -49
  158. data/test/test_hash.rb +0 -29
  159. data/test/test_integer_range.rb +0 -73
  160. data/test/test_null.rb +0 -376
  161. data/test/test_object.rb +0 -1018
  162. data/test/test_saj.rb +0 -186
  163. data/test/test_scp.rb +0 -433
  164. data/test/test_strict.rb +0 -410
  165. data/test/test_various.rb +0 -741
  166. data/test/test_wab.rb +0 -307
  167. data/test/test_writer.rb +0 -380
  168. data/test/tests.rb +0 -24
  169. data/test/tests_mimic.rb +0 -14
  170. data/test/tests_mimic_addition.rb +0 -7
  171. data/test/zoo.rb +0 -13
data/ext/oj/dump_object.c CHANGED
@@ -1,837 +1,710 @@
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 "dump.h"
5
+ #include "mem.h"
7
6
  #include "odd.h"
8
7
  #include "trace.h"
9
8
 
10
- static const char hex_chars[17] = "0123456789abcdef";
9
+ static const char hex_chars[17] = "0123456789abcdef";
11
10
 
12
- static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out);
11
+ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out);
13
12
 
14
- static void
15
- dump_time(VALUE obj, Out out) {
13
+ static void dump_time(VALUE obj, Out out) {
16
14
  switch (out->opts->time_format) {
17
15
  case RubyTime:
18
- case XmlTime: oj_dump_xml_time(obj, out); break;
19
- case UnixZTime: oj_dump_time(obj, out, 1); break;
16
+ case XmlTime: oj_dump_xml_time(obj, out); break;
17
+ case UnixZTime: oj_dump_time(obj, out, 1); break;
20
18
  case UnixTime:
21
- default: oj_dump_time(obj, out, 0); break;
19
+ default: oj_dump_time(obj, out, 0); break;
22
20
  }
23
21
  }
24
22
 
25
- static void
26
- dump_data(VALUE obj, int depth, Out out, bool as_ok) {
27
- VALUE clas = rb_obj_class(obj);
23
+ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
24
+ VALUE clas = rb_obj_class(obj);
28
25
 
29
26
  if (rb_cTime == clas) {
30
- assure_size(out, 6);
31
- *out->cur++ = '{';
32
- *out->cur++ = '"';
33
- *out->cur++ = '^';
34
- *out->cur++ = 't';
35
- *out->cur++ = '"';
36
- *out->cur++ = ':';
37
- dump_time(obj, out);
38
- *out->cur++ = '}';
39
- *out->cur = '\0';
27
+ assure_size(out, 6);
28
+ APPEND_CHARS(out->cur, "{\"^t\":", 6);
29
+ dump_time(obj, out);
30
+ *out->cur++ = '}';
31
+ *out->cur = '\0';
40
32
  } else {
41
- if (oj_bigdecimal_class == clas) {
42
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
43
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
44
- int len = (int)RSTRING_LEN(rstr);
45
-
46
- if (No != out->opts->bigdec_as_num) {
47
- oj_dump_raw(str, len, out);
48
- } else if (0 == strcasecmp("Infinity", str)) {
49
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
50
- oj_dump_raw(str, len, out);
51
- } else if (0 == strcasecmp("-Infinity", str)) {
52
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
53
- oj_dump_raw(str, len, out);
54
- } else {
55
- oj_dump_cstr(str, len, 0, 0, out);
56
- }
57
- } else {
58
- long id = oj_check_circular(obj, out);
59
-
60
- if (0 <= id) {
61
- dump_obj_attrs(obj, clas, id, depth, out);
62
- }
63
- }
33
+ if (oj_bigdecimal_class == clas) {
34
+ volatile VALUE rstr = oj_safe_string_convert(obj);
35
+ const char *str = RSTRING_PTR(rstr);
36
+ size_t len = RSTRING_LEN(rstr);
37
+
38
+ if (No != out->opts->bigdec_as_num) {
39
+ oj_dump_raw(str, len, out);
40
+ } else if (0 == strcasecmp("Infinity", str)) {
41
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
42
+ oj_dump_raw(str, len, out);
43
+ } else if (0 == strcasecmp("-Infinity", str)) {
44
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
45
+ oj_dump_raw(str, len, out);
46
+ } else {
47
+ oj_dump_cstr(str, len, 0, 0, out);
48
+ }
49
+ } else {
50
+ long id = oj_check_circular(obj, out);
51
+
52
+ if (0 <= id) {
53
+ dump_obj_attrs(obj, clas, id, depth, out);
54
+ }
55
+ }
64
56
  }
65
57
  }
66
58
 
67
- static void
68
- dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
69
- VALUE clas = rb_obj_class(obj);
59
+ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
60
+ VALUE clas = rb_obj_class(obj);
70
61
 
71
62
  if (oj_bigdecimal_class == clas) {
72
- volatile VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
73
- const char *str = rb_string_value_ptr((VALUE*)&rstr);
74
- int len = (int)RSTRING_LEN(rstr);
75
-
76
- if (0 == strcasecmp("Infinity", str)) {
77
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
78
- oj_dump_raw(str, len, out);
79
- } else if (0 == strcasecmp("-Infinity", str)) {
80
- str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
81
- oj_dump_raw(str, len, out);
82
- } else {
83
- oj_dump_raw(str, len, out);
84
- }
63
+ volatile VALUE rstr = oj_safe_string_convert(obj);
64
+ const char *str = RSTRING_PTR(rstr);
65
+ size_t len = RSTRING_LEN(rstr);
66
+
67
+ if (0 == strcasecmp("Infinity", str)) {
68
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
69
+ oj_dump_raw(str, len, out);
70
+ } else if (0 == strcasecmp("-Infinity", str)) {
71
+ str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, false, &len);
72
+ oj_dump_raw(str, len, out);
73
+ } else {
74
+ oj_dump_raw(str, len, out);
75
+ }
85
76
  } else {
86
- long id = oj_check_circular(obj, out);
77
+ long id = oj_check_circular(obj, out);
87
78
 
88
- if (0 <= id) {
89
- dump_obj_attrs(obj, clas, id, depth, out);
90
- }
79
+ if (0 <= id) {
80
+ dump_obj_attrs(obj, clas, id, depth, out);
81
+ }
91
82
  }
92
83
  }
93
84
 
94
- static void
95
- dump_class(VALUE obj, int depth, Out out, bool as_ok) {
96
- const char *s = rb_class2name(obj);
97
- size_t len = strlen(s);
85
+ static void dump_class(VALUE obj, int depth, Out out, bool as_ok) {
86
+ const char *s = rb_class2name(obj);
87
+ size_t len = strlen(s);
98
88
 
99
89
  assure_size(out, 6);
100
- *out->cur++ = '{';
101
- *out->cur++ = '"';
102
- *out->cur++ = '^';
103
- *out->cur++ = 'c';
104
- *out->cur++ = '"';
105
- *out->cur++ = ':';
90
+ APPEND_CHARS(out->cur, "{\"^c\":", 6);
106
91
  oj_dump_cstr(s, len, 0, 0, out);
107
92
  *out->cur++ = '}';
108
- *out->cur = '\0';
93
+ *out->cur = '\0';
109
94
  }
110
95
 
111
- static void
112
- dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
113
- size_t size;
114
- int i, cnt;
115
- int d2 = depth + 1;
116
- long id = oj_check_circular(a, out);
96
+ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
97
+ size_t size;
98
+ size_t i;
99
+ size_t cnt;
100
+ int d2 = depth + 1;
101
+ long id = oj_check_circular(a, out);
117
102
 
118
103
  if (id < 0) {
119
- return;
104
+ return;
120
105
  }
121
106
  if (Qundef != clas && rb_cArray != clas && ObjectMode == out->opts->mode) {
122
- dump_obj_attrs(a, clas, 0, depth, out);
123
- return;
107
+ dump_obj_attrs(a, clas, 0, depth, out);
108
+ return;
124
109
  }
125
- cnt = (int)RARRAY_LEN(a);
110
+ cnt = RARRAY_LEN(a);
126
111
  *out->cur++ = '[';
127
112
  if (0 < id) {
128
- assure_size(out, d2 * out->indent + 16);
129
- fill_indent(out, d2);
130
- *out->cur++ = '"';
131
- *out->cur++ = '^';
132
- *out->cur++ = 'i';
133
- dump_ulong(id, out);
134
- *out->cur++ = '"';
113
+ assure_size(out, d2 * out->indent + 16);
114
+ fill_indent(out, d2);
115
+ APPEND_CHARS(out->cur, "\"^i", 3);
116
+ dump_ulong(id, out);
117
+ *out->cur++ = '"';
135
118
  }
136
119
  size = 2;
137
120
  assure_size(out, 2);
138
121
  if (0 == cnt) {
139
- *out->cur++ = ']';
122
+ *out->cur++ = ']';
140
123
  } else {
141
- if (0 < id) {
142
- *out->cur++ = ',';
143
- }
144
- if (out->opts->dump_opts.use) {
145
- size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
146
- } else {
147
- size = d2 * out->indent + 2;
148
- }
149
- cnt--;
150
- for (i = 0; i <= cnt; i++) {
151
- assure_size(out, size);
152
- if (out->opts->dump_opts.use) {
153
- if (0 < out->opts->dump_opts.array_size) {
154
- strcpy(out->cur, out->opts->dump_opts.array_nl);
155
- out->cur += out->opts->dump_opts.array_size;
156
- }
157
- if (0 < out->opts->dump_opts.indent_size) {
158
- int i;
159
- for (i = d2; 0 < i; i--) {
160
- strcpy(out->cur, out->opts->dump_opts.indent_str);
161
- out->cur += out->opts->dump_opts.indent_size;
162
- }
163
- }
164
- } else {
165
- fill_indent(out, d2);
166
- }
167
- oj_dump_obj_val(rb_ary_entry(a, i), d2, out);
168
- if (i < cnt) {
169
- *out->cur++ = ',';
170
- }
171
- }
172
- size = depth * out->indent + 1;
173
- assure_size(out, size);
174
- if (out->opts->dump_opts.use) {
175
- //printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size, out->opts->dump_opts->indent);
176
- if (0 < out->opts->dump_opts.array_size) {
177
- strcpy(out->cur, out->opts->dump_opts.array_nl);
178
- out->cur += out->opts->dump_opts.array_size;
179
- }
180
- if (0 < out->opts->dump_opts.indent_size) {
181
- int i;
182
-
183
- for (i = depth; 0 < i; i--) {
184
- strcpy(out->cur, out->opts->dump_opts.indent_str);
185
- out->cur += out->opts->dump_opts.indent_size;
186
- }
187
- }
188
- } else {
189
- fill_indent(out, depth);
190
- }
191
- *out->cur++ = ']';
124
+ if (0 < id) {
125
+ *out->cur++ = ',';
126
+ }
127
+ if (out->opts->dump_opts.use) {
128
+ size = d2 * out->opts->dump_opts.indent_size + out->opts->dump_opts.array_size + 1;
129
+ } else {
130
+ size = d2 * out->indent + 2;
131
+ }
132
+ assure_size(out, size * cnt);
133
+ cnt--;
134
+ for (i = 0; i <= cnt; i++) {
135
+ if (out->opts->dump_opts.use) {
136
+ if (0 < out->opts->dump_opts.array_size) {
137
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
138
+ }
139
+ if (0 < out->opts->dump_opts.indent_size) {
140
+ int i;
141
+ for (i = d2; 0 < i; i--) {
142
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
143
+ }
144
+ }
145
+ } else {
146
+ fill_indent(out, d2);
147
+ }
148
+ oj_dump_obj_val(RARRAY_AREF(a, i), d2, out);
149
+ if (i < cnt) {
150
+ *out->cur++ = ',';
151
+ }
152
+ }
153
+ size = depth * out->indent + 1;
154
+ assure_size(out, size);
155
+ if (out->opts->dump_opts.use) {
156
+ // printf("*** d2: %u indent: %u '%s'\n", d2, out->opts->dump_opts->indent_size,
157
+ // out->opts->dump_opts->indent);
158
+ if (0 < out->opts->dump_opts.array_size) {
159
+ APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
160
+ }
161
+ if (0 < out->opts->dump_opts.indent_size) {
162
+ int i;
163
+
164
+ for (i = depth; 0 < i; i--) {
165
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
166
+ }
167
+ }
168
+ } else {
169
+ fill_indent(out, depth);
170
+ }
171
+ *out->cur++ = ']';
192
172
  }
193
173
  *out->cur = '\0';
194
174
  }
195
175
 
196
- static void
197
- dump_array(VALUE obj, int depth, Out out, bool as_ok) {
176
+ static void dump_array(VALUE obj, int depth, Out out, bool as_ok) {
198
177
  dump_array_class(obj, rb_obj_class(obj), depth, out);
199
178
  }
200
179
 
201
- static void
202
- dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
180
+ static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
203
181
  if (Qundef != clas && rb_cString != clas) {
204
- dump_obj_attrs(obj, clas, 0, depth, out);
182
+ dump_obj_attrs(obj, clas, 0, depth, out);
205
183
  } else {
206
- const char *s = rb_string_value_ptr((VALUE*)&obj);
207
- size_t len = (int)RSTRING_LEN(obj);
208
- char s1 = s[1];
184
+ const char *s = RSTRING_PTR(obj);
185
+ size_t len = RSTRING_LEN(obj);
186
+ char s1 = s[1];
209
187
 
210
- oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
188
+ oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
211
189
  }
212
190
  }
213
191
 
214
- static void
215
- dump_str(VALUE obj, int depth, Out out, bool as_ok) {
192
+ static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
216
193
  dump_str_class(obj, rb_obj_class(obj), depth, out);
217
194
  }
218
195
 
219
- static void
220
- dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
221
- volatile VALUE s = rb_sym_to_s(obj);
196
+ static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
197
+ volatile VALUE s = rb_sym2str(obj);
222
198
 
223
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&s), (int)RSTRING_LEN(s), 1, 0, out);
199
+ oj_dump_cstr(RSTRING_PTR(s), RSTRING_LEN(s), 1, 0, out);
224
200
  }
225
201
 
226
- static int
227
- hash_cb(VALUE key, VALUE value, Out out) {
228
- int depth = out->depth;
229
- long size = depth * out->indent + 1;
202
+ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
203
+ Out out = (Out)ov;
204
+ int depth = out->depth;
205
+ long size = depth * out->indent + 1;
230
206
 
231
- if (oj_dump_ignore(out->opts, value)) {
232
- return ST_CONTINUE;
207
+ if (dump_ignore(out->opts, value)) {
208
+ return ST_CONTINUE;
233
209
  }
234
210
  if (out->omit_nil && Qnil == value) {
235
- return ST_CONTINUE;
211
+ return ST_CONTINUE;
236
212
  }
237
213
  assure_size(out, size);
238
214
  fill_indent(out, depth);
239
- if (rb_type(key) == T_STRING) {
240
- dump_str_class(key, Qundef, depth, out);
241
- *out->cur++ = ':';
242
- oj_dump_obj_val(value, depth, out);
243
- } else if (rb_type(key) == T_SYMBOL) {
244
- dump_sym(key, 0, out, false);
245
- *out->cur++ = ':';
246
- oj_dump_obj_val(value, depth, out);
247
- } else {
248
- int d2 = depth + 1;
249
- long s2 = size + out->indent + 1;
250
- int i;
251
- int started = 0;
252
- uint8_t b;
253
-
254
- assure_size(out, s2 + 15);
255
- *out->cur++ = '"';
256
- *out->cur++ = '^';
257
- *out->cur++ = '#';
258
- out->hash_cnt++;
259
- for (i = 28; 0 <= i; i -= 4) {
260
- b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
261
- if ('\0' != b) {
262
- started = 1;
263
- }
264
- if (started) {
265
- *out->cur++ = hex_chars[b];
266
- }
267
- }
268
- *out->cur++ = '"';
269
- *out->cur++ = ':';
270
- *out->cur++ = '[';
271
- fill_indent(out, d2);
272
- oj_dump_obj_val(key, d2, out);
273
- assure_size(out, s2);
274
- *out->cur++ = ',';
275
- fill_indent(out, d2);
276
- oj_dump_obj_val(value, d2, out);
277
- assure_size(out, size);
278
- fill_indent(out, depth);
279
- *out->cur++ = ']';
280
- }
281
- out->depth = depth;
215
+ switch (rb_type(key)) {
216
+ case T_STRING:
217
+ dump_str_class(key, Qundef, depth, out);
218
+ *out->cur++ = ':';
219
+ oj_dump_obj_val(value, depth, out);
220
+ break;
221
+
222
+ case T_SYMBOL:
223
+ dump_sym(key, 0, out, false);
224
+ *out->cur++ = ':';
225
+ oj_dump_obj_val(value, depth, out);
226
+ break;
227
+
228
+ default: {
229
+ int d2 = depth + 1;
230
+ long s2 = size + out->indent + 1;
231
+ int i;
232
+ int started = 0;
233
+ uint8_t b;
234
+
235
+ assure_size(out, s2 + 15);
236
+ APPEND_CHARS(out->cur, "\"^#", 3);
237
+ out->hash_cnt++;
238
+ for (i = 28; 0 <= i; i -= 4) {
239
+ b = (uint8_t)((out->hash_cnt >> i) & 0x0000000F);
240
+ if ('\0' != b) {
241
+ started = 1;
242
+ }
243
+ if (started) {
244
+ *out->cur++ = hex_chars[b];
245
+ }
246
+ }
247
+ APPEND_CHARS(out->cur, "\":[", 3);
248
+ fill_indent(out, d2);
249
+ oj_dump_obj_val(key, d2, out);
250
+ assure_size(out, s2);
251
+ *out->cur++ = ',';
252
+ fill_indent(out, d2);
253
+ oj_dump_obj_val(value, d2, out);
254
+ assure_size(out, size);
255
+ fill_indent(out, depth);
256
+ *out->cur++ = ']';
257
+ }
258
+ }
259
+ out->depth = depth;
282
260
  *out->cur++ = ',';
283
-
261
+
284
262
  return ST_CONTINUE;
285
263
  }
286
264
 
287
- static void
288
- dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
289
- int cnt;
290
- size_t size;
265
+ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
266
+ int cnt;
267
+ size_t size;
291
268
 
292
269
  if (Qundef != clas && rb_cHash != clas) {
293
- dump_obj_attrs(obj, clas, 0, depth, out);
294
- return;
270
+ dump_obj_attrs(obj, clas, 0, depth, out);
271
+ return;
295
272
  }
296
- cnt = (int)RHASH_SIZE(obj);
273
+ cnt = (int)RHASH_SIZE(obj);
297
274
  size = depth * out->indent + 2;
298
275
  assure_size(out, 2);
299
276
  if (0 == cnt) {
300
- *out->cur++ = '{';
301
- *out->cur++ = '}';
277
+ APPEND_CHARS(out->cur, "{}", 2);
302
278
  } else {
303
- long id = oj_check_circular(obj, out);
304
-
305
- if (0 > id) {
306
- return;
307
- }
308
- *out->cur++ = '{';
309
- if (0 < id) {
310
- assure_size(out, size + 16);
311
- fill_indent(out, depth + 1);
312
- *out->cur++ = '"';
313
- *out->cur++ = '^';
314
- *out->cur++ = 'i';
315
- *out->cur++ = '"';
316
- *out->cur++ = ':';
317
- dump_ulong(id, out);
318
- *out->cur++ = ',';
319
- }
320
- out->depth = depth + 1;
321
- rb_hash_foreach(obj, hash_cb, (VALUE)out);
322
- if (',' == *(out->cur - 1)) {
323
- out->cur--; // backup to overwrite last comma
324
- }
325
- if (!out->opts->dump_opts.use) {
326
- assure_size(out, size);
327
- fill_indent(out, depth);
328
- } else {
329
- size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
330
- assure_size(out, size);
331
- if (0 < out->opts->dump_opts.hash_size) {
332
- strcpy(out->cur, out->opts->dump_opts.hash_nl);
333
- out->cur += out->opts->dump_opts.hash_size;
334
- }
335
- if (0 < out->opts->dump_opts.indent_size) {
336
- int i;
337
-
338
- for (i = depth; 0 < i; i--) {
339
- strcpy(out->cur, out->opts->dump_opts.indent_str);
340
- out->cur += out->opts->dump_opts.indent_size;
341
- }
342
- }
343
- }
344
- *out->cur++ = '}';
279
+ long id = oj_check_circular(obj, out);
280
+
281
+ if (0 > id) {
282
+ return;
283
+ }
284
+ *out->cur++ = '{';
285
+ if (0 < id) {
286
+ assure_size(out, size + 16);
287
+ fill_indent(out, depth + 1);
288
+ APPEND_CHARS(out->cur, "\"^i\":", 5);
289
+ dump_ulong(id, out);
290
+ *out->cur++ = ',';
291
+ }
292
+ out->depth = depth + 1;
293
+ rb_hash_foreach(obj, hash_cb, (VALUE)out);
294
+ if (',' == *(out->cur - 1)) {
295
+ out->cur--; // backup to overwrite last comma
296
+ }
297
+ if (!out->opts->dump_opts.use) {
298
+ assure_size(out, size);
299
+ fill_indent(out, depth);
300
+ } else {
301
+ size = depth * out->opts->dump_opts.indent_size + out->opts->dump_opts.hash_size + 1;
302
+ assure_size(out, size);
303
+ if (0 < out->opts->dump_opts.hash_size) {
304
+ APPEND_CHARS(out->cur, out->opts->dump_opts.hash_nl, out->opts->dump_opts.hash_size);
305
+ }
306
+ if (0 < out->opts->dump_opts.indent_size) {
307
+ int i;
308
+
309
+ for (i = depth; 0 < i; i--) {
310
+ APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
311
+ }
312
+ }
313
+ }
314
+ *out->cur++ = '}';
345
315
  }
346
316
  *out->cur = '\0';
347
317
  }
348
318
 
349
- #ifdef HAVE_RB_IVAR_FOREACH
350
- static int
351
- dump_attr_cb(ID key, VALUE value, Out out) {
352
- int depth = out->depth;
353
- size_t size = depth * out->indent + 1;
354
- const char *attr = rb_id2name(key);
319
+ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
320
+ Out out = (Out)ov;
321
+ int depth = out->depth;
322
+ size_t size = depth * out->indent + 1;
323
+ const char *attr = rb_id2name(key);
355
324
 
356
- if (oj_dump_ignore(out->opts, value)) {
357
- return ST_CONTINUE;
325
+ if (dump_ignore(out->opts, value)) {
326
+ return ST_CONTINUE;
358
327
  }
359
328
  if (out->omit_nil && Qnil == value) {
360
- return ST_CONTINUE;
329
+ return ST_CONTINUE;
361
330
  }
362
331
  // Some exceptions such as NoMethodError have an invisible attribute where
363
332
  // the key name is NULL. Not an empty string but NULL.
364
333
  if (NULL == attr) {
365
- attr = "";
334
+ attr = "";
335
+ } else if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
336
+ return ST_CONTINUE;
366
337
  }
367
338
  if (0 == strcmp("bt", attr) || 0 == strcmp("mesg", attr)) {
368
- return ST_CONTINUE;
339
+ return ST_CONTINUE;
369
340
  }
370
341
  assure_size(out, size);
371
342
  fill_indent(out, depth);
372
343
  if ('@' == *attr) {
373
- attr++;
374
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
344
+ attr++;
345
+ oj_dump_cstr(attr, strlen(attr), 0, 0, out);
375
346
  } else {
376
- char buf[32];
347
+ char buf[32];
377
348
 
378
- *buf = '~';
379
- strncpy(buf + 1, attr, sizeof(buf) - 2);
380
- buf[sizeof(buf) - 1] = '\0';
381
- oj_dump_cstr(buf, strlen(buf), 0, 0, out);
349
+ *buf = '~';
350
+ strncpy(buf + 1, attr, sizeof(buf) - 2);
351
+ buf[sizeof(buf) - 1] = '\0';
352
+ oj_dump_cstr(buf, strlen(buf), 0, 0, out);
382
353
  }
383
354
  *out->cur++ = ':';
384
355
  oj_dump_obj_val(value, depth, out);
385
- out->depth = depth;
356
+ out->depth = depth;
386
357
  *out->cur++ = ',';
387
-
358
+
388
359
  return ST_CONTINUE;
389
360
  }
390
- #endif
391
361
 
392
- static void
393
- dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
362
+ static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
394
363
  dump_hash_class(obj, rb_obj_class(obj), depth, out);
395
364
  }
396
365
 
397
- static void
398
- dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
399
- ID *idp;
400
- AttrGetFunc *fp;
401
- volatile VALUE v;
402
- const char *name;
403
- size_t size;
404
- int d2 = depth + 1;
366
+ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
367
+ ID *idp;
368
+ AttrGetFunc *fp;
369
+ volatile VALUE v;
370
+ const char *name;
371
+ size_t size;
372
+ int d2 = depth + 1;
405
373
 
406
374
  assure_size(out, 2);
407
375
  *out->cur++ = '{';
408
376
  if (Qundef != clas) {
409
- const char *class_name = rb_class2name(clas);
410
- int clen = (int)strlen(class_name);
411
-
412
- size = d2 * out->indent + clen + 10;
413
- assure_size(out, size);
414
- fill_indent(out, d2);
415
- *out->cur++ = '"';
416
- *out->cur++ = '^';
417
- *out->cur++ = 'O';
418
- *out->cur++ = '"';
419
- *out->cur++ = ':';
420
- oj_dump_cstr(class_name, clen, 0, 0, out);
421
- *out->cur++ = ',';
377
+ const char *class_name = rb_class2name(clas);
378
+ int clen = (int)strlen(class_name);
379
+
380
+ size = d2 * out->indent + clen + 10;
381
+ assure_size(out, size);
382
+ fill_indent(out, d2);
383
+ APPEND_CHARS(out->cur, "\"^O\":", 5);
384
+ oj_dump_cstr(class_name, clen, 0, 0, out);
385
+ *out->cur++ = ',';
422
386
  }
423
387
  if (odd->raw) {
424
- v = rb_funcall(obj, *odd->attrs, 0);
425
- if (Qundef == v || T_STRING != rb_type(v)) {
426
- rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
427
- } else {
428
- const char *s = rb_string_value_ptr((VALUE*)&v);
429
- int len = (int)RSTRING_LEN(v);
430
- const char *name = rb_id2name(*odd->attrs);
431
- size_t nlen = strlen(name);
432
-
433
- size = len + d2 * out->indent + nlen + 10;
434
- assure_size(out, size);
435
- fill_indent(out, d2);
436
- *out->cur++ = '"';
437
- memcpy(out->cur, name, nlen);
438
- out->cur += nlen;
439
- *out->cur++ = '"';
440
- *out->cur++ = ':';
441
- memcpy(out->cur, s, len);
442
- out->cur += len;
443
- *out->cur = '\0';
444
- }
388
+ v = rb_funcall(obj, *odd->attrs, 0);
389
+ if (Qundef == v || T_STRING != rb_type(v)) {
390
+ rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
391
+ } else {
392
+ const char *s = RSTRING_PTR(v);
393
+ size_t len = RSTRING_LEN(v);
394
+ const char *name = rb_id2name(*odd->attrs);
395
+ size_t nlen = strlen(name);
396
+
397
+ size = len + d2 * out->indent + nlen + 10;
398
+ assure_size(out, size);
399
+ fill_indent(out, d2);
400
+ *out->cur++ = '"';
401
+ APPEND_CHARS(out->cur, name, nlen);
402
+ APPEND_CHARS(out->cur, "\":", 2);
403
+ APPEND_CHARS(out->cur, s, len);
404
+ *out->cur = '\0';
405
+ }
445
406
  } else {
446
- size = d2 * out->indent + 1;
447
- for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
448
- size_t nlen;
449
-
450
- assure_size(out, size);
451
- name = rb_id2name(*idp);
452
- nlen = strlen(name);
453
- if (0 != *fp) {
454
- v = (*fp)(obj);
455
- } else if (0 == strchr(name, '.')) {
456
- v = rb_funcall(obj, *idp, 0);
457
- } else {
458
- char nbuf[256];
459
- char *n2 = nbuf;
460
- char *n;
461
- char *end;
462
- ID i;
463
-
464
- if (sizeof(nbuf) <= nlen) {
465
- if (NULL == (n2 = strdup(name))) {
466
- rb_raise(rb_eNoMemError, "for attribute name.");
467
- }
468
- } else {
469
- strcpy(n2, name);
470
- }
471
- n = n2;
472
- v = obj;
473
- while (0 != (end = strchr(n, '.'))) {
474
- *end = '\0';
475
- i = rb_intern(n);
476
- v = rb_funcall(v, i, 0);
477
- n = end + 1;
478
- }
479
- i = rb_intern(n);
480
- v = rb_funcall(v, i, 0);
481
- if (nbuf != n2) {
482
- free(n2);
483
- }
484
- }
485
- fill_indent(out, d2);
486
- oj_dump_cstr(name, nlen, 0, 0, out);
487
- *out->cur++ = ':';
488
- oj_dump_obj_val(v, d2, out);
489
- assure_size(out, 2);
490
- *out->cur++ = ',';
491
- }
492
- out->cur--;
407
+ size = d2 * out->indent + 1;
408
+ for (idp = odd->attrs, fp = odd->attrFuncs; 0 != *idp; idp++, fp++) {
409
+ size_t nlen;
410
+
411
+ assure_size(out, size);
412
+ name = rb_id2name(*idp);
413
+ nlen = strlen(name);
414
+ if (NULL != *fp) {
415
+ v = (*fp)(obj);
416
+ } else if (0 == strchr(name, '.')) {
417
+ v = rb_funcall(obj, *idp, 0);
418
+ } else {
419
+ char nbuf[256];
420
+ char *n2 = nbuf;
421
+ char *n;
422
+ char *end;
423
+ ID i;
424
+
425
+ if (sizeof(nbuf) <= nlen) {
426
+ if (NULL == (n2 = OJ_STRDUP(name))) {
427
+ rb_raise(rb_eNoMemError, "for attribute name.");
428
+ }
429
+ } else {
430
+ strcpy(n2, name);
431
+ }
432
+ n = n2;
433
+ v = obj;
434
+ while (0 != (end = strchr(n, '.'))) {
435
+ *end = '\0';
436
+ i = rb_intern(n);
437
+ v = rb_funcall(v, i, 0);
438
+ n = end + 1;
439
+ }
440
+ i = rb_intern(n);
441
+ v = rb_funcall(v, i, 0);
442
+ if (nbuf != n2) {
443
+ OJ_FREE(n2);
444
+ }
445
+ }
446
+ fill_indent(out, d2);
447
+ oj_dump_cstr(name, nlen, 0, 0, out);
448
+ *out->cur++ = ':';
449
+ oj_dump_obj_val(v, d2, out);
450
+ assure_size(out, 2);
451
+ *out->cur++ = ',';
452
+ }
453
+ out->cur--;
493
454
  }
494
455
  *out->cur++ = '}';
495
- *out->cur = '\0';
456
+ *out->cur = '\0';
496
457
  }
497
458
 
498
- static void
499
- dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
500
- size_t size = 0;
501
- int d2 = depth + 1;
502
- int type = rb_type(obj);
503
- Odd odd;
459
+ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out) {
460
+ size_t size = 0;
461
+ int d2 = depth + 1;
462
+ int type = rb_type(obj);
463
+ Odd odd;
504
464
 
505
465
  if (0 != (odd = oj_get_odd(clas))) {
506
- dump_odd(obj, odd, clas, depth + 1, out);
507
- return;
466
+ dump_odd(obj, odd, clas, depth + 1, out);
467
+ return;
508
468
  }
509
469
  assure_size(out, 2);
510
470
  *out->cur++ = '{';
511
471
  if (Qundef != clas) {
512
- const char *class_name = rb_class2name(clas);
513
- int clen = (int)strlen(class_name);
514
-
515
- assure_size(out, d2 * out->indent + clen + 10);
516
- fill_indent(out, d2);
517
- *out->cur++ = '"';
518
- *out->cur++ = '^';
519
- *out->cur++ = 'o';
520
- *out->cur++ = '"';
521
- *out->cur++ = ':';
522
- oj_dump_cstr(class_name, clen, 0, 0, out);
472
+ const char *class_name = rb_class2name(clas);
473
+ int clen = (int)strlen(class_name);
474
+
475
+ assure_size(out, d2 * out->indent + clen + 10);
476
+ fill_indent(out, d2);
477
+ APPEND_CHARS(out->cur, "\"^o\":", 5);
478
+ oj_dump_cstr(class_name, clen, 0, 0, out);
523
479
  }
524
480
  if (0 < id) {
525
- assure_size(out, d2 * out->indent + 16);
526
- *out->cur++ = ',';
527
- fill_indent(out, d2);
528
- *out->cur++ = '"';
529
- *out->cur++ = '^';
530
- *out->cur++ = 'i';
531
- *out->cur++ = '"';
532
- *out->cur++ = ':';
533
- dump_ulong(id, out);
481
+ assure_size(out, d2 * out->indent + 16);
482
+ *out->cur++ = ',';
483
+ fill_indent(out, d2);
484
+ APPEND_CHARS(out->cur, "\"^i\":", 5);
485
+ dump_ulong(id, out);
534
486
  }
535
487
  switch (type) {
536
488
  case T_STRING:
537
- assure_size(out, d2 * out->indent + 14);
538
- *out->cur++ = ',';
539
- fill_indent(out, d2);
540
- *out->cur++ = '"';
541
- *out->cur++ = 's';
542
- *out->cur++ = 'e';
543
- *out->cur++ = 'l';
544
- *out->cur++ = 'f';
545
- *out->cur++ = '"';
546
- *out->cur++ = ':';
547
- oj_dump_cstr(rb_string_value_ptr((VALUE*)&obj), (int)RSTRING_LEN(obj), 0, 0, out);
548
- break;
489
+ assure_size(out, d2 * out->indent + 14);
490
+ *out->cur++ = ',';
491
+ fill_indent(out, d2);
492
+ APPEND_CHARS(out->cur, "\"self\":", 7);
493
+ oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
494
+ break;
549
495
  case T_ARRAY:
550
- assure_size(out, d2 * out->indent + 14);
551
- *out->cur++ = ',';
552
- fill_indent(out, d2);
553
- *out->cur++ = '"';
554
- *out->cur++ = 's';
555
- *out->cur++ = 'e';
556
- *out->cur++ = 'l';
557
- *out->cur++ = 'f';
558
- *out->cur++ = '"';
559
- *out->cur++ = ':';
560
- dump_array_class(obj, Qundef, depth + 1, out);
561
- break;
496
+ assure_size(out, d2 * out->indent + 14);
497
+ *out->cur++ = ',';
498
+ fill_indent(out, d2);
499
+ APPEND_CHARS(out->cur, "\"self\":", 7);
500
+ dump_array_class(obj, Qundef, depth + 1, out);
501
+ break;
562
502
  case T_HASH:
563
- assure_size(out, d2 * out->indent + 14);
564
- *out->cur++ = ',';
565
- fill_indent(out, d2);
566
- *out->cur++ = '"';
567
- *out->cur++ = 's';
568
- *out->cur++ = 'e';
569
- *out->cur++ = 'l';
570
- *out->cur++ = 'f';
571
- *out->cur++ = '"';
572
- *out->cur++ = ':';
573
- dump_hash_class(obj, Qundef, depth + 1, out);
574
- break;
575
- default:
576
- break;
503
+ assure_size(out, d2 * out->indent + 14);
504
+ *out->cur++ = ',';
505
+ fill_indent(out, d2);
506
+ APPEND_CHARS(out->cur, "\"self\":", 7);
507
+ dump_hash_class(obj, Qundef, depth + 1, out);
508
+ break;
509
+ default: break;
577
510
  }
578
511
  {
579
- int cnt;
580
- #ifdef HAVE_RB_IVAR_COUNT
581
- cnt = (int)rb_ivar_count(obj);
582
- #else
583
- volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
584
- VALUE *np = RARRAY_PTR(vars);
585
- ID vid;
586
- const char *attr;
587
- int i;
588
- int first = 1;
589
-
590
- cnt = (int)RARRAY_LEN(vars);
591
- #endif
592
- if (Qundef != clas && 0 < cnt) {
593
- *out->cur++ = ',';
594
- }
595
- if (0 == cnt && Qundef == clas) {
596
- // Might be something special like an Enumerable.
597
- if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
598
- out->cur--;
599
- oj_dump_obj_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out);
600
- return;
601
- }
602
- }
603
- out->depth = depth + 1;
604
- #ifdef HAVE_RB_IVAR_FOREACH
605
- rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
606
- if (',' == *(out->cur - 1)) {
607
- out->cur--; // backup to overwrite last comma
608
- }
609
- #else
610
- size = d2 * out->indent + 1;
611
- for (i = cnt; 0 < i; i--, np++) {
612
- VALUE value;
613
-
614
- vid = rb_to_id(*np);
615
- attr = rb_id2name(vid);
616
- value = rb_ivar_get(obj, vid);
617
-
618
- if (oj_dump_ignore(out->opts, value)) {
619
- continue;
620
- }
621
- if (out->omit_nil && Qnil == value) {
622
- continue;
623
- }
624
- if (first) {
625
- first = 0;
626
- } else {
627
- *out->cur++ = ',';
628
- }
629
- assure_size(out, size);
630
- fill_indent(out, d2);
631
- if ('@' == *attr) {
632
- attr++;
633
- oj_dump_cstr(attr, strlen(attr), 0, 0, out);
634
- } else {
635
- char buf[32];
636
-
637
- *buf = '~';
638
- strncpy(buf + 1, attr, sizeof(buf) - 2);
639
- buf[sizeof(buf) - 1] = '\0';
640
- oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
641
- }
642
- *out->cur++ = ':';
643
- oj_dump_obj_val(value, d2, out);
644
- assure_size(out, 2);
645
- }
646
- #endif
647
- if (rb_obj_is_kind_of(obj, rb_eException)) {
648
- volatile VALUE rv;
649
-
650
- if (',' != *(out->cur - 1)) {
651
- *out->cur++ = ',';
652
- }
653
- // message
654
- assure_size(out, size);
655
- fill_indent(out, d2);
656
- oj_dump_cstr("~mesg", 5, 0, 0, out);
657
- *out->cur++ = ':';
658
- rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
659
- oj_dump_obj_val(rv, d2, out);
660
- assure_size(out, 2);
661
- *out->cur++ = ',';
662
- // backtrace
663
- assure_size(out, size);
664
- fill_indent(out, d2);
665
- oj_dump_cstr("~bt", 3, 0, 0, out);
666
- *out->cur++ = ':';
667
- rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
668
- oj_dump_obj_val(rv, d2, out);
669
- assure_size(out, 2);
670
- }
671
- out->depth = depth;
512
+ int cnt = (int)rb_ivar_count(obj);
513
+
514
+ if (Qundef != clas && 0 < cnt) {
515
+ *out->cur++ = ',';
516
+ }
517
+ if (0 == cnt && Qundef == clas) {
518
+ // Might be something special like an Enumerable.
519
+ if (Qtrue == rb_obj_is_kind_of(obj, oj_enumerable_class)) {
520
+ out->cur--;
521
+ oj_dump_obj_val(rb_funcall(obj, rb_intern("entries"), 0), depth, out);
522
+ return;
523
+ }
524
+ }
525
+ out->depth = depth + 1;
526
+ rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
527
+ if (',' == *(out->cur - 1)) {
528
+ out->cur--; // backup to overwrite last comma
529
+ }
530
+ if (rb_obj_is_kind_of(obj, rb_eException)) {
531
+ volatile VALUE rv;
532
+
533
+ if (',' != *(out->cur - 1)) {
534
+ *out->cur++ = ',';
535
+ }
536
+ // message
537
+ assure_size(out, size);
538
+ fill_indent(out, d2);
539
+ oj_dump_cstr("~mesg", 5, 0, 0, out);
540
+ *out->cur++ = ':';
541
+ rv = rb_funcall2(obj, rb_intern("message"), 0, 0);
542
+ oj_dump_obj_val(rv, d2, out);
543
+ assure_size(out, 2);
544
+ *out->cur++ = ',';
545
+ // backtrace
546
+ assure_size(out, size);
547
+ fill_indent(out, d2);
548
+ oj_dump_cstr("~bt", 3, 0, 0, out);
549
+ *out->cur++ = ':';
550
+ rv = rb_funcall2(obj, rb_intern("backtrace"), 0, 0);
551
+ oj_dump_obj_val(rv, d2, out);
552
+ assure_size(out, 2);
553
+ }
554
+ out->depth = depth;
672
555
  }
673
556
  fill_indent(out, depth);
674
557
  *out->cur++ = '}';
675
- *out->cur = '\0';
558
+ *out->cur = '\0';
676
559
  }
677
560
 
678
- static void
679
- dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
561
+ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
680
562
  dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
681
563
  }
682
564
 
683
- static void
684
- dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
685
- VALUE clas = rb_obj_class(obj);
686
- const char *class_name = rb_class2name(clas);
687
- int i;
688
- int d2 = depth + 1;
689
- int d3 = d2 + 1;
690
- size_t len = strlen(class_name);
691
- size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
565
+ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
566
+ VALUE clas = rb_obj_class(obj);
567
+ const char *class_name = rb_class2name(clas);
568
+ size_t i;
569
+ int d2 = depth + 1;
570
+ int d3 = d2 + 1;
571
+ size_t len = strlen(class_name);
572
+ size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
573
+ char circular = out->opts->circular;
692
574
 
693
575
  assure_size(out, size);
694
576
  *out->cur++ = '{';
695
577
  fill_indent(out, d2);
696
- *out->cur++ = '"';
697
- *out->cur++ = '^';
698
- *out->cur++ = 'u';
699
- *out->cur++ = '"';
700
- *out->cur++ = ':';
701
- *out->cur++ = '[';
578
+ APPEND_CHARS(out->cur, "\"^u\":[", 6);
702
579
  if ('#' == *class_name) {
703
- VALUE ma = rb_struct_s_members(clas);
704
- const char *name;
705
- int cnt = (int)RARRAY_LEN(ma);
706
-
707
- *out->cur++ = '[';
708
- for (i = 0; i < cnt; i++) {
709
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
710
-
711
- name = rb_string_value_ptr((VALUE*)&s);
712
- len = (int)RSTRING_LEN(s);
713
- size = len + 3;
714
- assure_size(out, size);
715
- if (0 < i) {
716
- *out->cur++ = ',';
717
- }
718
- *out->cur++ = '"';
719
- memcpy(out->cur, name, len);
720
- out->cur += len;
721
- *out->cur++ = '"';
722
- }
723
- *out->cur++ = ']';
580
+ VALUE ma = rb_struct_s_members(clas);
581
+ const char *name;
582
+ size_t cnt = RARRAY_LEN(ma);
583
+
584
+ *out->cur++ = '[';
585
+ for (i = 0; i < cnt; i++) {
586
+ volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
587
+
588
+ name = RSTRING_PTR(s);
589
+ len = RSTRING_LEN(s);
590
+ size = len + 3;
591
+ assure_size(out, size);
592
+ if (0 < i) {
593
+ *out->cur++ = ',';
594
+ }
595
+ *out->cur++ = '"';
596
+ APPEND_CHARS(out->cur, name, len);
597
+ *out->cur++ = '"';
598
+ }
599
+ *out->cur++ = ']';
724
600
  } else {
725
- fill_indent(out, d3);
726
- *out->cur++ = '"';
727
- memcpy(out->cur, class_name, len);
728
- out->cur += len;
729
- *out->cur++ = '"';
601
+ fill_indent(out, d3);
602
+ *out->cur++ = '"';
603
+ APPEND_CHARS(out->cur, class_name, len);
604
+ *out->cur++ = '"';
730
605
  }
731
606
  *out->cur++ = ',';
732
- size = d3 * out->indent + 2;
607
+ size = d3 * out->indent + 2;
733
608
  #ifdef RSTRUCT_LEN
734
609
  {
735
- VALUE v;
736
- int cnt;
610
+ VALUE v;
611
+ int cnt;
612
+
737
613
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
738
- cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
739
- #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
740
- cnt = (int)RSTRUCT_LEN(obj);
741
- #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
742
-
743
- for (i = 0; i < cnt; i++) {
744
- v = RSTRUCT_GET(obj, i);
745
- if (oj_dump_ignore(out->opts, v)) {
746
- v = Qnil;
747
- }
748
- assure_size(out, size);
749
- fill_indent(out, d3);
750
- oj_dump_obj_val(v, d3, out);
751
- *out->cur++ = ',';
752
- }
614
+ cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
615
+ #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
616
+ cnt = (int)RSTRUCT_LEN(obj);
617
+ #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
618
+
619
+ if (0 == strcmp(class_name, "Range")) {
620
+ out->opts->circular = 'n';
621
+ }
622
+ for (i = 0; i < (size_t)cnt; i++) {
623
+ v = RSTRUCT_GET(obj, (int)i);
624
+ if (dump_ignore(out->opts, v)) {
625
+ v = Qnil;
626
+ }
627
+ assure_size(out, size);
628
+ fill_indent(out, d3);
629
+ oj_dump_obj_val(v, d3, out);
630
+ *out->cur++ = ',';
631
+ }
753
632
  }
754
633
  #else
755
634
  {
756
- // This is a bit risky as a struct in C ruby is not the same as a Struct
757
- // class in interpreted Ruby so length() may not be defined.
758
- int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
759
-
760
- for (i = 0; i < slen; i++) {
761
- assure_size(out, size);
762
- fill_indent(out, d3);
763
- if (oj_dump_ignore(out->opts, v)) {
764
- v = Qnil;
765
- }
766
- oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true);
767
- *out->cur++ = ',';
768
- }
635
+ // This is a bit risky as a struct in C ruby is not the same as a Struct
636
+ // class in interpreted Ruby so length() may not be defined.
637
+ int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
638
+
639
+ if (0 == strcmp(class_name, "Range")) {
640
+ out->opts->circular = 'n';
641
+ }
642
+ for (i = 0; i < slen; i++) {
643
+ assure_size(out, size);
644
+ fill_indent(out, d3);
645
+ if (dump_ignore(out->opts, v)) {
646
+ v = Qnil;
647
+ }
648
+ oj_dump_obj_val(rb_struct_aref(obj, INT2FIX(i)), d3, out, 0, 0, true);
649
+ *out->cur++ = ',';
650
+ }
769
651
  }
770
652
  #endif
653
+ out->opts->circular = circular;
771
654
  out->cur--;
772
- *out->cur++ = ']';
773
- *out->cur++ = '}';
655
+ APPEND_CHARS(out->cur, "]}", 2);
774
656
  *out->cur = '\0';
775
657
  }
776
658
 
777
- static void
778
- dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
659
+ static void dump_complex(VALUE obj, int depth, Out out, bool as_ok) {
779
660
  dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
780
661
  }
781
662
 
782
- static void
783
- dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
663
+ static void dump_rational(VALUE obj, int depth, Out out, bool as_ok) {
784
664
  dump_obj_attrs(obj, rb_obj_class(obj), 0, depth, out);
785
665
  }
786
666
 
787
- static DumpFunc obj_funcs[] = {
788
- NULL, // RUBY_T_NONE = 0x00,
789
- dump_obj, // RUBY_T_OBJECT = 0x01,
790
- dump_class, // RUBY_T_CLASS = 0x02,
791
- dump_class, // RUBY_T_MODULE = 0x03,
792
- oj_dump_float, // RUBY_T_FLOAT = 0x04,
793
- dump_str, // RUBY_T_STRING = 0x05,
794
- dump_regexp, // RUBY_T_REGEXP = 0x06,
795
- dump_array, // RUBY_T_ARRAY = 0x07,
796
- dump_hash, // RUBY_T_HASH = 0x08,
797
- dump_struct, // RUBY_T_STRUCT = 0x09,
798
- oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
799
- NULL, // RUBY_T_FILE = 0x0b,
800
- dump_data, // RUBY_T_DATA = 0x0c,
801
- NULL, // RUBY_T_MATCH = 0x0d,
802
- dump_complex, // RUBY_T_COMPLEX = 0x0e,
803
- dump_rational, // RUBY_T_RATIONAL = 0x0f,
804
- NULL, // 0x10
805
- oj_dump_nil, // RUBY_T_NIL = 0x11,
806
- oj_dump_true, // RUBY_T_TRUE = 0x12,
807
- oj_dump_false, // RUBY_T_FALSE = 0x13,
808
- dump_sym, // RUBY_T_SYMBOL = 0x14,
809
- oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
667
+ static DumpFunc obj_funcs[] = {
668
+ NULL, // RUBY_T_NONE = 0x00,
669
+ dump_obj, // RUBY_T_OBJECT = 0x01,
670
+ dump_class, // RUBY_T_CLASS = 0x02,
671
+ dump_class, // RUBY_T_MODULE = 0x03,
672
+ oj_dump_float, // RUBY_T_FLOAT = 0x04,
673
+ dump_str, // RUBY_T_STRING = 0x05,
674
+ dump_regexp, // RUBY_T_REGEXP = 0x06,
675
+ dump_array, // RUBY_T_ARRAY = 0x07,
676
+ dump_hash, // RUBY_T_HASH = 0x08,
677
+ dump_struct, // RUBY_T_STRUCT = 0x09,
678
+ oj_dump_bignum, // RUBY_T_BIGNUM = 0x0a,
679
+ NULL, // RUBY_T_FILE = 0x0b,
680
+ dump_data, // RUBY_T_DATA = 0x0c,
681
+ NULL, // RUBY_T_MATCH = 0x0d,
682
+ dump_complex, // RUBY_T_COMPLEX = 0x0e,
683
+ dump_rational, // RUBY_T_RATIONAL = 0x0f,
684
+ NULL, // 0x10
685
+ oj_dump_nil, // RUBY_T_NIL = 0x11,
686
+ oj_dump_true, // RUBY_T_TRUE = 0x12,
687
+ oj_dump_false, // RUBY_T_FALSE = 0x13,
688
+ dump_sym, // RUBY_T_SYMBOL = 0x14,
689
+ oj_dump_fixnum, // RUBY_T_FIXNUM = 0x15,
810
690
  };
811
691
 
812
- void
813
- oj_dump_obj_val(VALUE obj, int depth, Out out) {
814
- int type = rb_type(obj);
815
-
816
- if (Yes == out->opts->trace) {
817
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
818
- }
692
+ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
693
+ int type = rb_type(obj);
694
+
695
+ TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
819
696
  if (MAX_DEPTH < depth) {
820
- rb_raise(rb_eNoMemError, "Too deeply nested.\n");
697
+ rb_raise(rb_eNoMemError, "Too deeply nested.\n");
821
698
  }
822
699
  if (0 < type && type <= RUBY_T_FIXNUM) {
823
- DumpFunc f = obj_funcs[type];
824
-
825
- if (NULL != f) {
826
- f(obj, depth, out, false);
827
- if (Yes == out->opts->trace) {
828
- oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
829
- }
830
- return;
831
- }
700
+ DumpFunc f = obj_funcs[type];
701
+
702
+ if (NULL != f) {
703
+ f(obj, depth, out, false);
704
+ TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
705
+ return;
706
+ }
832
707
  }
833
708
  oj_dump_nil(Qnil, depth, out, false);
834
- if (Yes == out->opts->trace) {
835
- oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
836
- }
709
+ TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
837
710
  }