oj 3.7.4 → 3.13.21

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1352 -0
  3. data/README.md +29 -8
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +53 -72
  6. data/ext/oj/cache.c +326 -0
  7. data/ext/oj/cache.h +21 -0
  8. data/ext/oj/cache8.c +61 -64
  9. data/ext/oj/cache8.h +12 -39
  10. data/ext/oj/circarray.c +37 -43
  11. data/ext/oj/circarray.h +16 -17
  12. data/ext/oj/code.c +165 -179
  13. data/ext/oj/code.h +27 -29
  14. data/ext/oj/compat.c +174 -194
  15. data/ext/oj/custom.c +809 -866
  16. data/ext/oj/debug.c +132 -0
  17. data/ext/oj/dump.c +848 -863
  18. data/ext/oj/dump.h +81 -67
  19. data/ext/oj/dump_compat.c +85 -123
  20. data/ext/oj/dump_leaf.c +100 -188
  21. data/ext/oj/dump_object.c +527 -656
  22. data/ext/oj/dump_strict.c +315 -338
  23. data/ext/oj/encode.h +7 -34
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +40 -29
  26. data/ext/oj/err.h +48 -48
  27. data/ext/oj/extconf.rb +17 -4
  28. data/ext/oj/fast.c +1070 -1087
  29. data/ext/oj/intern.c +301 -0
  30. data/ext/oj/intern.h +26 -0
  31. data/ext/oj/mimic_json.c +469 -436
  32. data/ext/oj/object.c +525 -593
  33. data/ext/oj/odd.c +154 -138
  34. data/ext/oj/odd.h +37 -38
  35. data/ext/oj/oj.c +1325 -986
  36. data/ext/oj/oj.h +333 -316
  37. data/ext/oj/parse.c +1002 -846
  38. data/ext/oj/parse.h +92 -87
  39. data/ext/oj/parser.c +1557 -0
  40. data/ext/oj/parser.h +91 -0
  41. data/ext/oj/rails.c +888 -878
  42. data/ext/oj/rails.h +11 -14
  43. data/ext/oj/reader.c +141 -147
  44. data/ext/oj/reader.h +73 -89
  45. data/ext/oj/resolve.c +41 -62
  46. data/ext/oj/resolve.h +7 -9
  47. data/ext/oj/rxclass.c +71 -75
  48. data/ext/oj/rxclass.h +18 -19
  49. data/ext/oj/saj.c +443 -486
  50. data/ext/oj/saj2.c +602 -0
  51. data/ext/oj/scp.c +88 -113
  52. data/ext/oj/sparse.c +787 -709
  53. data/ext/oj/stream_writer.c +133 -159
  54. data/ext/oj/strict.c +127 -118
  55. data/ext/oj/string_writer.c +230 -249
  56. data/ext/oj/trace.c +34 -41
  57. data/ext/oj/trace.h +19 -19
  58. data/ext/oj/usual.c +1254 -0
  59. data/ext/oj/util.c +136 -0
  60. data/ext/oj/util.h +20 -0
  61. data/ext/oj/val_stack.c +59 -67
  62. data/ext/oj/val_stack.h +91 -129
  63. data/ext/oj/validate.c +46 -0
  64. data/ext/oj/wab.c +342 -353
  65. data/lib/oj/bag.rb +1 -0
  66. data/lib/oj/easy_hash.rb +5 -4
  67. data/lib/oj/error.rb +1 -1
  68. data/lib/oj/json.rb +1 -1
  69. data/lib/oj/mimic.rb +48 -14
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/state.rb +8 -7
  72. data/lib/oj/version.rb +2 -2
  73. data/lib/oj.rb +0 -8
  74. data/pages/Compatibility.md +1 -1
  75. data/pages/JsonGem.md +15 -0
  76. data/pages/Modes.md +53 -46
  77. data/pages/Options.md +72 -11
  78. data/pages/Parser.md +309 -0
  79. data/pages/Rails.md +73 -22
  80. data/pages/Security.md +1 -1
  81. data/test/activerecord/result_test.rb +7 -2
  82. data/test/activesupport5/abstract_unit.rb +45 -0
  83. data/test/activesupport5/decoding_test.rb +68 -60
  84. data/test/activesupport5/encoding_test.rb +111 -96
  85. data/test/activesupport5/encoding_test_cases.rb +33 -25
  86. data/test/activesupport5/test_helper.rb +43 -21
  87. data/test/activesupport5/time_zone_test_helpers.rb +18 -3
  88. data/test/activesupport6/abstract_unit.rb +44 -0
  89. data/test/activesupport6/decoding_test.rb +133 -0
  90. data/test/activesupport6/encoding_test.rb +507 -0
  91. data/test/activesupport6/encoding_test_cases.rb +98 -0
  92. data/test/activesupport6/test_common.rb +17 -0
  93. data/test/activesupport6/test_helper.rb +163 -0
  94. data/test/activesupport6/time_zone_test_helpers.rb +39 -0
  95. data/test/activesupport7/abstract_unit.rb +49 -0
  96. data/test/activesupport7/decoding_test.rb +125 -0
  97. data/test/activesupport7/encoding_test.rb +486 -0
  98. data/test/activesupport7/encoding_test_cases.rb +104 -0
  99. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  100. data/test/bar.rb +6 -12
  101. data/test/baz.rb +16 -0
  102. data/test/bug.rb +16 -0
  103. data/test/foo.rb +69 -75
  104. data/test/helper.rb +16 -0
  105. data/test/json_gem/json_common_interface_test.rb +8 -3
  106. data/test/json_gem/json_generator_test.rb +18 -4
  107. data/test/json_gem/json_parser_test.rb +9 -0
  108. data/test/json_gem/test_helper.rb +12 -0
  109. data/test/mem.rb +33 -0
  110. data/test/perf.rb +1 -1
  111. data/test/perf_dump.rb +50 -0
  112. data/test/perf_once.rb +58 -0
  113. data/test/perf_parser.rb +189 -0
  114. data/test/perf_scp.rb +11 -10
  115. data/test/perf_strict.rb +17 -23
  116. data/test/prec.rb +23 -0
  117. data/test/sample_json.rb +1 -1
  118. data/test/test_compat.rb +46 -10
  119. data/test/test_custom.rb +147 -8
  120. data/test/test_fast.rb +62 -2
  121. data/test/test_file.rb +25 -2
  122. data/test/test_gc.rb +13 -0
  123. data/test/test_generate.rb +21 -0
  124. data/test/test_hash.rb +11 -1
  125. data/test/test_integer_range.rb +7 -2
  126. data/test/test_object.rb +85 -9
  127. data/test/test_parser.rb +27 -0
  128. data/test/test_parser_saj.rb +335 -0
  129. data/test/test_parser_usual.rb +217 -0
  130. data/test/test_rails.rb +35 -0
  131. data/test/test_saj.rb +1 -1
  132. data/test/test_scp.rb +5 -5
  133. data/test/test_strict.rb +26 -1
  134. data/test/test_various.rb +87 -65
  135. data/test/test_wab.rb +2 -0
  136. data/test/test_writer.rb +19 -2
  137. data/test/tests.rb +1 -1
  138. data/test/zoo.rb +13 -0
  139. metadata +60 -110
  140. data/ext/oj/hash.c +0 -163
  141. data/ext/oj/hash.h +0 -46
  142. data/ext/oj/hash_test.c +0 -512
data/ext/oj/dump_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
  }