oj 3.9.1 → 3.16.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1452 -0
  3. data/README.md +21 -6
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +50 -68
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +60 -62
  9. data/ext/oj/cache8.h +9 -36
  10. data/ext/oj/circarray.c +38 -42
  11. data/ext/oj/circarray.h +12 -13
  12. data/ext/oj/code.c +158 -179
  13. data/ext/oj/code.h +20 -22
  14. data/ext/oj/compat.c +145 -205
  15. data/ext/oj/custom.c +740 -880
  16. data/ext/oj/debug.c +126 -0
  17. data/ext/oj/dump.c +1145 -844
  18. data/ext/oj/dump.h +71 -57
  19. data/ext/oj/dump_compat.c +575 -655
  20. data/ext/oj/dump_leaf.c +96 -186
  21. data/ext/oj/dump_object.c +533 -660
  22. data/ext/oj/dump_strict.c +306 -340
  23. data/ext/oj/encode.h +4 -33
  24. data/ext/oj/encoder.c +43 -0
  25. data/ext/oj/err.c +28 -28
  26. data/ext/oj/err.h +39 -42
  27. data/ext/oj/extconf.rb +28 -7
  28. data/ext/oj/fast.c +1052 -1113
  29. data/ext/oj/intern.c +313 -0
  30. data/ext/oj/intern.h +22 -0
  31. data/ext/oj/mem.c +318 -0
  32. data/ext/oj/mem.h +53 -0
  33. data/ext/oj/mimic_json.c +471 -430
  34. data/ext/oj/object.c +532 -580
  35. data/ext/oj/odd.c +156 -142
  36. data/ext/oj/odd.h +25 -26
  37. data/ext/oj/oj.c +1346 -961
  38. data/ext/oj/oj.h +307 -290
  39. data/ext/oj/parse.c +954 -858
  40. data/ext/oj/parse.h +74 -72
  41. data/ext/oj/parser.c +1600 -0
  42. data/ext/oj/parser.h +103 -0
  43. data/ext/oj/rails.c +819 -836
  44. data/ext/oj/rails.h +8 -11
  45. data/ext/oj/reader.c +136 -147
  46. data/ext/oj/reader.h +69 -83
  47. data/ext/oj/resolve.c +41 -63
  48. data/ext/oj/resolve.h +4 -6
  49. data/ext/oj/rxclass.c +69 -72
  50. data/ext/oj/rxclass.h +12 -13
  51. data/ext/oj/saj.c +440 -485
  52. data/ext/oj/saj2.c +584 -0
  53. data/ext/oj/saj2.h +23 -0
  54. data/ext/oj/scp.c +79 -118
  55. data/ext/oj/simd.h +10 -0
  56. data/ext/oj/sparse.c +739 -709
  57. data/ext/oj/stream_writer.c +141 -175
  58. data/ext/oj/strict.c +103 -128
  59. data/ext/oj/string_writer.c +244 -261
  60. data/ext/oj/trace.c +34 -41
  61. data/ext/oj/trace.h +42 -15
  62. data/ext/oj/usual.c +1218 -0
  63. data/ext/oj/usual.h +69 -0
  64. data/ext/oj/util.c +107 -107
  65. data/ext/oj/util.h +4 -3
  66. data/ext/oj/val_stack.c +61 -78
  67. data/ext/oj/val_stack.h +80 -114
  68. data/ext/oj/validate.c +46 -0
  69. data/ext/oj/wab.c +316 -361
  70. data/lib/oj/active_support_helper.rb +1 -3
  71. data/lib/oj/bag.rb +8 -1
  72. data/lib/oj/easy_hash.rb +9 -9
  73. data/lib/oj/error.rb +1 -2
  74. data/lib/oj/json.rb +162 -150
  75. data/lib/oj/mimic.rb +54 -20
  76. data/lib/oj/saj.rb +20 -6
  77. data/lib/oj/schandler.rb +5 -4
  78. data/lib/oj/state.rb +12 -8
  79. data/lib/oj/version.rb +1 -2
  80. data/lib/oj.rb +2 -8
  81. data/pages/Compatibility.md +1 -1
  82. data/pages/Encoding.md +1 -1
  83. data/pages/InstallOptions.md +20 -0
  84. data/pages/JsonGem.md +15 -0
  85. data/pages/Modes.md +9 -3
  86. data/pages/Options.md +62 -12
  87. data/pages/Parser.md +309 -0
  88. data/pages/Rails.md +73 -22
  89. metadata +68 -192
  90. data/ext/oj/hash.c +0 -163
  91. data/ext/oj/hash.h +0 -46
  92. data/ext/oj/hash_test.c +0 -512
  93. data/test/_test_active.rb +0 -76
  94. data/test/_test_active_mimic.rb +0 -96
  95. data/test/_test_mimic_rails.rb +0 -126
  96. data/test/activerecord/result_test.rb +0 -27
  97. data/test/activesupport4/decoding_test.rb +0 -108
  98. data/test/activesupport4/encoding_test.rb +0 -531
  99. data/test/activesupport4/test_helper.rb +0 -41
  100. data/test/activesupport5/decoding_test.rb +0 -125
  101. data/test/activesupport5/encoding_test.rb +0 -485
  102. data/test/activesupport5/encoding_test_cases.rb +0 -90
  103. data/test/activesupport5/test_helper.rb +0 -50
  104. data/test/activesupport5/time_zone_test_helpers.rb +0 -24
  105. data/test/bar.rb +0 -25
  106. data/test/files.rb +0 -29
  107. data/test/foo.rb +0 -21
  108. data/test/helper.rb +0 -26
  109. data/test/isolated/shared.rb +0 -308
  110. data/test/isolated/test_mimic_after.rb +0 -13
  111. data/test/isolated/test_mimic_alone.rb +0 -12
  112. data/test/isolated/test_mimic_as_json.rb +0 -45
  113. data/test/isolated/test_mimic_before.rb +0 -13
  114. data/test/isolated/test_mimic_define.rb +0 -28
  115. data/test/isolated/test_mimic_rails_after.rb +0 -22
  116. data/test/isolated/test_mimic_rails_before.rb +0 -21
  117. data/test/isolated/test_mimic_redefine.rb +0 -15
  118. data/test/json_gem/json_addition_test.rb +0 -216
  119. data/test/json_gem/json_common_interface_test.rb +0 -148
  120. data/test/json_gem/json_encoding_test.rb +0 -107
  121. data/test/json_gem/json_ext_parser_test.rb +0 -20
  122. data/test/json_gem/json_fixtures_test.rb +0 -35
  123. data/test/json_gem/json_generator_test.rb +0 -383
  124. data/test/json_gem/json_generic_object_test.rb +0 -90
  125. data/test/json_gem/json_parser_test.rb +0 -470
  126. data/test/json_gem/json_string_matching_test.rb +0 -42
  127. data/test/json_gem/test_helper.rb +0 -18
  128. data/test/perf.rb +0 -107
  129. data/test/perf_compat.rb +0 -130
  130. data/test/perf_fast.rb +0 -164
  131. data/test/perf_file.rb +0 -64
  132. data/test/perf_object.rb +0 -138
  133. data/test/perf_saj.rb +0 -109
  134. data/test/perf_scp.rb +0 -151
  135. data/test/perf_simple.rb +0 -287
  136. data/test/perf_strict.rb +0 -145
  137. data/test/perf_wab.rb +0 -131
  138. data/test/sample/change.rb +0 -14
  139. data/test/sample/dir.rb +0 -19
  140. data/test/sample/doc.rb +0 -36
  141. data/test/sample/file.rb +0 -48
  142. data/test/sample/group.rb +0 -16
  143. data/test/sample/hasprops.rb +0 -16
  144. data/test/sample/layer.rb +0 -12
  145. data/test/sample/line.rb +0 -20
  146. data/test/sample/oval.rb +0 -10
  147. data/test/sample/rect.rb +0 -10
  148. data/test/sample/shape.rb +0 -35
  149. data/test/sample/text.rb +0 -20
  150. data/test/sample.rb +0 -54
  151. data/test/sample_json.rb +0 -37
  152. data/test/test_compat.rb +0 -509
  153. data/test/test_custom.rb +0 -503
  154. data/test/test_debian.rb +0 -53
  155. data/test/test_fast.rb +0 -470
  156. data/test/test_file.rb +0 -239
  157. data/test/test_gc.rb +0 -49
  158. data/test/test_hash.rb +0 -29
  159. data/test/test_integer_range.rb +0 -73
  160. data/test/test_null.rb +0 -376
  161. data/test/test_object.rb +0 -1018
  162. data/test/test_saj.rb +0 -186
  163. data/test/test_scp.rb +0 -433
  164. data/test/test_strict.rb +0 -410
  165. data/test/test_various.rb +0 -741
  166. data/test/test_wab.rb +0 -307
  167. data/test/test_writer.rb +0 -380
  168. data/test/tests.rb +0 -24
  169. data/test/tests_mimic.rb +0 -14
  170. data/test/tests_mimic_addition.rb +0 -7
  171. data/test/zoo.rb +0 -13
@@ -1,259 +1,259 @@
1
- /* strwriter.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 "encode.h"
6
+ #include "mem.h"
8
7
 
9
- extern VALUE Oj;
8
+ extern VALUE Oj;
10
9
 
11
- bool string_writer_optimized = false;
10
+ bool string_writer_optimized = false;
12
11
 
13
- static void
14
- key_check(StrWriter sw, const char *key) {
15
- DumpType type = sw->types[sw->depth];
12
+ static void key_check(StrWriter sw, const char *key) {
13
+ DumpType type = sw->types[sw->depth];
16
14
 
17
15
  if (0 == key && (ObjectNew == type || ObjectType == type)) {
18
- rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
16
+ rb_raise(rb_eStandardError, "Can not push onto an Object without a key.");
19
17
  }
20
18
  }
21
19
 
22
- static void
23
- push_type(StrWriter sw, DumpType type) {
20
+ static void push_type(StrWriter sw, DumpType type) {
24
21
  if (sw->types_end <= sw->types + sw->depth + 1) {
25
- size_t size = (sw->types_end - sw->types) * 2;
22
+ size_t size = (sw->types_end - sw->types) * 2;
26
23
 
27
- REALLOC_N(sw->types, char, size);
28
- sw->types_end = sw->types + size;
24
+ OJ_R_REALLOC_N(sw->types, char, size);
25
+ sw->types_end = sw->types + size;
29
26
  }
30
27
  sw->depth++;
31
28
  sw->types[sw->depth] = type;
32
29
  }
33
30
 
34
- static void
35
- maybe_comma(StrWriter sw) {
31
+ static void maybe_comma(StrWriter sw) {
36
32
  switch (sw->types[sw->depth]) {
37
- case ObjectNew:
38
- sw->types[sw->depth] = ObjectType;
39
- break;
40
- case ArrayNew:
41
- sw->types[sw->depth] = ArrayType;
42
- break;
33
+ case ObjectNew: sw->types[sw->depth] = ObjectType; break;
34
+ case ArrayNew: sw->types[sw->depth] = ArrayType; break;
43
35
  case ObjectType:
44
36
  case ArrayType:
45
- // Always have a few characters available in the out.buf.
46
- *sw->out.cur++ = ',';
47
- break;
37
+ // Always have a few characters available in the out.buf.
38
+ *sw->out.cur++ = ',';
39
+ break;
48
40
  }
49
41
  }
50
42
 
51
43
  // Used by stream writer also.
52
- void
53
- oj_str_writer_init(StrWriter sw, int buf_size) {
54
- sw->opts = oj_default_options;
55
- sw->depth = 0;
56
- sw->types = ALLOC_N(char, 256);
57
- sw->types_end = sw->types + 256;
58
- *sw->types = '\0';
44
+ void oj_str_writer_init(StrWriter sw, int buf_size) {
45
+ sw->opts = oj_default_options;
46
+ sw->depth = 0;
47
+ sw->types = OJ_R_ALLOC_N(char, 256);
48
+ sw->types_end = sw->types + 256;
49
+ *sw->types = '\0';
59
50
  sw->keyWritten = 0;
60
51
 
61
52
  if (0 == buf_size) {
62
- buf_size = 4096;
53
+ buf_size = 4096;
63
54
  } else if (buf_size < 1024) {
64
- buf_size = 1024;
55
+ buf_size = 1024;
65
56
  }
66
- sw->out.buf = ALLOC_N(char, buf_size);
67
- sw->out.end = sw->out.buf + buf_size - 10;
57
+ // Must be allocated. Using the out.stack_buffer results in double frees
58
+ // and I haven't figured out why yet.
59
+ sw->out.buf = OJ_R_ALLOC_N(char, buf_size);
60
+ sw->out.cur = sw->out.buf;
61
+ sw->out.end = sw->out.buf + buf_size - BUFFER_EXTRA;
68
62
  sw->out.allocated = true;
69
- sw->out.cur = sw->out.buf;
70
- *sw->out.cur = '\0';
63
+
64
+ *sw->out.cur = '\0';
71
65
  sw->out.circ_cache = NULL;
72
- sw->out.circ_cnt = 0;
73
- sw->out.hash_cnt = 0;
74
- sw->out.opts = &sw->opts;
75
- sw->out.indent = sw->opts.indent;
76
- sw->out.depth = 0;
77
- sw->out.argc = 0;
78
- sw->out.argv = NULL;
79
- sw->out.caller = 0;
80
- sw->out.ropts = NULL;
81
- sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
66
+ sw->out.circ_cnt = 0;
67
+ sw->out.hash_cnt = 0;
68
+ sw->out.opts = &sw->opts;
69
+ sw->out.indent = sw->opts.indent;
70
+ sw->out.depth = 0;
71
+ sw->out.argc = 0;
72
+ sw->out.argv = NULL;
73
+ sw->out.ropts = NULL;
74
+ sw->out.omit_nil = oj_default_options.dump_opts.omit_nil;
82
75
  }
83
76
 
84
- void
85
- oj_str_writer_push_key(StrWriter sw, const char *key) {
86
- DumpType type = sw->types[sw->depth];
87
- long size;
77
+ void oj_str_writer_push_key(StrWriter sw, const char *key) {
78
+ DumpType type = sw->types[sw->depth];
79
+ long size;
88
80
 
89
81
  if (sw->keyWritten) {
90
- rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
82
+ rb_raise(rb_eStandardError, "Can not push more than one key before pushing a non-key.");
91
83
  }
92
84
  if (ObjectNew != type && ObjectType != type) {
93
- rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
85
+ rb_raise(rb_eStandardError, "Can only push a key onto an Object.");
94
86
  }
95
87
  size = sw->depth * sw->out.indent + 3;
96
88
  assure_size(&sw->out, size);
97
89
  maybe_comma(sw);
98
90
  if (0 < sw->depth) {
99
- fill_indent(&sw->out, sw->depth);
91
+ fill_indent(&sw->out, sw->depth);
100
92
  }
101
93
  oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
102
94
  *sw->out.cur++ = ':';
103
95
  sw->keyWritten = 1;
104
96
  }
105
97
 
106
- void
107
- oj_str_writer_push_object(StrWriter sw, const char *key) {
98
+ void oj_str_writer_push_object(StrWriter sw, const char *key) {
108
99
  if (sw->keyWritten) {
109
- sw->keyWritten = 0;
110
- assure_size(&sw->out, 1);
100
+ sw->keyWritten = 0;
101
+ assure_size(&sw->out, 1);
111
102
  } else {
112
- long size;
113
-
114
- key_check(sw, key);
115
- size = sw->depth * sw->out.indent + 3;
116
- assure_size(&sw->out, size);
117
- maybe_comma(sw);
118
- if (0 < sw->depth) {
119
- fill_indent(&sw->out, sw->depth);
120
- }
121
- if (0 != key) {
122
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
123
- *sw->out.cur++ = ':';
124
- }
103
+ long size;
104
+
105
+ key_check(sw, key);
106
+ size = sw->depth * sw->out.indent + 3;
107
+ assure_size(&sw->out, size);
108
+ maybe_comma(sw);
109
+ if (0 < sw->depth) {
110
+ fill_indent(&sw->out, sw->depth);
111
+ }
112
+ if (0 != key) {
113
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
114
+ *sw->out.cur++ = ':';
115
+ }
125
116
  }
126
117
  *sw->out.cur++ = '{';
127
118
  push_type(sw, ObjectNew);
128
119
  }
129
120
 
130
- void
131
- oj_str_writer_push_array(StrWriter sw, const char *key) {
121
+ void oj_str_writer_push_array(StrWriter sw, const char *key) {
132
122
  if (sw->keyWritten) {
133
- sw->keyWritten = 0;
134
- assure_size(&sw->out, 1);
123
+ sw->keyWritten = 0;
124
+ assure_size(&sw->out, 1);
135
125
  } else {
136
- long size;
137
-
138
- key_check(sw, key);
139
- size = sw->depth * sw->out.indent + 3;
140
- assure_size(&sw->out, size);
141
- maybe_comma(sw);
142
- if (0 < sw->depth) {
143
- fill_indent(&sw->out, sw->depth);
144
- }
145
- if (0 != key) {
146
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
147
- *sw->out.cur++ = ':';
148
- }
126
+ long size;
127
+
128
+ key_check(sw, key);
129
+ size = sw->depth * sw->out.indent + 3;
130
+ assure_size(&sw->out, size);
131
+ maybe_comma(sw);
132
+ if (0 < sw->depth) {
133
+ fill_indent(&sw->out, sw->depth);
134
+ }
135
+ if (0 != key) {
136
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
137
+ *sw->out.cur++ = ':';
138
+ }
149
139
  }
150
140
  *sw->out.cur++ = '[';
151
141
  push_type(sw, ArrayNew);
152
142
  }
153
143
 
154
- void
155
- oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
156
- Out out = &sw->out;
144
+ void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
145
+ Out out = &sw->out;
157
146
 
158
147
  if (sw->keyWritten) {
159
- sw->keyWritten = 0;
148
+ sw->keyWritten = 0;
160
149
  } else {
161
- long size;
162
-
163
- key_check(sw, key);
164
- size = sw->depth * out->indent + 3;
165
- assure_size(out, size);
166
- maybe_comma(sw);
167
- if (0 < sw->depth) {
168
- fill_indent(&sw->out, sw->depth);
169
- }
170
- if (0 != key) {
171
- oj_dump_cstr(key, strlen(key), 0, 0, out);
172
- *out->cur++ = ':';
173
- }
150
+ long size;
151
+
152
+ key_check(sw, key);
153
+ size = sw->depth * out->indent + 3;
154
+ assure_size(out, size);
155
+ maybe_comma(sw);
156
+ if (0 < sw->depth) {
157
+ fill_indent(&sw->out, sw->depth);
158
+ }
159
+ if (0 != key) {
160
+ oj_dump_cstr(key, strlen(key), 0, 0, out);
161
+ *out->cur++ = ':';
162
+ }
174
163
  }
175
164
  switch (out->opts->mode) {
176
- case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
177
- case NullMode: oj_dump_null_val(val, sw->depth, out); break;
178
- case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
179
- case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
180
- case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
181
- case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
182
- default: oj_dump_custom_val(val, sw->depth, out, true); break;
165
+ case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
166
+ case NullMode: oj_dump_null_val(val, sw->depth, out); break;
167
+ case ObjectMode: oj_dump_obj_val(val, sw->depth, out); break;
168
+ case CompatMode: oj_dump_compat_val(val, sw->depth, out, Yes == out->opts->to_json); break;
169
+ case RailsMode: oj_dump_rails_val(val, sw->depth, out); break;
170
+ case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
171
+ default: oj_dump_custom_val(val, sw->depth, out, true); break;
183
172
  }
184
173
  }
185
174
 
186
- void
187
- oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
175
+ void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
188
176
  if (sw->keyWritten) {
189
- sw->keyWritten = 0;
177
+ sw->keyWritten = 0;
190
178
  } else {
191
- long size;
192
-
193
- key_check(sw, key);
194
- size = sw->depth * sw->out.indent + 3;
195
- assure_size(&sw->out, size);
196
- maybe_comma(sw);
197
- if (0 < sw->depth) {
198
- fill_indent(&sw->out, sw->depth);
199
- }
200
- if (0 != key) {
201
- oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
202
- *sw->out.cur++ = ':';
203
- }
179
+ long size;
180
+
181
+ key_check(sw, key);
182
+ size = sw->depth * sw->out.indent + 3;
183
+ assure_size(&sw->out, size);
184
+ maybe_comma(sw);
185
+ if (0 < sw->depth) {
186
+ fill_indent(&sw->out, sw->depth);
187
+ }
188
+ if (0 != key) {
189
+ oj_dump_cstr(key, strlen(key), 0, 0, &sw->out);
190
+ *sw->out.cur++ = ':';
191
+ }
204
192
  }
205
193
  oj_dump_raw(json, strlen(json), &sw->out);
206
194
  }
207
195
 
208
- void
209
- oj_str_writer_pop(StrWriter sw) {
210
- long size;
211
- DumpType type = sw->types[sw->depth];
196
+ void oj_str_writer_pop(StrWriter sw) {
197
+ long size;
198
+ DumpType type = sw->types[sw->depth];
212
199
 
213
200
  if (sw->keyWritten) {
214
- sw->keyWritten = 0;
215
- rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
201
+ sw->keyWritten = 0;
202
+ rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
216
203
  }
217
204
  sw->depth--;
218
205
  if (0 > sw->depth) {
219
- rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
206
+ rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
220
207
  }
221
208
  size = sw->depth * sw->out.indent + 2;
222
209
  assure_size(&sw->out, size);
223
210
  fill_indent(&sw->out, sw->depth);
224
211
  switch (type) {
225
212
  case ObjectNew:
226
- case ObjectType:
227
- *sw->out.cur++ = '}';
228
- break;
213
+ case ObjectType: *sw->out.cur++ = '}'; break;
229
214
  case ArrayNew:
230
- case ArrayType:
231
- *sw->out.cur++ = ']';
232
- break;
215
+ case ArrayType: *sw->out.cur++ = ']'; break;
233
216
  }
234
217
  if (0 == sw->depth && 0 <= sw->out.indent) {
235
- *sw->out.cur++ = '\n';
218
+ *sw->out.cur++ = '\n';
236
219
  }
237
220
  }
238
221
 
239
- void
240
- oj_str_writer_pop_all(StrWriter sw) {
222
+ void oj_str_writer_pop_all(StrWriter sw) {
241
223
  while (0 < sw->depth) {
242
- oj_str_writer_pop(sw);
224
+ oj_str_writer_pop(sw);
243
225
  }
244
226
  }
245
227
 
246
- static void
247
- str_writer_free(void *ptr) {
248
- StrWriter sw;
228
+ static void string_writer_free(void *ptr) {
229
+ StrWriter sw;
249
230
 
250
231
  if (0 == ptr) {
251
- return;
232
+ return;
252
233
  }
253
234
  sw = (StrWriter)ptr;
254
- xfree(sw->out.buf);
255
- xfree(sw->types);
256
- xfree(ptr);
235
+
236
+ oj_out_free(&sw->out);
237
+
238
+ OJ_R_FREE(sw->types);
239
+ OJ_R_FREE(ptr);
240
+ }
241
+
242
+ static const rb_data_type_t oj_string_writer_type = {
243
+ "Oj/string_writer",
244
+ {
245
+ NULL,
246
+ string_writer_free,
247
+ NULL,
248
+ },
249
+ 0,
250
+ 0,
251
+ };
252
+
253
+ StrWriter oj_str_writer_unwrap(VALUE writer) {
254
+ StrWriter sw;
255
+ TypedData_Get_Struct(writer, struct _strWriter, &oj_string_writer_type, sw);
256
+ return sw;
257
257
  }
258
258
 
259
259
  /* Document-method: new
@@ -270,21 +270,20 @@ str_writer_free(void *ptr) {
270
270
  * should be.
271
271
  *
272
272
  * - *io* [_IO_] stream to write to
273
- * - *options* [_Hash_] formating options
273
+ * - *options* [_Hash_] formatting options
274
274
  */
275
- static VALUE
276
- str_writer_new(int argc, VALUE *argv, VALUE self) {
277
- StrWriter sw = ALLOC(struct _strWriter);
275
+ static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
276
+ StrWriter sw = OJ_R_ALLOC(struct _strWriter);
278
277
 
279
278
  oj_str_writer_init(sw, 0);
280
279
  if (1 == argc) {
281
- oj_parse_options(argv[0], &sw->opts);
280
+ oj_parse_options(argv[0], &sw->opts);
282
281
  }
283
- sw->out.argc = argc - 1;
284
- sw->out.argv = argv + 1;
282
+ sw->out.argc = argc - 1;
283
+ sw->out.argv = argv + 1;
285
284
  sw->out.indent = sw->opts.indent;
286
285
 
287
- return Data_Wrap_Struct(oj_string_writer_class, 0, str_writer_free, sw);
286
+ return TypedData_Wrap_Struct(oj_string_writer_class, &oj_string_writer_type, sw);
288
287
  }
289
288
 
290
289
  /* Document-method: push_key
@@ -295,11 +294,10 @@ str_writer_new(int argc, VALUE *argv, VALUE self) {
295
294
  * the next push then that new key will be ignored.
296
295
  * - *key* [_String_] the key pending for the next push
297
296
  */
298
- static VALUE
299
- str_writer_push_key(VALUE self, VALUE key) {
300
- StrWriter sw = (StrWriter)DATA_PTR(self);
297
+ static VALUE str_writer_push_key(VALUE self, VALUE key) {
298
+ StrWriter sw;
299
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
301
300
 
302
- rb_check_type(key, T_STRING);
303
301
  oj_str_writer_push_key(sw, StringValuePtr(key));
304
302
 
305
303
  return Qnil;
@@ -312,29 +310,24 @@ str_writer_push_key(VALUE self, VALUE key) {
312
310
  * until a pop() is called.
313
311
  * - *key* [_String_] the key if adding to an object in the JSON document
314
312
  */
315
- static VALUE
316
- str_writer_push_object(int argc, VALUE *argv, VALUE self) {
317
- StrWriter sw = (StrWriter)DATA_PTR(self);
313
+ static VALUE str_writer_push_object(int argc, VALUE *argv, VALUE self) {
314
+ StrWriter sw;
315
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
318
316
 
319
317
  switch (argc) {
320
- case 0:
321
- oj_str_writer_push_object(sw, 0);
322
- break;
318
+ case 0: oj_str_writer_push_object(sw, 0); break;
323
319
  case 1:
324
- if (Qnil == argv[0]) {
325
- oj_str_writer_push_object(sw, 0);
326
- } else {
327
- rb_check_type(argv[0], T_STRING);
328
- oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
329
- }
330
- break;
331
- default:
332
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
333
- break;
320
+ if (Qnil == argv[0]) {
321
+ oj_str_writer_push_object(sw, 0);
322
+ } else {
323
+ oj_str_writer_push_object(sw, StringValuePtr(argv[0]));
324
+ }
325
+ break;
326
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
334
327
  }
335
328
  if (rb_block_given_p()) {
336
- rb_yield(Qnil);
337
- oj_str_writer_pop(sw);
329
+ rb_yield(Qnil);
330
+ oj_str_writer_pop(sw);
338
331
  }
339
332
  return Qnil;
340
333
  }
@@ -346,29 +339,24 @@ str_writer_push_object(int argc, VALUE *argv, VALUE self) {
346
339
  * until a pop() is called.
347
340
  * - *key* [_String_] the key if adding to an object in the JSON document
348
341
  */
349
- static VALUE
350
- str_writer_push_array(int argc, VALUE *argv, VALUE self) {
351
- StrWriter sw = (StrWriter)DATA_PTR(self);
342
+ static VALUE str_writer_push_array(int argc, VALUE *argv, VALUE self) {
343
+ StrWriter sw;
344
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
352
345
 
353
346
  switch (argc) {
354
- case 0:
355
- oj_str_writer_push_array(sw, 0);
356
- break;
347
+ case 0: oj_str_writer_push_array(sw, 0); break;
357
348
  case 1:
358
- if (Qnil == argv[0]) {
359
- oj_str_writer_push_array(sw, 0);
360
- } else {
361
- rb_check_type(argv[0], T_STRING);
362
- oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
363
- }
364
- break;
365
- default:
366
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'.");
367
- break;
349
+ if (Qnil == argv[0]) {
350
+ oj_str_writer_push_array(sw, 0);
351
+ } else {
352
+ oj_str_writer_push_array(sw, StringValuePtr(argv[0]));
353
+ }
354
+ break;
355
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_object'."); break;
368
356
  }
369
357
  if (rb_block_given_p()) {
370
- rb_yield(Qnil);
371
- oj_str_writer_pop(sw);
358
+ rb_yield(Qnil);
359
+ oj_str_writer_pop(sw);
372
360
  }
373
361
  return Qnil;
374
362
  }
@@ -380,23 +368,20 @@ str_writer_push_array(int argc, VALUE *argv, VALUE self) {
380
368
  * - *value* [_Object_] value to add to the JSON document
381
369
  * - *key* [_String_] the key if adding to an object in the JSON document
382
370
  */
383
- static VALUE
384
- str_writer_push_value(int argc, VALUE *argv, VALUE self) {
371
+ static VALUE str_writer_push_value(int argc, VALUE *argv, VALUE self) {
372
+ StrWriter sw;
373
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
374
+
385
375
  switch (argc) {
386
- case 1:
387
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
388
- break;
376
+ case 1: oj_str_writer_push_value(sw, *argv, 0); break;
389
377
  case 2:
390
- if (Qnil == argv[1]) {
391
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, 0);
392
- } else {
393
- rb_check_type(argv[1], T_STRING);
394
- oj_str_writer_push_value((StrWriter)DATA_PTR(self), *argv, StringValuePtr(argv[1]));
395
- }
396
- break;
397
- default:
398
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'.");
399
- break;
378
+ if (Qnil == argv[1]) {
379
+ oj_str_writer_push_value(sw, *argv, 0);
380
+ } else {
381
+ oj_str_writer_push_value(sw, *argv, StringValuePtr(argv[1]));
382
+ }
383
+ break;
384
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_value'."); break;
400
385
  }
401
386
  return Qnil;
402
387
  }
@@ -410,24 +395,20 @@ str_writer_push_value(int argc, VALUE *argv, VALUE self) {
410
395
  * - *value* [_Object_] value to add to the JSON document
411
396
  * - *key* [_String_] the key if adding to an object in the JSON document
412
397
  */
413
- static VALUE
414
- str_writer_push_json(int argc, VALUE *argv, VALUE self) {
415
- rb_check_type(argv[0], T_STRING);
398
+ static VALUE str_writer_push_json(int argc, VALUE *argv, VALUE self) {
399
+ StrWriter sw;
400
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
401
+
416
402
  switch (argc) {
417
- case 1:
418
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
419
- break;
403
+ case 1: oj_str_writer_push_json(sw, StringValuePtr(*argv), 0); break;
420
404
  case 2:
421
- if (Qnil == argv[1]) {
422
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), 0);
423
- } else {
424
- rb_check_type(argv[1], T_STRING);
425
- oj_str_writer_push_json((StrWriter)DATA_PTR(self), StringValuePtr(*argv), StringValuePtr(argv[1]));
426
- }
427
- break;
428
- default:
429
- rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'.");
430
- break;
405
+ if (Qnil == argv[1]) {
406
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), 0);
407
+ } else {
408
+ oj_str_writer_push_json(sw, StringValuePtr(*argv), StringValuePtr(argv[1]));
409
+ }
410
+ break;
411
+ default: rb_raise(rb_eArgError, "Wrong number of argument to 'push_json'."); break;
431
412
  }
432
413
  return Qnil;
433
414
  }
@@ -437,9 +418,11 @@ str_writer_push_json(int argc, VALUE *argv, VALUE self) {
437
418
  * Pops up a level in the JSON document closing the array or object that is
438
419
  * currently open.
439
420
  */
440
- static VALUE
441
- str_writer_pop(VALUE self) {
442
- oj_str_writer_pop((StrWriter)DATA_PTR(self));
421
+ static VALUE str_writer_pop(VALUE self) {
422
+ StrWriter sw;
423
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
424
+
425
+ oj_str_writer_pop(sw);
443
426
  return Qnil;
444
427
  }
445
428
 
@@ -449,9 +432,11 @@ str_writer_pop(VALUE self) {
449
432
  * Pops all level in the JSON document closing all the array or object that is
450
433
  * currently open.
451
434
  */
452
- static VALUE
453
- str_writer_pop_all(VALUE self) {
454
- oj_str_writer_pop_all((StrWriter)DATA_PTR(self));
435
+ static VALUE str_writer_pop_all(VALUE self) {
436
+ StrWriter sw;
437
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
438
+
439
+ oj_str_writer_pop_all(sw);
455
440
 
456
441
  return Qnil;
457
442
  }
@@ -461,15 +446,15 @@ str_writer_pop_all(VALUE self) {
461
446
  *
462
447
  * Reset the writer back to the empty state.
463
448
  */
464
- static VALUE
465
- str_writer_reset(VALUE self) {
466
- StrWriter sw = (StrWriter)DATA_PTR(self);
449
+ static VALUE str_writer_reset(VALUE self) {
450
+ StrWriter sw;
451
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
467
452
 
468
- sw->depth = 0;
469
- *sw->types = '\0';
453
+ sw->depth = 0;
454
+ *sw->types = '\0';
470
455
  sw->keyWritten = 0;
471
- sw->out.cur = sw->out.buf;
472
- *sw->out.cur = '\0';
456
+ sw->out.cur = sw->out.buf;
457
+ *sw->out.cur = '\0';
473
458
 
474
459
  return Qnil;
475
460
  }
@@ -481,28 +466,25 @@ str_writer_reset(VALUE self) {
481
466
  *
482
467
  * *return* [_String_]
483
468
  */
484
- static VALUE
485
- str_writer_to_s(VALUE self) {
486
- StrWriter sw = (StrWriter)DATA_PTR(self);
487
- VALUE rstr = rb_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
488
-
489
- return oj_encode(rstr);
469
+ static VALUE str_writer_to_s(VALUE self) {
470
+ StrWriter sw;
471
+ TypedData_Get_Struct(self, struct _strWriter, &oj_string_writer_type, sw);
472
+ return rb_utf8_str_new(sw->out.buf, sw->out.cur - sw->out.buf);
490
473
  }
491
474
 
492
475
  /* Document-method: as_json
493
- * call-seq: as_json()
476
+ * call-seq: as_json(*)
494
477
  *
495
478
  * Returns the contents of the writer as a JSON element. If called from inside
496
479
  * an array or hash by Oj the raw buffer will be used othersize a more
497
480
  * inefficient parse of the contents and a return of the result is
498
- * completed. The parse uses the trict mode.
481
+ * completed. The parse uses the strict mode. Optional arguments are ignored.
499
482
  *
500
483
  * *return* [_Hash_|_Array_|_String_|_Integer_|_Float_|_True_|_False_|_nil|)
501
484
  */
502
- static VALUE
503
- str_writer_as_json(VALUE self) {
485
+ static VALUE str_writer_as_json(int argc, VALUE *argv, VALUE self) {
504
486
  if (string_writer_optimized) {
505
- return self;
487
+ return self;
506
488
  }
507
489
  return rb_hash_new();
508
490
  }
@@ -513,12 +495,13 @@ str_writer_as_json(VALUE self) {
513
495
  * by pushing values into the document. Pushing an array or an object will
514
496
  * create that element in the JSON document and subsequent pushes will add the
515
497
  * elements to that array or object until a pop() is called. When complete
516
- * calling to_s() will return the JSON document. Note tha calling to_s() before
498
+ * calling to_s() will return the JSON document. Note that calling to_s() before
517
499
  * construction is complete will return the document in it's current state.
518
500
  */
519
- void
520
- oj_string_writer_init() {
501
+ void oj_string_writer_init(void) {
521
502
  oj_string_writer_class = rb_define_class_under(Oj, "StringWriter", rb_cObject);
503
+ rb_gc_register_address(&oj_string_writer_class);
504
+ rb_undef_alloc_func(oj_string_writer_class);
522
505
  rb_define_module_function(oj_string_writer_class, "new", str_writer_new, -1);
523
506
  rb_define_method(oj_string_writer_class, "push_key", str_writer_push_key, 1);
524
507
  rb_define_method(oj_string_writer_class, "push_object", str_writer_push_object, -1);
@@ -530,5 +513,5 @@ oj_string_writer_init() {
530
513
  rb_define_method(oj_string_writer_class, "reset", str_writer_reset, 0);
531
514
  rb_define_method(oj_string_writer_class, "to_s", str_writer_to_s, 0);
532
515
  rb_define_method(oj_string_writer_class, "raw_json", str_writer_to_s, 0);
533
- rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, 0);
516
+ rb_define_method(oj_string_writer_class, "as_json", str_writer_as_json, -1);
534
517
  }