oj 3.7.4 → 3.13.21

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