oj 3.11.5 → 3.16.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/usual.c ADDED
@@ -0,0 +1,1218 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "usual.h"
4
+
5
+ #include "cache.h"
6
+ #include "mem.h"
7
+ #include "oj.h"
8
+ #include "parser.h"
9
+
10
+ // The Usual delegate builds Ruby objects during parsing. It makes use of
11
+ // three stacks. The first is the value stack. This is where parsed values are
12
+ // placed. With the value stack the bulk creation and setting can be used
13
+ // which is significantly faster than setting Array (15x) or Hash (3x)
14
+ // elements one at a time.
15
+ //
16
+ // The second stack is the collection stack. Each element on the collection
17
+ // stack marks the start of a Hash, Array, or Object.
18
+ //
19
+ // The third stack is the key stack which is used for Hash and Object
20
+ // members. The key stack elements store the keys that could be used for
21
+ // either a Hash or Object. Since the decision on whether the parent is a Hash
22
+ // or Object can not be made until the end of the JSON object the keys remain
23
+ // as strings until just before setting the Hash or Object members.
24
+ //
25
+ // The approach taken with the usual delegate is to configure the delegate for
26
+ // the parser up front so that the various options are not checked during
27
+ // parsing and thus avoiding conditionals as much as reasonably possible in
28
+ // the more time sensitive parsing. Configuration is simply setting the
29
+ // function pointers to point to the function to be used for the selected
30
+ // option.
31
+
32
+ #define DEBUG 0
33
+
34
+ static ID to_f_id = 0;
35
+ static ID ltlt_id = 0;
36
+ static ID hset_id = 0;
37
+
38
+ static char *str_dup(const char *s, size_t len) {
39
+ char *d = OJ_R_ALLOC_N(char, len + 1);
40
+
41
+ memcpy(d, s, len);
42
+ d[len] = '\0';
43
+
44
+ return d;
45
+ }
46
+
47
+ static VALUE form_str(const char *str, size_t len) {
48
+ return rb_str_freeze(rb_utf8_str_new(str, len));
49
+ }
50
+
51
+ static VALUE form_sym(const char *str, size_t len) {
52
+ return rb_str_intern(rb_utf8_str_new(str, len));
53
+ }
54
+
55
+ static VALUE form_attr(const char *str, size_t len) {
56
+ char buf[256];
57
+
58
+ if (sizeof(buf) - 2 <= len) {
59
+ char *b = OJ_R_ALLOC_N(char, len + 2);
60
+ ID id;
61
+
62
+ *b = '@';
63
+ memcpy(b + 1, str, len);
64
+ b[len + 1] = '\0';
65
+
66
+ id = rb_intern3(buf, len + 1, oj_utf8_encoding);
67
+ OJ_R_FREE(b);
68
+ return id;
69
+ }
70
+ *buf = '@';
71
+ memcpy(buf + 1, str, len);
72
+ buf[len + 1] = '\0';
73
+
74
+ return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
75
+ }
76
+
77
+ static VALUE resolve_classname(VALUE mod, const char *classname, bool auto_define) {
78
+ VALUE clas;
79
+ ID ci = rb_intern(classname);
80
+
81
+ if (rb_const_defined_at(mod, ci)) {
82
+ clas = rb_const_get_at(mod, ci);
83
+ } else if (auto_define) {
84
+ clas = rb_define_class_under(mod, classname, oj_bag_class);
85
+ } else {
86
+ clas = Qundef;
87
+ }
88
+ return clas;
89
+ }
90
+
91
+ static VALUE resolve_classpath(const char *name, size_t len, bool auto_define) {
92
+ char class_name[1024];
93
+ VALUE clas;
94
+ char *end = class_name + sizeof(class_name) - 1;
95
+ char *s;
96
+ const char *n = name;
97
+
98
+ clas = rb_cObject;
99
+ for (s = class_name; 0 < len; n++, len--) {
100
+ if (':' == *n) {
101
+ *s = '\0';
102
+ n++;
103
+ len--;
104
+ if (':' != *n) {
105
+ return Qundef;
106
+ }
107
+ if (Qundef == (clas = resolve_classname(clas, class_name, auto_define))) {
108
+ return Qundef;
109
+ }
110
+ s = class_name;
111
+ } else if (end <= s) {
112
+ return Qundef;
113
+ } else {
114
+ *s++ = *n;
115
+ }
116
+ }
117
+ *s = '\0';
118
+ return resolve_classname(clas, class_name, auto_define);
119
+ }
120
+
121
+ static VALUE form_class(const char *str, size_t len) {
122
+ return resolve_classpath(str, len, false);
123
+ }
124
+
125
+ static VALUE form_class_auto(const char *str, size_t len) {
126
+ return resolve_classpath(str, len, true);
127
+ }
128
+
129
+ static void assure_cstack(Usual d) {
130
+ if (d->cend <= d->ctail + 1) {
131
+ size_t cap = d->cend - d->chead;
132
+ long pos = d->ctail - d->chead;
133
+
134
+ cap *= 2;
135
+ OJ_R_REALLOC_N(d->chead, struct _col, cap);
136
+ d->ctail = d->chead + pos;
137
+ d->cend = d->chead + cap;
138
+ }
139
+ }
140
+
141
+ static void push(ojParser p, VALUE v) {
142
+ Usual d = (Usual)p->ctx;
143
+
144
+ if (d->vend <= d->vtail) {
145
+ size_t cap = d->vend - d->vhead;
146
+ long pos = d->vtail - d->vhead;
147
+
148
+ cap *= 2;
149
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
150
+ d->vtail = d->vhead + pos;
151
+ d->vend = d->vhead + cap;
152
+ }
153
+ *d->vtail = v;
154
+ d->vtail++;
155
+ }
156
+
157
+ static VALUE cache_key(ojParser p, Key kp) {
158
+ Usual d = (Usual)p->ctx;
159
+
160
+ if ((size_t)kp->len < sizeof(kp->buf)) {
161
+ return cache_intern(d->key_cache, kp->buf, kp->len);
162
+ }
163
+ return cache_intern(d->key_cache, kp->key, kp->len);
164
+ }
165
+
166
+ static VALUE str_key(ojParser p, Key kp) {
167
+ if ((size_t)kp->len < sizeof(kp->buf)) {
168
+ return rb_str_freeze(rb_utf8_str_new(kp->buf, kp->len));
169
+ }
170
+ return rb_str_freeze(rb_utf8_str_new(kp->key, kp->len));
171
+ }
172
+
173
+ static VALUE sym_key(ojParser p, Key kp) {
174
+ if ((size_t)kp->len < sizeof(kp->buf)) {
175
+ return rb_str_freeze(rb_str_intern(rb_utf8_str_new(kp->buf, kp->len)));
176
+ }
177
+ return rb_str_freeze(rb_str_intern(rb_utf8_str_new(kp->key, kp->len)));
178
+ }
179
+
180
+ static ID get_attr_id(ojParser p, Key kp) {
181
+ Usual d = (Usual)p->ctx;
182
+
183
+ if ((size_t)kp->len < sizeof(kp->buf)) {
184
+ return (ID)cache_intern(d->attr_cache, kp->buf, kp->len);
185
+ }
186
+ return (ID)cache_intern(d->attr_cache, kp->key, kp->len);
187
+ }
188
+
189
+ static void push_key(ojParser p) {
190
+ Usual d = (Usual)p->ctx;
191
+ size_t klen = buf_len(&p->key);
192
+ const char *key = buf_str(&p->key);
193
+
194
+ if (d->kend <= d->ktail) {
195
+ size_t cap = d->kend - d->khead;
196
+ long pos = d->ktail - d->khead;
197
+
198
+ cap *= 2;
199
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
200
+ d->ktail = d->khead + pos;
201
+ d->kend = d->khead + cap;
202
+ }
203
+ d->ktail->len = klen;
204
+ if (klen < sizeof(d->ktail->buf)) {
205
+ memcpy(d->ktail->buf, key, klen);
206
+ d->ktail->buf[klen] = '\0';
207
+ } else {
208
+ d->ktail->key = str_dup(key, klen);
209
+ }
210
+ d->ktail++;
211
+ }
212
+
213
+ static void push2(ojParser p, VALUE v) {
214
+ Usual d = (Usual)p->ctx;
215
+
216
+ if (d->vend <= d->vtail + 1) {
217
+ size_t cap = d->vend - d->vhead;
218
+ long pos = d->vtail - d->vhead;
219
+
220
+ cap *= 2;
221
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
222
+ d->vtail = d->vhead + pos;
223
+ d->vend = d->vhead + cap;
224
+ }
225
+ *d->vtail = Qundef; // key place holder
226
+ d->vtail++;
227
+ *d->vtail = v;
228
+ d->vtail++;
229
+ }
230
+
231
+ static void open_object(ojParser p) {
232
+ Usual d = (Usual)p->ctx;
233
+
234
+ assure_cstack(d);
235
+ d->ctail->vi = d->vtail - d->vhead;
236
+ d->ctail->ki = d->ktail - d->khead;
237
+ d->ctail++;
238
+ push(p, Qundef);
239
+ }
240
+
241
+ static void open_object_key(ojParser p) {
242
+ Usual d = (Usual)p->ctx;
243
+
244
+ push_key(p);
245
+ assure_cstack(d);
246
+ d->ctail->vi = d->vtail - d->vhead + 1;
247
+ d->ctail->ki = d->ktail - d->khead;
248
+ d->ctail++;
249
+ push2(p, Qundef);
250
+ }
251
+
252
+ static void open_array(ojParser p) {
253
+ Usual d = (Usual)p->ctx;
254
+
255
+ assure_cstack(d);
256
+ d->ctail->vi = d->vtail - d->vhead;
257
+ d->ctail->ki = -1;
258
+ d->ctail++;
259
+ push(p, Qundef);
260
+ }
261
+
262
+ static void open_array_key(ojParser p) {
263
+ Usual d = (Usual)p->ctx;
264
+
265
+ push_key(p);
266
+ assure_cstack(d);
267
+ d->ctail->vi = d->vtail - d->vhead + 1;
268
+ d->ctail->ki = -1;
269
+ d->ctail++;
270
+ push2(p, Qundef);
271
+ }
272
+
273
+ static void close_object(ojParser p) {
274
+ VALUE *vp;
275
+ Usual d = (Usual)p->ctx;
276
+
277
+ d->ctail--;
278
+
279
+ Col c = d->ctail;
280
+ Key kp = d->khead + c->ki;
281
+ VALUE *head = d->vhead + c->vi + 1;
282
+ volatile VALUE obj = rb_hash_new();
283
+
284
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
285
+ *vp = d->get_key(p, kp);
286
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
287
+ OJ_R_FREE(kp->key);
288
+ }
289
+ }
290
+ rb_hash_bulk_insert(d->vtail - head, head, obj);
291
+ d->ktail = d->khead + c->ki;
292
+
293
+ d->vtail = head;
294
+ head--;
295
+ *head = obj;
296
+ if (1 == d->vtail - d->vhead && rb_block_given_p()) {
297
+ d->vtail = d->vhead;
298
+ rb_yield(obj);
299
+ }
300
+ }
301
+
302
+ static void close_object_class(ojParser p) {
303
+ VALUE *vp;
304
+ Usual d = (Usual)p->ctx;
305
+
306
+ d->ctail--;
307
+
308
+ Col c = d->ctail;
309
+ Key kp = d->khead + c->ki;
310
+ VALUE *head = d->vhead + c->vi + 1;
311
+ volatile VALUE obj = rb_class_new_instance(0, NULL, d->hash_class);
312
+
313
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
314
+ rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
315
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
316
+ OJ_R_FREE(kp->key);
317
+ }
318
+ }
319
+ d->ktail = d->khead + c->ki;
320
+ d->vtail = head;
321
+ head--;
322
+ *head = obj;
323
+ }
324
+
325
+ static void close_object_create(ojParser p) {
326
+ VALUE *vp;
327
+ Usual d = (Usual)p->ctx;
328
+
329
+ d->ctail--;
330
+
331
+ Col c = d->ctail;
332
+ Key kp = d->khead + c->ki;
333
+ VALUE *head = d->vhead + c->vi;
334
+ volatile VALUE obj;
335
+
336
+ if (Qundef == *head) {
337
+ head++;
338
+ if (Qnil == d->hash_class) {
339
+ obj = rb_hash_new();
340
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
341
+ *vp = d->get_key(p, kp);
342
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
343
+ OJ_R_FREE(kp->key);
344
+ }
345
+ }
346
+ rb_hash_bulk_insert(d->vtail - head, head, obj);
347
+ } else {
348
+ obj = rb_class_new_instance(0, NULL, d->hash_class);
349
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
350
+ rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
351
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
352
+ OJ_R_FREE(kp->key);
353
+ }
354
+ }
355
+ }
356
+ } else {
357
+ VALUE clas = *head;
358
+
359
+ head++;
360
+ if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
361
+ volatile VALUE arg = rb_hash_new();
362
+
363
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
364
+ *vp = d->get_key(p, kp);
365
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
366
+ OJ_R_FREE(kp->key);
367
+ }
368
+ }
369
+ rb_hash_bulk_insert(d->vtail - head, head, arg);
370
+ obj = rb_funcall(clas, oj_json_create_id, 1, arg);
371
+ } else {
372
+ obj = rb_class_new_instance(0, NULL, clas);
373
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
374
+ rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
375
+ if (sizeof(kp->buf) <= (size_t)kp->len) {
376
+ OJ_R_FREE(kp->key);
377
+ }
378
+ }
379
+ }
380
+ }
381
+ d->ktail = d->khead + c->ki;
382
+ d->vtail = head;
383
+ head--;
384
+ *head = obj;
385
+ }
386
+
387
+ static void close_array(ojParser p) {
388
+ Usual d = (Usual)p->ctx;
389
+
390
+ d->ctail--;
391
+ VALUE *head = d->vhead + d->ctail->vi + 1;
392
+ volatile VALUE a = rb_ary_new_from_values(d->vtail - head, head);
393
+
394
+ d->vtail = head;
395
+ head--;
396
+ *head = a;
397
+ }
398
+
399
+ static void close_array_class(ojParser p) {
400
+ VALUE *vp;
401
+ Usual d = (Usual)p->ctx;
402
+
403
+ d->ctail--;
404
+ VALUE *head = d->vhead + d->ctail->vi + 1;
405
+ volatile VALUE a = rb_class_new_instance(0, NULL, d->array_class);
406
+
407
+ for (vp = head; vp < d->vtail; vp++) {
408
+ rb_funcall(a, ltlt_id, 1, *vp);
409
+ }
410
+ d->vtail = head;
411
+ head--;
412
+ *head = a;
413
+ }
414
+
415
+ static void noop(ojParser p) {
416
+ }
417
+
418
+ static void add_null(ojParser p) {
419
+ push(p, Qnil);
420
+ }
421
+
422
+ static void add_null_key(ojParser p) {
423
+ push_key(p);
424
+ push2(p, Qnil);
425
+ }
426
+
427
+ static void add_true(ojParser p) {
428
+ push(p, Qtrue);
429
+ }
430
+
431
+ static void add_true_key(ojParser p) {
432
+ push_key(p);
433
+ push2(p, Qtrue);
434
+ }
435
+
436
+ static void add_false(ojParser p) {
437
+ push(p, Qfalse);
438
+ }
439
+
440
+ static void add_false_key(ojParser p) {
441
+ push_key(p);
442
+ push2(p, Qfalse);
443
+ }
444
+
445
+ static void add_int(ojParser p) {
446
+ push(p, LONG2NUM(p->num.fixnum));
447
+ }
448
+
449
+ static void add_int_key(ojParser p) {
450
+ push_key(p);
451
+ push2(p, LONG2NUM(p->num.fixnum));
452
+ }
453
+
454
+ static void add_float(ojParser p) {
455
+ push(p, rb_float_new(p->num.dub));
456
+ }
457
+
458
+ static void add_float_key(ojParser p) {
459
+ push_key(p);
460
+ push2(p, rb_float_new(p->num.dub));
461
+ }
462
+
463
+ static void add_float_as_big(ojParser p) {
464
+ char buf[64];
465
+
466
+ // snprintf fails on ubuntu and macOS for long double
467
+ // snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
468
+ sprintf(buf, "%Lg", p->num.dub);
469
+ push(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
470
+ }
471
+
472
+ static void add_float_as_big_key(ojParser p) {
473
+ char buf[64];
474
+
475
+ // snprintf fails on ubuntu and macOS for long double
476
+ // snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
477
+ sprintf(buf, "%Lg", p->num.dub);
478
+ push_key(p);
479
+ push2(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
480
+ }
481
+
482
+ static void add_big(ojParser p) {
483
+ push(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))));
484
+ }
485
+
486
+ static void add_big_key(ojParser p) {
487
+ push_key(p);
488
+ push2(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))));
489
+ }
490
+
491
+ static void add_big_as_float(ojParser p) {
492
+ volatile VALUE big = rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf)));
493
+
494
+ push(p, rb_funcall(big, to_f_id, 0));
495
+ }
496
+
497
+ static void add_big_as_float_key(ojParser p) {
498
+ volatile VALUE big = rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf)));
499
+
500
+ push_key(p);
501
+ push2(p, rb_funcall(big, to_f_id, 0));
502
+ }
503
+
504
+ static void add_big_as_ruby(ojParser p) {
505
+ push(p, rb_funcall(rb_str_new(buf_str(&p->buf), buf_len(&p->buf)), to_f_id, 0));
506
+ }
507
+
508
+ static void add_big_as_ruby_key(ojParser p) {
509
+ push_key(p);
510
+ push2(p, rb_funcall(rb_str_new(buf_str(&p->buf), buf_len(&p->buf)), to_f_id, 0));
511
+ }
512
+
513
+ static void add_str(ojParser p) {
514
+ Usual d = (Usual)p->ctx;
515
+ volatile VALUE rstr;
516
+ const char *str = buf_str(&p->buf);
517
+ size_t len = buf_len(&p->buf);
518
+
519
+ if (len < d->cache_str) {
520
+ rstr = cache_intern(d->str_cache, str, len);
521
+ } else {
522
+ rstr = rb_utf8_str_new(str, len);
523
+ }
524
+ push(p, rstr);
525
+ }
526
+
527
+ static void add_str_key(ojParser p) {
528
+ Usual d = (Usual)p->ctx;
529
+ volatile VALUE rstr;
530
+ const char *str = buf_str(&p->buf);
531
+ size_t len = buf_len(&p->buf);
532
+
533
+ if (len < d->cache_str) {
534
+ rstr = cache_intern(d->str_cache, str, len);
535
+ } else {
536
+ rstr = rb_utf8_str_new(str, len);
537
+ }
538
+ push_key(p);
539
+ push2(p, rstr);
540
+ }
541
+
542
+ static void add_str_key_create(ojParser p) {
543
+ Usual d = (Usual)p->ctx;
544
+ volatile VALUE rstr;
545
+ const char *str = buf_str(&p->buf);
546
+ size_t len = buf_len(&p->buf);
547
+ const char *key = buf_str(&p->key);
548
+ size_t klen = buf_len(&p->key);
549
+
550
+ if (klen == (size_t)d->create_id_len && 0 == strncmp(d->create_id, key, klen)) {
551
+ Col c = d->ctail - 1;
552
+ VALUE clas;
553
+
554
+ if (NULL != d->class_cache) {
555
+ clas = cache_intern(d->class_cache, str, len);
556
+ } else {
557
+ clas = resolve_classpath(str, len, MISS_AUTO == d->miss_class);
558
+ }
559
+ if (Qundef != clas) {
560
+ *(d->vhead + c->vi) = clas;
561
+ return;
562
+ }
563
+ if (MISS_RAISE == d->miss_class) {
564
+ rb_raise(rb_eLoadError, "%s is not define", str);
565
+ }
566
+ }
567
+ if (len < d->cache_str) {
568
+ rstr = cache_intern(d->str_cache, str, len);
569
+ } else {
570
+ rstr = rb_utf8_str_new(str, len);
571
+ }
572
+ push_key(p);
573
+ push2(p, rstr);
574
+ }
575
+
576
+ static VALUE result(ojParser p) {
577
+ Usual d = (Usual)p->ctx;
578
+
579
+ if (d->vhead < d->vtail) {
580
+ long cnt = d->vtail - d->vhead;
581
+ volatile VALUE ary;
582
+ volatile VALUE *vp;
583
+
584
+ if (1 == cnt) {
585
+ return *d->vhead;
586
+ }
587
+ ary = rb_ary_new();
588
+ for (vp = d->vhead; vp < d->vtail; vp++) {
589
+ rb_ary_push(ary, *vp);
590
+ }
591
+ return ary;
592
+ }
593
+ if (d->raise_on_empty) {
594
+ rb_raise(oj_parse_error_class, "empty string");
595
+ }
596
+ return Qnil;
597
+ }
598
+
599
+ static void start(ojParser p) {
600
+ Usual d = (Usual)p->ctx;
601
+
602
+ d->vtail = d->vhead;
603
+ d->ctail = d->chead;
604
+ d->ktail = d->khead;
605
+ }
606
+
607
+ static void dfree(ojParser p) {
608
+ Usual d = (Usual)p->ctx;
609
+
610
+ cache_free(d->str_cache);
611
+ cache_free(d->attr_cache);
612
+ if (NULL != d->sym_cache) {
613
+ cache_free(d->sym_cache);
614
+ }
615
+ if (NULL != d->class_cache) {
616
+ cache_free(d->class_cache);
617
+ }
618
+ OJ_R_FREE(d->vhead);
619
+ OJ_R_FREE(d->chead);
620
+ OJ_R_FREE(d->khead);
621
+ OJ_R_FREE(d->create_id);
622
+ OJ_R_FREE(p->ctx);
623
+ p->ctx = NULL;
624
+ }
625
+
626
+ static void mark(ojParser p) {
627
+ if (NULL == p || NULL == p->ctx) {
628
+ return;
629
+ }
630
+ Usual d = (Usual)p->ctx;
631
+ VALUE *vp;
632
+
633
+ if (NULL == d) {
634
+ return;
635
+ }
636
+ cache_mark(d->str_cache);
637
+ if (NULL != d->sym_cache) {
638
+ cache_mark(d->sym_cache);
639
+ }
640
+ if (NULL != d->class_cache) {
641
+ cache_mark(d->class_cache);
642
+ }
643
+ for (vp = d->vhead; vp < d->vtail; vp++) {
644
+ if (Qundef != *vp) {
645
+ rb_gc_mark(*vp);
646
+ }
647
+ }
648
+ }
649
+
650
+ ///// options /////////////////////////////////////////////////////////////////
651
+
652
+ // Each option is handled by a separate function and then added to an assoc
653
+ // list (struct opt}. The list is then iterated over until there is a name
654
+ // match. This is done primarily to keep each option separate and easier to
655
+ // understand instead of placing all in one large function.
656
+
657
+ struct opt {
658
+ const char *name;
659
+ VALUE (*func)(ojParser p, VALUE value);
660
+ };
661
+
662
+ static VALUE opt_array_class(ojParser p, VALUE value) {
663
+ Usual d = (Usual)p->ctx;
664
+
665
+ return d->array_class;
666
+ }
667
+
668
+ static VALUE opt_array_class_set(ojParser p, VALUE value) {
669
+ Usual d = (Usual)p->ctx;
670
+
671
+ if (Qnil == value) {
672
+ p->funcs[TOP_FUN].close_array = close_array;
673
+ p->funcs[ARRAY_FUN].close_array = close_array;
674
+ p->funcs[OBJECT_FUN].close_array = close_array;
675
+ } else {
676
+ rb_check_type(value, T_CLASS);
677
+ if (!rb_method_boundp(value, ltlt_id, 1)) {
678
+ rb_raise(rb_eArgError, "An array class must implement the << method.");
679
+ }
680
+ p->funcs[TOP_FUN].close_array = close_array_class;
681
+ p->funcs[ARRAY_FUN].close_array = close_array_class;
682
+ p->funcs[OBJECT_FUN].close_array = close_array_class;
683
+ }
684
+ d->array_class = value;
685
+
686
+ return d->array_class;
687
+ }
688
+
689
+ static VALUE opt_cache_keys(ojParser p, VALUE value) {
690
+ Usual d = (Usual)p->ctx;
691
+
692
+ return d->cache_keys ? Qtrue : Qfalse;
693
+ }
694
+
695
+ static VALUE opt_cache_keys_set(ojParser p, VALUE value) {
696
+ Usual d = (Usual)p->ctx;
697
+
698
+ if (Qtrue == value) {
699
+ d->cache_keys = true;
700
+ d->get_key = cache_key;
701
+ if (NULL == d->sym_cache) {
702
+ d->key_cache = d->str_cache;
703
+ } else {
704
+ d->key_cache = d->sym_cache;
705
+ }
706
+ } else {
707
+ d->cache_keys = false;
708
+ if (NULL == d->sym_cache) {
709
+ d->get_key = str_key;
710
+ } else {
711
+ d->get_key = sym_key;
712
+ }
713
+ }
714
+ return d->cache_keys ? Qtrue : Qfalse;
715
+ }
716
+
717
+ static VALUE opt_cache_strings(ojParser p, VALUE value) {
718
+ Usual d = (Usual)p->ctx;
719
+
720
+ return INT2NUM((int)d->cache_str);
721
+ }
722
+
723
+ static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
724
+ Usual d = (Usual)p->ctx;
725
+ int limit = NUM2INT(value);
726
+
727
+ if (CACHE_MAX_KEY < limit) {
728
+ limit = CACHE_MAX_KEY;
729
+ } else if (limit < 0) {
730
+ limit = 0;
731
+ }
732
+ d->cache_str = limit;
733
+
734
+ return INT2NUM((int)d->cache_str);
735
+ }
736
+
737
+ static VALUE opt_cache_expunge(ojParser p, VALUE value) {
738
+ Usual d = (Usual)p->ctx;
739
+
740
+ return INT2NUM((int)d->cache_xrate);
741
+ }
742
+
743
+ static VALUE opt_cache_expunge_set(ojParser p, VALUE value) {
744
+ Usual d = (Usual)p->ctx;
745
+ int rate = NUM2INT(value);
746
+
747
+ if (rate < 0) {
748
+ rate = 0;
749
+ } else if (3 < rate) {
750
+ rate = 3;
751
+ }
752
+ d->cache_xrate = (uint8_t)rate;
753
+ cache_set_expunge_rate(d->str_cache, rate);
754
+ cache_set_expunge_rate(d->attr_cache, rate);
755
+ if (NULL != d->sym_cache) {
756
+ cache_set_expunge_rate(d->sym_cache, rate);
757
+ }
758
+ return INT2NUM((int)rate);
759
+ }
760
+
761
+ static VALUE opt_capacity(ojParser p, VALUE value) {
762
+ Usual d = (Usual)p->ctx;
763
+
764
+ return ULONG2NUM(d->vend - d->vhead);
765
+ }
766
+
767
+ static VALUE opt_capacity_set(ojParser p, VALUE value) {
768
+ Usual d = (Usual)p->ctx;
769
+ long cap = NUM2LONG(value);
770
+
771
+ if (d->vend - d->vhead < cap) {
772
+ long pos = d->vtail - d->vhead;
773
+
774
+ OJ_R_REALLOC_N(d->vhead, VALUE, cap);
775
+ d->vtail = d->vhead + pos;
776
+ d->vend = d->vhead + cap;
777
+ }
778
+ if (d->kend - d->khead < cap) {
779
+ long pos = d->ktail - d->khead;
780
+
781
+ OJ_R_REALLOC_N(d->khead, union _key, cap);
782
+ d->ktail = d->khead + pos;
783
+ d->kend = d->khead + cap;
784
+ }
785
+ return ULONG2NUM(d->vend - d->vhead);
786
+ }
787
+
788
+ static VALUE opt_class_cache(ojParser p, VALUE value) {
789
+ Usual d = (Usual)p->ctx;
790
+
791
+ return (NULL != d->class_cache) ? Qtrue : Qfalse;
792
+ }
793
+
794
+ static VALUE opt_class_cache_set(ojParser p, VALUE value) {
795
+ Usual d = (Usual)p->ctx;
796
+
797
+ if (Qtrue == value) {
798
+ if (NULL == d->class_cache) {
799
+ d->class_cache = cache_create(0, form_class_auto, MISS_AUTO == d->miss_class, false);
800
+ }
801
+ } else if (NULL != d->class_cache) {
802
+ cache_free(d->class_cache);
803
+ d->class_cache = NULL;
804
+ }
805
+ return (NULL != d->class_cache) ? Qtrue : Qfalse;
806
+ }
807
+
808
+ static VALUE opt_create_id(ojParser p, VALUE value) {
809
+ Usual d = (Usual)p->ctx;
810
+
811
+ if (NULL == d->create_id) {
812
+ return Qnil;
813
+ }
814
+ return rb_utf8_str_new(d->create_id, d->create_id_len);
815
+ }
816
+
817
+ static VALUE opt_create_id_set(ojParser p, VALUE value) {
818
+ Usual d = (Usual)p->ctx;
819
+
820
+ if (Qnil == value) {
821
+ d->create_id = NULL;
822
+ d->create_id_len = 0;
823
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
824
+ if (Qnil == d->hash_class) {
825
+ p->funcs[TOP_FUN].close_object = close_object;
826
+ p->funcs[ARRAY_FUN].close_object = close_object;
827
+ p->funcs[OBJECT_FUN].close_object = close_object;
828
+ } else {
829
+ p->funcs[TOP_FUN].close_object = close_object_class;
830
+ p->funcs[ARRAY_FUN].close_object = close_object_class;
831
+ p->funcs[OBJECT_FUN].close_object = close_object_class;
832
+ }
833
+ } else {
834
+ rb_check_type(value, T_STRING);
835
+ size_t len = RSTRING_LEN(value);
836
+
837
+ if (1 << sizeof(d->create_id_len) <= len) {
838
+ rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << sizeof(d->create_id_len));
839
+ }
840
+ d->create_id_len = (uint8_t)len;
841
+ d->create_id = str_dup(RSTRING_PTR(value), len);
842
+ p->funcs[OBJECT_FUN].add_str = add_str_key_create;
843
+ p->funcs[TOP_FUN].close_object = close_object_create;
844
+ p->funcs[ARRAY_FUN].close_object = close_object_create;
845
+ p->funcs[OBJECT_FUN].close_object = close_object_create;
846
+ }
847
+ return opt_create_id(p, value);
848
+ }
849
+
850
+ static VALUE opt_decimal(ojParser p, VALUE value) {
851
+ if (add_float_as_big == p->funcs[TOP_FUN].add_float) {
852
+ return ID2SYM(rb_intern("bigdecimal"));
853
+ }
854
+ if (add_big == p->funcs[TOP_FUN].add_big) {
855
+ return ID2SYM(rb_intern("auto"));
856
+ }
857
+ if (add_big_as_float == p->funcs[TOP_FUN].add_big) {
858
+ return ID2SYM(rb_intern("float"));
859
+ }
860
+ if (add_big_as_ruby == p->funcs[TOP_FUN].add_big) {
861
+ return ID2SYM(rb_intern("ruby"));
862
+ }
863
+ return Qnil;
864
+ }
865
+
866
+ static VALUE opt_decimal_set(ojParser p, VALUE value) {
867
+ const char *mode;
868
+ volatile VALUE s;
869
+
870
+ switch (rb_type(value)) {
871
+ case T_STRING: mode = RSTRING_PTR(value); break;
872
+ case T_SYMBOL:
873
+ s = rb_sym2str(value);
874
+ mode = RSTRING_PTR(s);
875
+ break;
876
+ default:
877
+ rb_raise(rb_eTypeError,
878
+ "the decimal options must be a Symbol or String, not %s.",
879
+ rb_class2name(rb_obj_class(value)));
880
+ break;
881
+ }
882
+ if (0 == strcmp("auto", mode)) {
883
+ p->funcs[TOP_FUN].add_big = add_big;
884
+ p->funcs[ARRAY_FUN].add_big = add_big;
885
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
886
+ p->funcs[TOP_FUN].add_float = add_float;
887
+ p->funcs[ARRAY_FUN].add_float = add_float;
888
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
889
+
890
+ return opt_decimal(p, Qnil);
891
+ }
892
+ if (0 == strcmp("bigdecimal", mode)) {
893
+ p->funcs[TOP_FUN].add_big = add_big;
894
+ p->funcs[ARRAY_FUN].add_big = add_big;
895
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
896
+ p->funcs[TOP_FUN].add_float = add_float_as_big;
897
+ p->funcs[ARRAY_FUN].add_float = add_float_as_big;
898
+ p->funcs[OBJECT_FUN].add_float = add_float_as_big_key;
899
+
900
+ return opt_decimal(p, Qnil);
901
+ }
902
+ if (0 == strcmp("float", mode)) {
903
+ p->funcs[TOP_FUN].add_big = add_big_as_float;
904
+ p->funcs[ARRAY_FUN].add_big = add_big_as_float;
905
+ p->funcs[OBJECT_FUN].add_big = add_big_as_float_key;
906
+ p->funcs[TOP_FUN].add_float = add_float;
907
+ p->funcs[ARRAY_FUN].add_float = add_float;
908
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
909
+
910
+ return opt_decimal(p, Qnil);
911
+ }
912
+ if (0 == strcmp("ruby", mode)) {
913
+ p->funcs[TOP_FUN].add_big = add_big_as_ruby;
914
+ p->funcs[ARRAY_FUN].add_big = add_big_as_ruby;
915
+ p->funcs[OBJECT_FUN].add_big = add_big_as_ruby_key;
916
+ p->funcs[TOP_FUN].add_float = add_float;
917
+ p->funcs[ARRAY_FUN].add_float = add_float;
918
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
919
+
920
+ return opt_decimal(p, Qnil);
921
+ }
922
+ rb_raise(rb_eArgError, "%s is not a valid option for the decimal option.", mode);
923
+
924
+ return Qnil;
925
+ }
926
+
927
+ static VALUE opt_hash_class(ojParser p, VALUE value) {
928
+ Usual d = (Usual)p->ctx;
929
+
930
+ return d->hash_class;
931
+ }
932
+
933
+ static VALUE opt_hash_class_set(ojParser p, VALUE value) {
934
+ Usual d = (Usual)p->ctx;
935
+
936
+ if (Qnil != value) {
937
+ rb_check_type(value, T_CLASS);
938
+ if (!rb_method_boundp(value, hset_id, 1)) {
939
+ rb_raise(rb_eArgError, "A hash class must implement the []= method.");
940
+ }
941
+ }
942
+ d->hash_class = value;
943
+ if (NULL == d->create_id) {
944
+ if (Qnil == value) {
945
+ p->funcs[TOP_FUN].close_object = close_object;
946
+ p->funcs[ARRAY_FUN].close_object = close_object;
947
+ p->funcs[OBJECT_FUN].close_object = close_object;
948
+ } else {
949
+ p->funcs[TOP_FUN].close_object = close_object_class;
950
+ p->funcs[ARRAY_FUN].close_object = close_object_class;
951
+ p->funcs[OBJECT_FUN].close_object = close_object_class;
952
+ }
953
+ }
954
+ return d->hash_class;
955
+ }
956
+
957
+ static VALUE opt_ignore_json_create(ojParser p, VALUE value) {
958
+ Usual d = (Usual)p->ctx;
959
+
960
+ return d->ignore_json_create ? Qtrue : Qfalse;
961
+ }
962
+
963
+ static VALUE opt_ignore_json_create_set(ojParser p, VALUE value) {
964
+ Usual d = (Usual)p->ctx;
965
+
966
+ d->ignore_json_create = (Qtrue == value);
967
+
968
+ return d->ignore_json_create ? Qtrue : Qfalse;
969
+ }
970
+
971
+ static VALUE opt_missing_class(ojParser p, VALUE value) {
972
+ Usual d = (Usual)p->ctx;
973
+
974
+ switch (d->miss_class) {
975
+ case MISS_AUTO: return ID2SYM(rb_intern("auto"));
976
+ case MISS_RAISE: return ID2SYM(rb_intern("raise"));
977
+ case MISS_IGNORE:
978
+ default: return ID2SYM(rb_intern("ignore"));
979
+ }
980
+ }
981
+
982
+ static VALUE opt_missing_class_set(ojParser p, VALUE value) {
983
+ Usual d = (Usual)p->ctx;
984
+ const char *mode;
985
+ volatile VALUE s;
986
+
987
+ switch (rb_type(value)) {
988
+ case T_STRING: mode = RSTRING_PTR(value); break;
989
+ case T_SYMBOL:
990
+ s = rb_sym2str(value);
991
+ mode = RSTRING_PTR(s);
992
+ break;
993
+ default:
994
+ rb_raise(rb_eTypeError,
995
+ "the missing_class options must be a Symbol or String, not %s.",
996
+ rb_class2name(rb_obj_class(value)));
997
+ break;
998
+ }
999
+ if (0 == strcmp("auto", mode)) {
1000
+ d->miss_class = MISS_AUTO;
1001
+ if (NULL != d->class_cache) {
1002
+ cache_set_form(d->class_cache, form_class_auto);
1003
+ }
1004
+ } else if (0 == strcmp("ignore", mode)) {
1005
+ d->miss_class = MISS_IGNORE;
1006
+ if (NULL != d->class_cache) {
1007
+ cache_set_form(d->class_cache, form_class);
1008
+ }
1009
+ } else if (0 == strcmp("raise", mode)) {
1010
+ d->miss_class = MISS_RAISE;
1011
+ if (NULL != d->class_cache) {
1012
+ cache_set_form(d->class_cache, form_class);
1013
+ }
1014
+ } else {
1015
+ rb_raise(rb_eArgError, "%s is not a valid value for the missing_class option.", mode);
1016
+ }
1017
+ return opt_missing_class(p, value);
1018
+ }
1019
+
1020
+ static VALUE opt_omit_null(ojParser p, VALUE value) {
1021
+ return (noop == p->funcs[OBJECT_FUN].add_null) ? Qtrue : Qfalse;
1022
+ }
1023
+
1024
+ static VALUE opt_omit_null_set(ojParser p, VALUE value) {
1025
+ if (Qtrue == value) {
1026
+ p->funcs[OBJECT_FUN].add_null = noop;
1027
+ } else {
1028
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
1029
+ }
1030
+ return (noop == p->funcs[OBJECT_FUN].add_null) ? Qtrue : Qfalse;
1031
+ }
1032
+
1033
+ static VALUE opt_symbol_keys(ojParser p, VALUE value) {
1034
+ Usual d = (Usual)p->ctx;
1035
+
1036
+ return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1037
+ }
1038
+
1039
+ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1040
+ Usual d = (Usual)p->ctx;
1041
+
1042
+ if (Qtrue == value) {
1043
+ d->sym_cache = cache_create(0, form_sym, true, false);
1044
+ cache_set_expunge_rate(d->sym_cache, d->cache_xrate);
1045
+ d->key_cache = d->sym_cache;
1046
+ if (!d->cache_keys) {
1047
+ d->get_key = sym_key;
1048
+ }
1049
+ } else {
1050
+ if (NULL != d->sym_cache) {
1051
+ cache_free(d->sym_cache);
1052
+ d->sym_cache = NULL;
1053
+ }
1054
+ if (!d->cache_keys) {
1055
+ d->get_key = str_key;
1056
+ }
1057
+ }
1058
+ return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1059
+ }
1060
+
1061
+ static VALUE opt_raise_on_empty(ojParser p, VALUE value) {
1062
+ Usual d = (Usual)p->ctx;
1063
+
1064
+ return d->raise_on_empty ? Qtrue : Qfalse;
1065
+ }
1066
+
1067
+ static VALUE opt_raise_on_empty_set(ojParser p, VALUE value) {
1068
+ Usual d = (Usual)p->ctx;
1069
+
1070
+ d->raise_on_empty = (Qtrue == value);
1071
+
1072
+ return d->raise_on_empty ? Qtrue : Qfalse;
1073
+ }
1074
+
1075
+ static VALUE option(ojParser p, const char *key, VALUE value) {
1076
+ struct opt *op;
1077
+ struct opt opts[] = {
1078
+ {.name = "array_class", .func = opt_array_class},
1079
+ {.name = "array_class=", .func = opt_array_class_set},
1080
+ {.name = "cache_keys", .func = opt_cache_keys},
1081
+ {.name = "cache_keys=", .func = opt_cache_keys_set},
1082
+ {.name = "cache_strings", .func = opt_cache_strings},
1083
+ {.name = "cache_strings=", .func = opt_cache_strings_set},
1084
+ {.name = "cache_expunge", .func = opt_cache_expunge},
1085
+ {.name = "cache_expunge=", .func = opt_cache_expunge_set},
1086
+ {.name = "capacity", .func = opt_capacity},
1087
+ {.name = "capacity=", .func = opt_capacity_set},
1088
+ {.name = "class_cache", .func = opt_class_cache},
1089
+ {.name = "class_cache=", .func = opt_class_cache_set},
1090
+ {.name = "create_id", .func = opt_create_id},
1091
+ {.name = "create_id=", .func = opt_create_id_set},
1092
+ {.name = "decimal", .func = opt_decimal},
1093
+ {.name = "decimal=", .func = opt_decimal_set},
1094
+ {.name = "hash_class", .func = opt_hash_class},
1095
+ {.name = "hash_class=", .func = opt_hash_class_set},
1096
+ {.name = "ignore_json_create", .func = opt_ignore_json_create},
1097
+ {.name = "ignore_json_create=", .func = opt_ignore_json_create_set},
1098
+ {.name = "missing_class", .func = opt_missing_class},
1099
+ {.name = "missing_class=", .func = opt_missing_class_set},
1100
+ {.name = "omit_null", .func = opt_omit_null},
1101
+ {.name = "omit_null=", .func = opt_omit_null_set},
1102
+ {.name = "symbol_keys", .func = opt_symbol_keys},
1103
+ {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1104
+ {.name = "raise_on_empty", .func = opt_raise_on_empty},
1105
+ {.name = "raise_on_empty=", .func = opt_raise_on_empty_set},
1106
+ {.name = NULL},
1107
+ };
1108
+
1109
+ for (op = opts; NULL != op->name; op++) {
1110
+ if (0 == strcmp(key, op->name)) {
1111
+ return op->func(p, value);
1112
+ }
1113
+ }
1114
+ rb_raise(rb_eArgError, "%s is not an option for the Usual delegate", key);
1115
+
1116
+ return Qnil; // Never reached due to the raise but required by the compiler.
1117
+ }
1118
+
1119
+ ///// the set up //////////////////////////////////////////////////////////////
1120
+
1121
+ void oj_init_usual(ojParser p, Usual d) {
1122
+ int cap = 4096;
1123
+
1124
+ d->vhead = OJ_R_ALLOC_N(VALUE, cap);
1125
+ d->vend = d->vhead + cap;
1126
+ d->vtail = d->vhead;
1127
+
1128
+ d->khead = OJ_R_ALLOC_N(union _key, cap);
1129
+ d->kend = d->khead + cap;
1130
+ d->ktail = d->khead;
1131
+
1132
+ cap = 256;
1133
+ d->chead = OJ_R_ALLOC_N(struct _col, cap);
1134
+ d->cend = d->chead + cap;
1135
+ d->ctail = d->chead;
1136
+
1137
+ d->get_key = cache_key;
1138
+ d->cache_keys = true;
1139
+ d->ignore_json_create = false;
1140
+ d->raise_on_empty = false;
1141
+ d->cache_str = 6;
1142
+ d->array_class = Qnil;
1143
+ d->hash_class = Qnil;
1144
+ d->create_id = NULL;
1145
+ d->create_id_len = 0;
1146
+ d->miss_class = MISS_IGNORE;
1147
+ d->cache_xrate = 1;
1148
+
1149
+ Funcs f = &p->funcs[TOP_FUN];
1150
+ f->add_null = add_null;
1151
+ f->add_true = add_true;
1152
+ f->add_false = add_false;
1153
+ f->add_int = add_int;
1154
+ f->add_float = add_float;
1155
+ f->add_big = add_big;
1156
+ f->add_str = add_str;
1157
+ f->open_array = open_array;
1158
+ f->close_array = close_array;
1159
+ f->open_object = open_object;
1160
+ f->close_object = close_object;
1161
+
1162
+ f = &p->funcs[ARRAY_FUN];
1163
+ f->add_null = add_null;
1164
+ f->add_true = add_true;
1165
+ f->add_false = add_false;
1166
+ f->add_int = add_int;
1167
+ f->add_float = add_float;
1168
+ f->add_big = add_big;
1169
+ f->add_str = add_str;
1170
+ f->open_array = open_array;
1171
+ f->close_array = close_array;
1172
+ f->open_object = open_object;
1173
+ f->close_object = close_object;
1174
+
1175
+ f = &p->funcs[OBJECT_FUN];
1176
+ f->add_null = add_null_key;
1177
+ f->add_true = add_true_key;
1178
+ f->add_false = add_false_key;
1179
+ f->add_int = add_int_key;
1180
+ f->add_float = add_float_key;
1181
+ f->add_big = add_big_key;
1182
+ f->add_str = add_str_key;
1183
+ f->open_array = open_array_key;
1184
+ f->close_array = close_array;
1185
+ f->open_object = open_object_key;
1186
+ f->close_object = close_object;
1187
+
1188
+ d->str_cache = cache_create(0, form_str, true, false);
1189
+ d->attr_cache = cache_create(0, form_attr, false, false);
1190
+ d->sym_cache = NULL;
1191
+ d->class_cache = NULL;
1192
+ d->key_cache = d->str_cache;
1193
+
1194
+ // The parser fields are set but the functions can be replaced by a
1195
+ // delegate that wraps the usual delegate.
1196
+ p->ctx = (void *)d;
1197
+ p->option = option;
1198
+ p->result = result;
1199
+ p->free = dfree;
1200
+ p->mark = mark;
1201
+ p->start = start;
1202
+
1203
+ if (0 == to_f_id) {
1204
+ to_f_id = rb_intern("to_f");
1205
+ }
1206
+ if (0 == ltlt_id) {
1207
+ ltlt_id = rb_intern("<<");
1208
+ }
1209
+ if (0 == hset_id) {
1210
+ hset_id = rb_intern("[]=");
1211
+ }
1212
+ }
1213
+
1214
+ void oj_set_parser_usual(ojParser p) {
1215
+ Usual d = OJ_R_ALLOC(struct _usual);
1216
+
1217
+ oj_init_usual(p, d);
1218
+ }