oj 3.12.3 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
data/ext/oj/scp.c CHANGED
@@ -9,7 +9,7 @@
9
9
  #include <unistd.h>
10
10
 
11
11
  #include "encode.h"
12
- #include "hash.h"
12
+ #include "intern.h"
13
13
  #include "oj.h"
14
14
  #include "parse.h"
15
15
 
data/ext/oj/sparse.c CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  #include "buf.h"
11
11
  #include "encode.h"
12
- #include "hash.h" // for oj_strndup()
12
+ #include "intern.h" // for oj_strndup()
13
13
  #include "oj.h"
14
14
  #include "parse.h"
15
15
  #include "val_stack.h"
@@ -56,9 +56,9 @@ static VALUE buffer_size_sym = Qundef;
56
56
  /* Document-method: new
57
57
  * call-seq: new(io, options)
58
58
  *
59
- * Creates a new StreamWriter. Options are supported according the the
60
- * specified mode or the mode in the default options. Note that if mimic_JSON
61
- * or Oj.optimize_rails has not been called then the behavior of the modes may
59
+ * Creates a new StreamWriter. Options are supported according the specified
60
+ * mode or the mode in the default options. Note that if mimic_JSON or
61
+ * Oj.optimize_rails has not been called then the behavior of the modes may
62
62
  * not be the same as if they were.
63
63
  *
64
64
  * In addition to the regular dump options for the various modes a
data/ext/oj/strict.c CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  #include "encode.h"
10
10
  #include "err.h"
11
- #include "hash.h"
11
+ #include "intern.h"
12
12
  #include "oj.h"
13
13
  #include "parse.h"
14
14
  #include "trace.h"
@@ -17,14 +17,7 @@ VALUE oj_cstr_to_value(const char *str, size_t len, size_t cache_str) {
17
17
  volatile VALUE rstr = Qnil;
18
18
 
19
19
  if (len <= cache_str) {
20
- VALUE *slot;
21
-
22
- if (Qnil == (rstr = oj_str_hash_get(str, len, &slot))) {
23
- rstr = rb_str_new(str, len);
24
- rstr = oj_encode(rstr);
25
- *slot = rstr;
26
- rb_gc_register_address(slot);
27
- }
20
+ rstr = oj_str_intern(str, len);
28
21
  } else {
29
22
  rstr = rb_str_new(str, len);
30
23
  rstr = oj_encode(rstr);
@@ -39,31 +32,21 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
39
32
  return rkey;
40
33
  }
41
34
  if (Yes != pi->options.cache_keys) {
42
- rkey = rb_str_new(parent->key, parent->klen);
43
- rkey = oj_encode(rkey);
44
35
  if (Yes == pi->options.sym_key) {
45
- rkey = rb_str_intern(rkey);
36
+ rkey = ID2SYM(rb_intern3(parent->key, parent->klen, oj_utf8_encoding));
37
+ } else {
38
+ rkey = rb_str_new(parent->key, parent->klen);
39
+ rkey = oj_encode(rkey);
46
40
  }
41
+ OBJ_FREEZE(rkey);
47
42
  return rkey;
48
43
  }
49
- VALUE *slot;
50
-
51
44
  if (Yes == pi->options.sym_key) {
52
- if (Qnil == (rkey = oj_sym_hash_get(parent->key, parent->klen, &slot))) {
53
- rkey = rb_str_new(parent->key, parent->klen);
54
- rkey = oj_encode(rkey);
55
- rkey = rb_str_intern(rkey);
56
- *slot = rkey;
57
- rb_gc_register_address(slot);
58
- }
45
+ rkey = oj_sym_intern(parent->key, parent->klen);
59
46
  } else {
60
- if (Qnil == (rkey = oj_str_hash_get(parent->key, parent->klen, &slot))) {
61
- rkey = rb_str_new(parent->key, parent->klen);
62
- rkey = oj_encode(rkey);
63
- *slot = rkey;
64
- rb_gc_register_address(slot);
65
- }
47
+ rkey = oj_str_intern(parent->key, parent->klen);
66
48
  }
49
+ OBJ_FREEZE(rkey);
67
50
  return rkey;
68
51
  }
69
52
 
data/ext/oj/usual.c ADDED
@@ -0,0 +1,1222 @@
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[22];
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 miss_class;
81
+ bool cache_keys;
82
+ bool ignore_json_create;
83
+ } * Delegate;
84
+
85
+ static ID to_f_id = 0;
86
+ static ID ltlt_id = 0;
87
+ static ID hset_id = 0;
88
+
89
+ static char *str_dup(const char *s, size_t len) {
90
+ char *d = ALLOC_N(char, len + 1);
91
+
92
+ memcpy(d, s, len);
93
+ d[len] = '\0';
94
+
95
+ return d;
96
+ }
97
+
98
+ static VALUE form_str(const char *str, size_t len) {
99
+ return rb_str_freeze(rb_utf8_str_new(str, len));
100
+ }
101
+
102
+ static VALUE form_sym(const char *str, size_t len) {
103
+ // return ID2SYM(rb_intern3(str, len, oj_utf8_encoding));
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) - 1) {
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) - 1) {
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) - 1) {
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) - 1) {
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) + 1) {
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
+ Delegate d = (Delegate)p->ctx;
327
+
328
+ d->ctail--;
329
+
330
+ Col c = d->ctail;
331
+ Key kp = d->khead + c->ki;
332
+ VALUE * head = d->vhead + c->vi + 1;
333
+ volatile VALUE obj = rb_hash_new();
334
+
335
+ #if HAVE_RB_HASH_BULK_INSERT
336
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
337
+ *vp = d->get_key(p, kp);
338
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
339
+ xfree(kp->key);
340
+ }
341
+ }
342
+ rb_hash_bulk_insert(d->vtail - head, head, obj);
343
+ #else
344
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
345
+ rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
346
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
347
+ xfree(kp->key);
348
+ }
349
+ }
350
+ #endif
351
+ d->ktail = d->khead + c->ki;
352
+ d->vtail = head;
353
+ head--;
354
+ *head = obj;
355
+ }
356
+
357
+ static void close_object_class(ojParser p) {
358
+ Delegate d = (Delegate)p->ctx;
359
+
360
+ d->ctail--;
361
+
362
+ Col c = d->ctail;
363
+ Key kp = d->khead + c->ki;
364
+ VALUE * head = d->vhead + c->vi + 1;
365
+ volatile VALUE obj = rb_class_new_instance(0, NULL, d->hash_class);
366
+
367
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
368
+ rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
369
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
370
+ xfree(kp->key);
371
+ }
372
+ }
373
+ d->ktail = d->khead + c->ki;
374
+ d->vtail = head;
375
+ head--;
376
+ *head = obj;
377
+ }
378
+
379
+ static void close_object_create(ojParser p) {
380
+ Delegate d = (Delegate)p->ctx;
381
+
382
+ d->ctail--;
383
+
384
+ Col c = d->ctail;
385
+ Key kp = d->khead + c->ki;
386
+ VALUE * head = d->vhead + c->vi;
387
+ volatile VALUE obj;
388
+
389
+ if (Qundef == *head) {
390
+ head++;
391
+ if (Qnil == d->hash_class) {
392
+ obj = rb_hash_new();
393
+ #if HAVE_RB_HASH_BULK_INSERT
394
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
395
+ *vp = d->get_key(p, kp);
396
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
397
+ xfree(kp->key);
398
+ }
399
+ }
400
+ rb_hash_bulk_insert(d->vtail - head, head, obj);
401
+ #else
402
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
403
+ rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
404
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
405
+ xfree(kp->key);
406
+ }
407
+ }
408
+ #endif
409
+ } else {
410
+ obj = rb_class_new_instance(0, NULL, d->hash_class);
411
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
412
+ rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
413
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
414
+ xfree(kp->key);
415
+ }
416
+ }
417
+ }
418
+ } else {
419
+ VALUE clas = *head;
420
+
421
+ head++;
422
+ if (!d->ignore_json_create && rb_respond_to(clas, oj_json_create_id)) {
423
+ volatile VALUE arg = rb_hash_new();
424
+
425
+ #if HAVE_RB_HASH_BULK_INSERT
426
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
427
+ *vp = d->get_key(p, kp);
428
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
429
+ xfree(kp->key);
430
+ }
431
+ }
432
+ rb_hash_bulk_insert(d->vtail - head, head, arg);
433
+ #else
434
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
435
+ rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
436
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
437
+ xfree(kp->key);
438
+ }
439
+ }
440
+ #endif
441
+ obj = rb_funcall(clas, oj_json_create_id, 1, arg);
442
+ } else {
443
+ obj = rb_class_new_instance(0, NULL, clas);
444
+ for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
445
+ rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
446
+ if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
447
+ xfree(kp->key);
448
+ }
449
+ }
450
+ }
451
+ }
452
+ d->ktail = d->khead + c->ki;
453
+ d->vtail = head;
454
+ head--;
455
+ *head = obj;
456
+ }
457
+
458
+ static void close_array(ojParser p) {
459
+ Delegate d = (Delegate)p->ctx;
460
+
461
+ d->ctail--;
462
+ VALUE * head = d->vhead + d->ctail->vi + 1;
463
+ volatile VALUE a = rb_ary_new_from_values(d->vtail - head, head);
464
+
465
+ d->vtail = head;
466
+ head--;
467
+ *head = a;
468
+ }
469
+
470
+ static void close_array_class(ojParser p) {
471
+ Delegate d = (Delegate)p->ctx;
472
+
473
+ d->ctail--;
474
+ VALUE * head = d->vhead + d->ctail->vi + 1;
475
+ volatile VALUE a = rb_class_new_instance(0, NULL, d->array_class);
476
+
477
+ for (VALUE *vp = head; vp < d->vtail; vp++) {
478
+ rb_funcall(a, ltlt_id, 1, *vp);
479
+ }
480
+ d->vtail = head;
481
+ head--;
482
+ *head = a;
483
+ }
484
+
485
+ static void noop(ojParser p) {
486
+ }
487
+
488
+ static void add_null(ojParser p) {
489
+ push(p, Qnil);
490
+ }
491
+
492
+ static void add_null_key(ojParser p) {
493
+ push_key(p);
494
+ push2(p, Qnil);
495
+ }
496
+
497
+ static void add_true(ojParser p) {
498
+ push(p, Qtrue);
499
+ }
500
+
501
+ static void add_true_key(ojParser p) {
502
+ push_key(p);
503
+ push2(p, Qtrue);
504
+ }
505
+
506
+ static void add_false(ojParser p) {
507
+ push(p, Qfalse);
508
+ }
509
+
510
+ static void add_false_key(ojParser p) {
511
+ push_key(p);
512
+ push2(p, Qfalse);
513
+ }
514
+
515
+ static void add_int(ojParser p) {
516
+ push(p, LONG2NUM(p->num.fixnum));
517
+ }
518
+
519
+ static void add_int_key(ojParser p) {
520
+ push_key(p);
521
+ push2(p, LONG2NUM(p->num.fixnum));
522
+ }
523
+
524
+ static void add_float(ojParser p) {
525
+ push(p, rb_float_new(p->num.dub));
526
+ }
527
+
528
+ static void add_float_key(ojParser p) {
529
+ push_key(p);
530
+ push2(p, rb_float_new(p->num.dub));
531
+ }
532
+
533
+ static void add_float_as_big(ojParser p) {
534
+ char buf[64];
535
+
536
+ // fails on ubuntu
537
+ // snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
538
+ sprintf(buf, "%Lg", p->num.dub);
539
+ push(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
540
+ }
541
+
542
+ static void add_float_as_big_key(ojParser p) {
543
+ char buf[64];
544
+
545
+ snprintf(buf, sizeof(buf), "%Lg", p->num.dub);
546
+ push_key(p);
547
+ push2(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new2(buf)));
548
+ }
549
+
550
+ static void add_big(ojParser p) {
551
+ push(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))));
552
+ }
553
+
554
+ static void add_big_key(ojParser p) {
555
+ push_key(p);
556
+ push2(p, rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))));
557
+ }
558
+
559
+ static void add_big_as_float(ojParser p) {
560
+ volatile VALUE big = rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf)));
561
+
562
+ push(p, rb_funcall(big, to_f_id, 0));
563
+ }
564
+
565
+ static void add_big_as_float_key(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_key(p);
569
+ push2(p, rb_funcall(big, to_f_id, 0));
570
+ }
571
+
572
+ static void add_big_as_ruby(ojParser p) {
573
+ push(p, rb_funcall(rb_str_new(buf_str(&p->buf), buf_len(&p->buf)), to_f_id, 0));
574
+ }
575
+
576
+ static void add_big_as_ruby_key(ojParser p) {
577
+ push_key(p);
578
+ push2(p, rb_funcall(rb_str_new(buf_str(&p->buf), buf_len(&p->buf)), to_f_id, 0));
579
+ }
580
+
581
+ static void add_str(ojParser p) {
582
+ Delegate d = (Delegate)p->ctx;
583
+ volatile VALUE rstr;
584
+ const char * str = buf_str(&p->buf);
585
+ size_t len = buf_len(&p->buf);
586
+
587
+ if (len < d->cache_str) {
588
+ rstr = cache_intern(d->str_cache, str, len);
589
+ } else {
590
+ rstr = rb_utf8_str_new(str, len);
591
+ }
592
+ push(p, rstr);
593
+ }
594
+
595
+ static void add_str_key(ojParser p) {
596
+ Delegate d = (Delegate)p->ctx;
597
+ volatile VALUE rstr;
598
+ const char * str = buf_str(&p->buf);
599
+ size_t len = buf_len(&p->buf);
600
+
601
+ if (len < d->cache_str) {
602
+ rstr = cache_intern(d->str_cache, str, len);
603
+ } else {
604
+ rstr = rb_utf8_str_new(str, len);
605
+ }
606
+ push_key(p);
607
+ push2(p, rstr);
608
+ }
609
+
610
+ static void add_str_key_create(ojParser p) {
611
+ Delegate d = (Delegate)p->ctx;
612
+ volatile VALUE rstr;
613
+ const char * str = buf_str(&p->buf);
614
+ size_t len = buf_len(&p->buf);
615
+ const char * key = buf_str(&p->key);
616
+ size_t klen = buf_len(&p->key);
617
+
618
+ if (klen == (size_t)d->create_id_len && 0 == strncmp(d->create_id, key, klen)) {
619
+ Col c = d->ctail - 1;
620
+ VALUE clas;
621
+
622
+ if (NULL != d->class_cache) {
623
+ clas = cache_intern(d->class_cache, str, len);
624
+ } else {
625
+ clas = resolve_classpath(str, len, MISS_AUTO == d->miss_class);
626
+ }
627
+ if (Qundef != clas) {
628
+ *(d->vhead + c->vi) = clas;
629
+ return;
630
+ }
631
+ if (MISS_RAISE == d->miss_class) {
632
+ rb_raise(rb_eLoadError, "%s is not define", str);
633
+ }
634
+ }
635
+ if (len < d->cache_str) {
636
+ rstr = cache_intern(d->str_cache, str, len);
637
+ } else {
638
+ rstr = rb_utf8_str_new(str, len);
639
+ }
640
+ push_key(p);
641
+ push2(p, rstr);
642
+ }
643
+
644
+ static VALUE result(ojParser p) {
645
+ Delegate d = (Delegate)p->ctx;
646
+
647
+ if (d->vhead < d->vtail) {
648
+ return *d->vhead;
649
+ }
650
+ return Qnil;
651
+ }
652
+
653
+ static void start(ojParser p) {
654
+ Delegate d = (Delegate)p->ctx;
655
+
656
+ d->vtail = d->vhead;
657
+ d->ctail = d->chead;
658
+ d->ktail = d->khead;
659
+ }
660
+
661
+ static void dfree(ojParser p) {
662
+ Delegate d = (Delegate)p->ctx;
663
+
664
+ cache_free(d->str_cache);
665
+ cache_free(d->attr_cache);
666
+ if (NULL != d->sym_cache) {
667
+ cache_free(d->sym_cache);
668
+ }
669
+ if (NULL != d->class_cache) {
670
+ cache_free(d->class_cache);
671
+ }
672
+ xfree(d->vhead);
673
+ xfree(d->chead);
674
+ xfree(d->khead);
675
+ xfree(d->create_id);
676
+ xfree(p->ctx);
677
+ p->ctx = NULL;
678
+ }
679
+
680
+ static void mark(ojParser p) {
681
+ if (NULL == p->ctx) {
682
+ return;
683
+ }
684
+ Delegate d = (Delegate)p->ctx;
685
+
686
+ if (NULL == d) {
687
+ return;
688
+ }
689
+ cache_mark(d->str_cache);
690
+ if (NULL != d->sym_cache) {
691
+ cache_mark(d->sym_cache);
692
+ }
693
+ if (NULL != d->class_cache) {
694
+ cache_mark(d->class_cache);
695
+ }
696
+ for (VALUE *vp = d->vhead; vp < d->vtail; vp++) {
697
+ if (Qundef != *vp) {
698
+ rb_gc_mark(*vp);
699
+ }
700
+ }
701
+ }
702
+
703
+ ///// options /////////////////////////////////////////////////////////////////
704
+
705
+ // Each option is handled by a separate function and then added to an assoc
706
+ // list (struct opt}. The list is then iterated over until there is a name
707
+ // match. This is done primarily to keep each option separate and easier to
708
+ // understand instead of placing all in one large function.
709
+
710
+ struct opt {
711
+ const char *name;
712
+ VALUE (*func)(ojParser p, VALUE value);
713
+ };
714
+
715
+ static VALUE opt_array_class(ojParser p, VALUE value) {
716
+ Delegate d = (Delegate)p->ctx;
717
+
718
+ return d->array_class;
719
+ }
720
+
721
+ static VALUE opt_array_class_set(ojParser p, VALUE value) {
722
+ Delegate d = (Delegate)p->ctx;
723
+
724
+ if (Qnil == value) {
725
+ p->funcs[TOP_FUN].close_array = close_array;
726
+ p->funcs[ARRAY_FUN].close_array = close_array;
727
+ p->funcs[OBJECT_FUN].close_array = close_array;
728
+ } else {
729
+ rb_check_type(value, T_CLASS);
730
+ if (!rb_method_boundp(value, ltlt_id, 1)) {
731
+ rb_raise(rb_eArgError, "An array class must implement the << method.");
732
+ }
733
+ p->funcs[TOP_FUN].close_array = close_array_class;
734
+ p->funcs[ARRAY_FUN].close_array = close_array_class;
735
+ p->funcs[OBJECT_FUN].close_array = close_array_class;
736
+ }
737
+ d->array_class = value;
738
+
739
+ return d->array_class;
740
+ }
741
+
742
+ static VALUE opt_cache_keys(ojParser p, VALUE value) {
743
+ Delegate d = (Delegate)p->ctx;
744
+
745
+ return d->cache_keys ? Qtrue : Qfalse;
746
+ }
747
+
748
+ static VALUE opt_cache_keys_set(ojParser p, VALUE value) {
749
+ Delegate d = (Delegate)p->ctx;
750
+
751
+ if (Qtrue == value) {
752
+ d->cache_keys = true;
753
+ d->get_key = cache_key;
754
+ if (NULL == d->sym_cache) {
755
+ d->key_cache = d->str_cache;
756
+ } else {
757
+ d->key_cache = d->sym_cache;
758
+ }
759
+ } else {
760
+ d->cache_keys = false;
761
+ if (NULL == d->sym_cache) {
762
+ d->get_key = str_key;
763
+ } else {
764
+ d->get_key = sym_key;
765
+ }
766
+ }
767
+ return d->cache_keys ? Qtrue : Qfalse;
768
+ }
769
+
770
+ static VALUE opt_cache_strings(ojParser p, VALUE value) {
771
+ Delegate d = (Delegate)p->ctx;
772
+
773
+ return INT2NUM((int)d->cache_str);
774
+ }
775
+
776
+ static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
777
+ Delegate d = (Delegate)p->ctx;
778
+ int limit = NUM2INT(value);
779
+
780
+ if (CACHE_MAX_KEY < limit) {
781
+ limit = CACHE_MAX_KEY;
782
+ } else if (limit < 0) {
783
+ limit = 0;
784
+ }
785
+ d->cache_str = limit;
786
+
787
+ return INT2NUM((int)d->cache_str);
788
+ }
789
+
790
+ static VALUE opt_capacity(ojParser p, VALUE value) {
791
+ Delegate d = (Delegate)p->ctx;
792
+
793
+ return ULONG2NUM(d->vend - d->vhead);
794
+ }
795
+
796
+ static VALUE opt_capacity_set(ojParser p, VALUE value) {
797
+ Delegate d = (Delegate)p->ctx;
798
+ long cap = NUM2LONG(value);
799
+
800
+ if (d->vend - d->vhead < cap) {
801
+ long pos = d->vtail - d->vhead;
802
+
803
+ REALLOC_N(d->vhead, VALUE, cap);
804
+ d->vtail = d->vhead + pos;
805
+ d->vend = d->vhead + cap;
806
+ }
807
+ if (d->kend - d->khead < cap) {
808
+ long pos = d->ktail - d->khead;
809
+
810
+ REALLOC_N(d->khead, union _key, cap);
811
+ d->ktail = d->khead + pos;
812
+ d->kend = d->khead + cap;
813
+ }
814
+ return ULONG2NUM(d->vend - d->vhead);
815
+ }
816
+
817
+ static VALUE opt_class_cache(ojParser p, VALUE value) {
818
+ Delegate d = (Delegate)p->ctx;
819
+
820
+ return (NULL != d->class_cache) ? Qtrue : Qfalse;
821
+ }
822
+
823
+ static VALUE opt_class_cache_set(ojParser p, VALUE value) {
824
+ Delegate d = (Delegate)p->ctx;
825
+
826
+ if (Qtrue == value) {
827
+ if (NULL == d->class_cache) {
828
+ if (MISS_AUTO == d->miss_class) {
829
+ d->class_cache = cache_create(0, form_class_auto, true);
830
+ } else {
831
+ d->class_cache = cache_create(0, form_class, false);
832
+ }
833
+ }
834
+ } else if (NULL != d->class_cache) {
835
+ cache_free(d->class_cache);
836
+ d->class_cache = NULL;
837
+ }
838
+ return (NULL != d->class_cache) ? Qtrue : Qfalse;
839
+ }
840
+
841
+ static VALUE opt_create_id(ojParser p, VALUE value) {
842
+ Delegate d = (Delegate)p->ctx;
843
+
844
+ if (NULL == d->create_id) {
845
+ return Qnil;
846
+ }
847
+ return rb_utf8_str_new(d->create_id, d->create_id_len);
848
+ }
849
+
850
+ static VALUE opt_create_id_set(ojParser p, VALUE value) {
851
+ Delegate d = (Delegate)p->ctx;
852
+
853
+ if (Qnil == value) {
854
+ d->create_id = NULL;
855
+ d->create_id_len = 0;
856
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
857
+ if (Qnil == d->hash_class) {
858
+ p->funcs[TOP_FUN].close_object = close_object;
859
+ p->funcs[ARRAY_FUN].close_object = close_object;
860
+ p->funcs[OBJECT_FUN].close_object = close_object;
861
+ } else {
862
+ p->funcs[TOP_FUN].close_object = close_object_class;
863
+ p->funcs[ARRAY_FUN].close_object = close_object_class;
864
+ p->funcs[OBJECT_FUN].close_object = close_object_class;
865
+ }
866
+ } else {
867
+ rb_check_type(value, T_STRING);
868
+ size_t len = RSTRING_LEN(value);
869
+
870
+ if (1 << sizeof(d->create_id_len) <= len) {
871
+ rb_raise(rb_eArgError, "The create_id values is limited to %d bytes.", 1 << sizeof(d->create_id_len));
872
+ }
873
+ d->create_id_len = (uint8_t)len;
874
+ d->create_id = str_dup(RSTRING_PTR(value), len);
875
+ p->funcs[OBJECT_FUN].add_str = add_str_key_create;
876
+ p->funcs[TOP_FUN].close_object = close_object_create;
877
+ p->funcs[ARRAY_FUN].close_object = close_object_create;
878
+ p->funcs[OBJECT_FUN].close_object = close_object_create;
879
+ }
880
+ return opt_create_id(p, value);
881
+ }
882
+
883
+ static VALUE opt_decimal(ojParser p, VALUE value) {
884
+ if (add_float_as_big == p->funcs[TOP_FUN].add_float) {
885
+ return ID2SYM(rb_intern("bigdecimal"));
886
+ }
887
+ if (add_big == p->funcs[TOP_FUN].add_big) {
888
+ return ID2SYM(rb_intern("auto"));
889
+ }
890
+ if (add_big_as_float == p->funcs[TOP_FUN].add_big) {
891
+ return ID2SYM(rb_intern("float"));
892
+ }
893
+ if (add_big_as_ruby == p->funcs[TOP_FUN].add_big) {
894
+ return ID2SYM(rb_intern("ruby"));
895
+ }
896
+ return Qnil;
897
+ }
898
+
899
+ static VALUE opt_decimal_set(ojParser p, VALUE value) {
900
+ const char * mode;
901
+ volatile VALUE s;
902
+
903
+ switch (rb_type(value)) {
904
+ case T_STRING: mode = RSTRING_PTR(value); break;
905
+ case T_SYMBOL:
906
+ s = rb_sym_to_s(value);
907
+ mode = RSTRING_PTR(s);
908
+ break;
909
+ default:
910
+ rb_raise(rb_eTypeError,
911
+ "the decimal options must be a Symbol or String, not %s.",
912
+ rb_class2name(rb_obj_class(value)));
913
+ break;
914
+ }
915
+ if (0 == strcmp("auto", mode)) {
916
+ p->funcs[TOP_FUN].add_big = add_big;
917
+ p->funcs[ARRAY_FUN].add_big = add_big;
918
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
919
+ p->funcs[TOP_FUN].add_float = add_float;
920
+ p->funcs[ARRAY_FUN].add_float = add_float;
921
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
922
+
923
+ return opt_decimal(p, Qnil);
924
+ }
925
+ if (0 == strcmp("bigdecimal", mode)) {
926
+ p->funcs[TOP_FUN].add_big = add_big;
927
+ p->funcs[ARRAY_FUN].add_big = add_big;
928
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
929
+ p->funcs[TOP_FUN].add_float = add_float_as_big;
930
+ p->funcs[ARRAY_FUN].add_float = add_float_as_big;
931
+ p->funcs[OBJECT_FUN].add_float = add_float_as_big_key;
932
+
933
+ return opt_decimal(p, Qnil);
934
+ }
935
+ if (0 == strcmp("float", mode)) {
936
+ p->funcs[TOP_FUN].add_big = add_big_as_float;
937
+ p->funcs[ARRAY_FUN].add_big = add_big_as_float;
938
+ p->funcs[OBJECT_FUN].add_big = add_big_as_float_key;
939
+ p->funcs[TOP_FUN].add_float = add_float;
940
+ p->funcs[ARRAY_FUN].add_float = add_float;
941
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
942
+
943
+ return opt_decimal(p, Qnil);
944
+ }
945
+ if (0 == strcmp("ruby", mode)) {
946
+ p->funcs[TOP_FUN].add_big = add_big_as_ruby;
947
+ p->funcs[ARRAY_FUN].add_big = add_big_as_ruby;
948
+ p->funcs[OBJECT_FUN].add_big = add_big_as_ruby_key;
949
+ p->funcs[TOP_FUN].add_float = add_float;
950
+ p->funcs[ARRAY_FUN].add_float = add_float;
951
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
952
+
953
+ return opt_decimal(p, Qnil);
954
+ }
955
+ rb_raise(rb_eArgError, "%s is not a valid option for the decimal option.", mode);
956
+
957
+ return Qnil;
958
+ }
959
+
960
+ static VALUE opt_hash_class(ojParser p, VALUE value) {
961
+ Delegate d = (Delegate)p->ctx;
962
+
963
+ return d->hash_class;
964
+ }
965
+
966
+ static VALUE opt_hash_class_set(ojParser p, VALUE value) {
967
+ Delegate d = (Delegate)p->ctx;
968
+
969
+ if (Qnil != value) {
970
+ rb_check_type(value, T_CLASS);
971
+ if (!rb_method_boundp(value, hset_id, 1)) {
972
+ rb_raise(rb_eArgError, "A hash class must implement the []= method.");
973
+ }
974
+ }
975
+ d->hash_class = value;
976
+ if (NULL == d->create_id) {
977
+ if (Qnil == value) {
978
+ p->funcs[TOP_FUN].close_object = close_object;
979
+ p->funcs[ARRAY_FUN].close_object = close_object;
980
+ p->funcs[OBJECT_FUN].close_object = close_object;
981
+ } else {
982
+ p->funcs[TOP_FUN].close_object = close_object_class;
983
+ p->funcs[ARRAY_FUN].close_object = close_object_class;
984
+ p->funcs[OBJECT_FUN].close_object = close_object_class;
985
+ }
986
+ }
987
+ return d->hash_class;
988
+ }
989
+
990
+ static VALUE opt_ignore_json_create(ojParser p, VALUE value) {
991
+ Delegate d = (Delegate)p->ctx;
992
+
993
+ return d->ignore_json_create ? Qtrue : Qfalse;
994
+ }
995
+
996
+ static VALUE opt_ignore_json_create_set(ojParser p, VALUE value) {
997
+ Delegate d = (Delegate)p->ctx;
998
+
999
+ d->ignore_json_create = (Qtrue == value);
1000
+
1001
+ return d->ignore_json_create ? Qtrue : Qfalse;
1002
+ }
1003
+
1004
+ static VALUE opt_missing_class(ojParser p, VALUE value) {
1005
+ Delegate d = (Delegate)p->ctx;
1006
+
1007
+ switch (d->miss_class) {
1008
+ case MISS_AUTO: return ID2SYM(rb_intern("auto"));
1009
+ case MISS_RAISE: return ID2SYM(rb_intern("raise"));
1010
+ case MISS_IGNORE:
1011
+ default: return ID2SYM(rb_intern("ignore"));
1012
+ }
1013
+ }
1014
+
1015
+ static VALUE opt_missing_class_set(ojParser p, VALUE value) {
1016
+ Delegate d = (Delegate)p->ctx;
1017
+ const char * mode;
1018
+ volatile VALUE s;
1019
+
1020
+ switch (rb_type(value)) {
1021
+ case T_STRING: mode = RSTRING_PTR(value); break;
1022
+ case T_SYMBOL:
1023
+ s = rb_sym_to_s(value);
1024
+ mode = RSTRING_PTR(s);
1025
+ break;
1026
+ default:
1027
+ rb_raise(rb_eTypeError,
1028
+ "the missing_class options must be a Symbol or String, not %s.",
1029
+ rb_class2name(rb_obj_class(value)));
1030
+ break;
1031
+ }
1032
+ if (0 == strcmp("auto", mode)) {
1033
+ d->miss_class = MISS_AUTO;
1034
+ if (NULL != d->class_cache) {
1035
+ cache_set_form(d->class_cache, form_class_auto);
1036
+ }
1037
+ } else if (0 == strcmp("ignore", mode)) {
1038
+ d->miss_class = MISS_IGNORE;
1039
+ if (NULL != d->class_cache) {
1040
+ cache_set_form(d->class_cache, form_class);
1041
+ }
1042
+ } else if (0 == strcmp("raise", mode)) {
1043
+ d->miss_class = MISS_RAISE;
1044
+ if (NULL != d->class_cache) {
1045
+ cache_set_form(d->class_cache, form_class);
1046
+ }
1047
+ } else {
1048
+ rb_raise(rb_eArgError, "%s is not a valid value for the missing_class option.", mode);
1049
+ }
1050
+ return opt_missing_class(p, value);
1051
+ }
1052
+
1053
+ static VALUE opt_omit_null(ojParser p, VALUE value) {
1054
+ return (noop == p->funcs[OBJECT_FUN].add_null) ? Qtrue : Qfalse;
1055
+ }
1056
+
1057
+ static VALUE opt_omit_null_set(ojParser p, VALUE value) {
1058
+ if (Qtrue == value) {
1059
+ p->funcs[OBJECT_FUN].add_null = noop;
1060
+ } else {
1061
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
1062
+ }
1063
+ return (noop == p->funcs[OBJECT_FUN].add_null) ? Qtrue : Qfalse;
1064
+ }
1065
+
1066
+ static VALUE opt_symbol_keys(ojParser p, VALUE value) {
1067
+ Delegate d = (Delegate)p->ctx;
1068
+
1069
+ return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1070
+ }
1071
+
1072
+ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1073
+ Delegate d = (Delegate)p->ctx;
1074
+
1075
+ if (Qtrue == value) {
1076
+ d->sym_cache = cache_create(0, form_sym, true);
1077
+ d->key_cache = d->sym_cache;
1078
+ if (!d->cache_keys) {
1079
+ d->get_key = sym_key;
1080
+ }
1081
+ } else {
1082
+ if (NULL != d->sym_cache) {
1083
+ cache_free(d->sym_cache);
1084
+ d->sym_cache = NULL;
1085
+ }
1086
+ if (!d->cache_keys) {
1087
+ d->get_key = str_key;
1088
+ }
1089
+ }
1090
+ return (NULL != d->sym_cache) ? Qtrue : Qfalse;
1091
+ }
1092
+
1093
+ static VALUE option(ojParser p, const char *key, VALUE value) {
1094
+ struct opt opts[] = {
1095
+ {.name = "array_class", .func = opt_array_class},
1096
+ {.name = "array_class=", .func = opt_array_class_set},
1097
+ {.name = "cache_keys", .func = opt_cache_keys},
1098
+ {.name = "cache_keys=", .func = opt_cache_keys_set},
1099
+ {.name = "cache_strings", .func = opt_cache_strings},
1100
+ {.name = "cache_strings=", .func = opt_cache_strings_set},
1101
+ {.name = "capacity", .func = opt_capacity},
1102
+ {.name = "capacity=", .func = opt_capacity_set},
1103
+ {.name = "class_cache", .func = opt_class_cache},
1104
+ {.name = "class_cache=", .func = opt_class_cache_set},
1105
+ {.name = "create_id", .func = opt_create_id},
1106
+ {.name = "create_id=", .func = opt_create_id_set},
1107
+ {.name = "decimal", .func = opt_decimal},
1108
+ {.name = "decimal=", .func = opt_decimal_set},
1109
+ {.name = "hash_class", .func = opt_hash_class},
1110
+ {.name = "hash_class=", .func = opt_hash_class_set},
1111
+ {.name = "ignore_json_create", .func = opt_ignore_json_create},
1112
+ {.name = "ignore_json_create=", .func = opt_ignore_json_create_set},
1113
+ {.name = "missing_class", .func = opt_missing_class},
1114
+ {.name = "missing_class=", .func = opt_missing_class_set},
1115
+ {.name = "omit_null", .func = opt_omit_null},
1116
+ {.name = "omit_null=", .func = opt_omit_null_set},
1117
+ {.name = "symbol_keys", .func = opt_symbol_keys},
1118
+ {.name = "symbol_keys=", .func = opt_symbol_keys_set},
1119
+ {.name = NULL},
1120
+ };
1121
+
1122
+ for (struct opt *op = opts; NULL != op->name; op++) {
1123
+ if (0 == strcmp(key, op->name)) {
1124
+ return op->func(p, value);
1125
+ }
1126
+ }
1127
+ rb_raise(rb_eArgError, "%s is not an option for the Usual delegate", key);
1128
+
1129
+ return Qnil; // Never reached due to the raise but required by the compiler.
1130
+ }
1131
+
1132
+ ///// the set up //////////////////////////////////////////////////////////////
1133
+
1134
+ void oj_set_parser_usual(ojParser p) {
1135
+ Delegate d = ALLOC(struct _delegate);
1136
+ int cap = 4096;
1137
+
1138
+ d->vhead = ALLOC_N(VALUE, cap);
1139
+ d->vend = d->vhead + cap;
1140
+ d->vtail = d->vhead;
1141
+
1142
+ d->khead = ALLOC_N(union _key, cap);
1143
+ d->kend = d->khead + cap;
1144
+ d->ktail = d->khead;
1145
+
1146
+ cap = 256;
1147
+ d->chead = ALLOC_N(struct _col, cap);
1148
+ d->cend = d->chead + cap;
1149
+ d->ctail = d->chead;
1150
+
1151
+ d->get_key = cache_key;
1152
+ d->cache_keys = true;
1153
+ d->ignore_json_create = false;
1154
+ d->cache_str = 6;
1155
+ d->array_class = Qnil;
1156
+ d->hash_class = Qnil;
1157
+ d->create_id = NULL;
1158
+ d->create_id_len = 0;
1159
+ d->miss_class = MISS_IGNORE;
1160
+
1161
+ Funcs f = &p->funcs[TOP_FUN];
1162
+ f->add_null = add_null;
1163
+ f->add_true = add_true;
1164
+ f->add_false = add_false;
1165
+ f->add_int = add_int;
1166
+ f->add_float = add_float;
1167
+ f->add_big = add_big;
1168
+ f->add_str = add_str;
1169
+ f->open_array = open_array;
1170
+ f->close_array = close_array;
1171
+ f->open_object = open_object;
1172
+ f->close_object = close_object;
1173
+
1174
+ f = &p->funcs[ARRAY_FUN];
1175
+ f->add_null = add_null;
1176
+ f->add_true = add_true;
1177
+ f->add_false = add_false;
1178
+ f->add_int = add_int;
1179
+ f->add_float = add_float;
1180
+ f->add_big = add_big;
1181
+ f->add_str = add_str;
1182
+ f->open_array = open_array;
1183
+ f->close_array = close_array;
1184
+ f->open_object = open_object;
1185
+ f->close_object = close_object;
1186
+
1187
+ f = &p->funcs[OBJECT_FUN];
1188
+ f->add_null = add_null_key;
1189
+ f->add_true = add_true_key;
1190
+ f->add_false = add_false_key;
1191
+ f->add_int = add_int_key;
1192
+ f->add_float = add_float_key;
1193
+ f->add_big = add_big_key;
1194
+ f->add_str = add_str_key;
1195
+ f->open_array = open_array_key;
1196
+ f->close_array = close_array;
1197
+ f->open_object = open_object_key;
1198
+ f->close_object = close_object;
1199
+
1200
+ d->str_cache = cache_create(0, form_str, true);
1201
+ d->attr_cache = cache_create(0, form_attr, false);
1202
+ d->sym_cache = NULL;
1203
+ d->class_cache = NULL;
1204
+ d->key_cache = d->str_cache;
1205
+
1206
+ p->ctx = (void *)d;
1207
+ p->option = option;
1208
+ p->result = result;
1209
+ p->free = dfree;
1210
+ p->mark = mark;
1211
+ p->start = start;
1212
+
1213
+ if (0 == to_f_id) {
1214
+ to_f_id = rb_intern("to_f");
1215
+ }
1216
+ if (0 == ltlt_id) {
1217
+ ltlt_id = rb_intern("<<");
1218
+ }
1219
+ if (0 == hset_id) {
1220
+ hset_id = rb_intern("[]=");
1221
+ }
1222
+ }