oj 3.7.4 → 3.13.21

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