oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
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
+ }