oj 3.7.4 → 3.13.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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/saj2.c ADDED
@@ -0,0 +1,602 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "cache.h"
4
+ #include "oj.h"
5
+ #include "parser.h"
6
+
7
+ typedef struct _delegate {
8
+ VALUE handler;
9
+ VALUE *keys;
10
+ VALUE *tail;
11
+ size_t klen;
12
+ struct _cache *str_cache;
13
+ uint8_t cache_str;
14
+ bool cache_keys;
15
+ bool thread_safe;
16
+ } * Delegate;
17
+
18
+ static VALUE get_key(ojParser p) {
19
+ Delegate d = (Delegate)p->ctx;
20
+ const char *key = buf_str(&p->key);
21
+ size_t len = buf_len(&p->key);
22
+ volatile VALUE rkey;
23
+
24
+ if (d->cache_keys) {
25
+ rkey = cache_intern(d->str_cache, key, len);
26
+ } else {
27
+ rkey = rb_utf8_str_new(key, len);
28
+ }
29
+ return rkey;
30
+ }
31
+
32
+ static void push_key(Delegate d, VALUE key) {
33
+ if (d->klen <= (size_t)(d->tail - d->keys)) {
34
+ size_t off = d->tail - d->keys;
35
+
36
+ d->klen += d->klen / 2;
37
+ REALLOC_N(d->keys, VALUE, d->klen);
38
+ d->tail = d->keys + off;
39
+ }
40
+ *d->tail = key;
41
+ d->tail++;
42
+ }
43
+
44
+ static void noop(ojParser p) {
45
+ }
46
+
47
+ static void open_object(ojParser p) {
48
+ rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
49
+ }
50
+
51
+ static void open_object_loc(ojParser p) {
52
+ rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
53
+ }
54
+
55
+ static void open_object_key(ojParser p) {
56
+ Delegate d = (Delegate)p->ctx;
57
+ volatile VALUE key = get_key(p);
58
+
59
+ push_key(d, key);
60
+ rb_funcall(d->handler, oj_hash_start_id, 1, key);
61
+ }
62
+
63
+ static void open_object_loc_key(ojParser p) {
64
+ Delegate d = (Delegate)p->ctx;
65
+ volatile VALUE key = get_key(p);
66
+
67
+ push_key(d, key);
68
+ rb_funcall(d->handler, oj_hash_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
69
+ }
70
+
71
+ static void open_array(ojParser p) {
72
+ rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 1, Qnil);
73
+ }
74
+
75
+ static void open_array_loc(ojParser p) {
76
+ rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
77
+ }
78
+
79
+ static void open_array_key(ojParser p) {
80
+ Delegate d = (Delegate)p->ctx;
81
+ volatile VALUE key = get_key(p);
82
+
83
+ push_key(d, key);
84
+ rb_funcall(d->handler, oj_array_start_id, 1, key);
85
+ }
86
+
87
+ static void open_array_loc_key(ojParser p) {
88
+ Delegate d = (Delegate)p->ctx;
89
+ volatile VALUE key = get_key(p);
90
+
91
+ push_key(d, key);
92
+ rb_funcall(d->handler, oj_array_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
93
+ }
94
+
95
+ static void close_object(ojParser p) {
96
+ Delegate d = (Delegate)p->ctx;
97
+ VALUE key = Qnil;
98
+
99
+ if (OBJECT_FUN == p->stack[p->depth]) {
100
+ d->tail--;
101
+ if (d->tail < d->keys) {
102
+ rb_raise(rb_eIndexError, "accessing key stack");
103
+ }
104
+ key = *d->tail;
105
+ }
106
+ rb_funcall(d->handler, oj_hash_end_id, 1, key);
107
+ }
108
+
109
+ static void close_object_loc(ojParser p) {
110
+ Delegate d = (Delegate)p->ctx;
111
+ VALUE key = Qnil;
112
+
113
+ if (OBJECT_FUN == p->stack[p->depth]) {
114
+ d->tail--;
115
+ if (d->tail < d->keys) {
116
+ rb_raise(rb_eIndexError, "accessing key stack");
117
+ }
118
+ key = *d->tail;
119
+ }
120
+ rb_funcall(d->handler, oj_hash_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
121
+ }
122
+
123
+ static void close_array(ojParser p) {
124
+ Delegate d = (Delegate)p->ctx;
125
+ VALUE key = Qnil;
126
+
127
+ if (OBJECT_FUN == p->stack[p->depth]) {
128
+ d->tail--;
129
+ if (d->tail < d->keys) {
130
+ rb_raise(rb_eIndexError, "accessing key stack");
131
+ }
132
+ key = *d->tail;
133
+ }
134
+ rb_funcall(d->handler, oj_array_end_id, 1, key);
135
+ }
136
+
137
+ static void close_array_loc(ojParser p) {
138
+ Delegate d = (Delegate)p->ctx;
139
+ VALUE key = Qnil;
140
+
141
+ if (OBJECT_FUN == p->stack[p->depth]) {
142
+ d->tail--;
143
+ if (d->tail < d->keys) {
144
+ rb_raise(rb_eIndexError, "accessing key stack");
145
+ }
146
+ key = *d->tail;
147
+ }
148
+ rb_funcall(d->handler, oj_array_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
149
+ }
150
+
151
+ static void add_null(ojParser p) {
152
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
153
+ }
154
+
155
+ static void add_null_loc(ojParser p) {
156
+ rb_funcall(((Delegate)p->ctx)->handler,
157
+ oj_add_value_id,
158
+ 4,
159
+ Qnil,
160
+ Qnil,
161
+ LONG2FIX(p->line),
162
+ LONG2FIX(p->cur - p->col));
163
+ }
164
+
165
+ static void add_null_key(ojParser p) {
166
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
167
+ }
168
+
169
+ static void add_null_key_loc(ojParser p) {
170
+ rb_funcall(((Delegate)p->ctx)->handler,
171
+ oj_add_value_id,
172
+ 4,
173
+ Qnil,
174
+ get_key(p),
175
+ LONG2FIX(p->line),
176
+ LONG2FIX(p->cur - p->col));
177
+ }
178
+
179
+ static void add_true(ojParser p) {
180
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
181
+ }
182
+
183
+ static void add_true_loc(ojParser p) {
184
+ rb_funcall(((Delegate)p->ctx)->handler,
185
+ oj_add_value_id,
186
+ 4,
187
+ Qtrue,
188
+ Qnil,
189
+ LONG2FIX(p->line),
190
+ LONG2FIX(p->cur - p->col));
191
+ }
192
+
193
+ static void add_true_key(ojParser p) {
194
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
195
+ }
196
+
197
+ static void add_true_key_loc(ojParser p) {
198
+ rb_funcall(((Delegate)p->ctx)->handler,
199
+ oj_add_value_id,
200
+ 4,
201
+ Qtrue,
202
+ get_key(p),
203
+ LONG2FIX(p->line),
204
+ LONG2FIX(p->cur - p->col));
205
+ }
206
+
207
+ static void add_false(ojParser p) {
208
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
209
+ }
210
+
211
+ static void add_false_loc(ojParser p) {
212
+ rb_funcall(((Delegate)p->ctx)->handler,
213
+ oj_add_value_id,
214
+ 4,
215
+ Qfalse,
216
+ Qnil,
217
+ LONG2FIX(p->line),
218
+ LONG2FIX(p->cur - p->col));
219
+ }
220
+
221
+ static void add_false_key(ojParser p) {
222
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
223
+ }
224
+
225
+ static void add_false_key_loc(ojParser p) {
226
+ rb_funcall(((Delegate)p->ctx)->handler,
227
+ oj_add_value_id,
228
+ 4,
229
+ Qfalse,
230
+ get_key(p),
231
+ LONG2FIX(p->line),
232
+ LONG2FIX(p->cur - p->col));
233
+ }
234
+
235
+ static void add_int(ojParser p) {
236
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
237
+ }
238
+
239
+ static void add_int_loc(ojParser p) {
240
+ rb_funcall(((Delegate)p->ctx)->handler,
241
+ oj_add_value_id,
242
+ 4,
243
+ LONG2NUM(p->num.fixnum),
244
+ Qnil,
245
+ LONG2FIX(p->line),
246
+ LONG2FIX(p->cur - p->col));
247
+ }
248
+
249
+ static void add_int_key(ojParser p) {
250
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
251
+ }
252
+
253
+ static void add_int_key_loc(ojParser p) {
254
+ rb_funcall(((Delegate)p->ctx)->handler,
255
+ oj_add_value_id,
256
+ 4,
257
+ LONG2NUM(p->num.fixnum),
258
+ get_key(p),
259
+ LONG2FIX(p->line),
260
+ LONG2FIX(p->cur - p->col));
261
+ }
262
+
263
+ static void add_float(ojParser p) {
264
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
265
+ }
266
+
267
+ static void add_float_loc(ojParser p) {
268
+ rb_funcall(((Delegate)p->ctx)->handler,
269
+ oj_add_value_id,
270
+ 4,
271
+ rb_float_new(p->num.dub),
272
+ Qnil,
273
+ LONG2FIX(p->line),
274
+ LONG2FIX(p->cur - p->col));
275
+ }
276
+
277
+ static void add_float_key(ojParser p) {
278
+ rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
279
+ }
280
+
281
+ static void add_float_key_loc(ojParser p) {
282
+ rb_funcall(((Delegate)p->ctx)->handler,
283
+ oj_add_value_id,
284
+ 4,
285
+ rb_float_new(p->num.dub),
286
+ get_key(p),
287
+ LONG2FIX(p->line),
288
+ LONG2FIX(p->cur - p->col));
289
+ }
290
+
291
+ static void add_big(ojParser p) {
292
+ rb_funcall(((Delegate)p->ctx)->handler,
293
+ oj_add_value_id,
294
+ 2,
295
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
296
+ Qnil);
297
+ }
298
+
299
+ static void add_big_loc(ojParser p) {
300
+ rb_funcall(((Delegate)p->ctx)->handler,
301
+ oj_add_value_id,
302
+ 4,
303
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
304
+ Qnil,
305
+ LONG2FIX(p->line),
306
+ LONG2FIX(p->cur - p->col));
307
+ }
308
+
309
+ static void add_big_key(ojParser p) {
310
+ rb_funcall(((Delegate)p->ctx)->handler,
311
+ oj_add_value_id,
312
+ 2,
313
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
314
+ get_key(p));
315
+ }
316
+
317
+ static void add_big_key_loc(ojParser p) {
318
+ rb_funcall(((Delegate)p->ctx)->handler,
319
+ oj_add_value_id,
320
+ 4,
321
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
322
+ get_key(p),
323
+ LONG2FIX(p->line),
324
+ LONG2FIX(p->cur - p->col));
325
+ }
326
+
327
+ static void add_str(ojParser p) {
328
+ Delegate d = (Delegate)p->ctx;
329
+ volatile VALUE rstr;
330
+ const char *str = buf_str(&p->buf);
331
+ size_t len = buf_len(&p->buf);
332
+
333
+ if (d->cache_str < len) {
334
+ rstr = cache_intern(d->str_cache, str, len);
335
+ } else {
336
+ rstr = rb_utf8_str_new(str, len);
337
+ }
338
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
339
+ }
340
+
341
+ static void add_str_loc(ojParser p) {
342
+ Delegate d = (Delegate)p->ctx;
343
+ volatile VALUE rstr;
344
+ const char *str = buf_str(&p->buf);
345
+ size_t len = buf_len(&p->buf);
346
+
347
+ if (d->cache_str < len) {
348
+ rstr = cache_intern(d->str_cache, str, len);
349
+ } else {
350
+ rstr = rb_utf8_str_new(str, len);
351
+ }
352
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
353
+ }
354
+
355
+ static void add_str_key(ojParser p) {
356
+ Delegate d = (Delegate)p->ctx;
357
+ volatile VALUE rstr;
358
+ const char *str = buf_str(&p->buf);
359
+ size_t len = buf_len(&p->buf);
360
+
361
+ if (d->cache_str < len) {
362
+ rstr = cache_intern(d->str_cache, str, len);
363
+ } else {
364
+ rstr = rb_utf8_str_new(str, len);
365
+ }
366
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
367
+ }
368
+
369
+ static void add_str_key_loc(ojParser p) {
370
+ Delegate d = (Delegate)p->ctx;
371
+ volatile VALUE rstr;
372
+ const char *str = buf_str(&p->buf);
373
+ size_t len = buf_len(&p->buf);
374
+
375
+ if (d->cache_str < len) {
376
+ rstr = cache_intern(d->str_cache, str, len);
377
+ } else {
378
+ rstr = rb_utf8_str_new(str, len);
379
+ }
380
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, get_key(p), LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
381
+ }
382
+
383
+ static void reset(ojParser p) {
384
+ Funcs end = p->funcs + 3;
385
+ Funcs f;
386
+
387
+ for (f = p->funcs; f < end; f++) {
388
+ f->add_null = noop;
389
+ f->add_true = noop;
390
+ f->add_false = noop;
391
+ f->add_int = noop;
392
+ f->add_float = noop;
393
+ f->add_big = noop;
394
+ f->add_str = noop;
395
+ f->open_array = noop;
396
+ f->close_array = noop;
397
+ f->open_object = noop;
398
+ f->close_object = noop;
399
+ }
400
+ }
401
+
402
+ static VALUE option(ojParser p, const char *key, VALUE value) {
403
+ Delegate d = (Delegate)p->ctx;
404
+
405
+ if (0 == strcmp(key, "handler")) {
406
+ return d->handler;
407
+ }
408
+ if (0 == strcmp(key, "handler=")) {
409
+ d->tail = d->keys;
410
+ d->handler = value;
411
+ reset(p);
412
+ if (rb_respond_to(value, oj_hash_start_id)) {
413
+ if (1 == rb_obj_method_arity(value, oj_hash_start_id)) {
414
+ p->funcs[TOP_FUN].open_object = open_object;
415
+ p->funcs[ARRAY_FUN].open_object = open_object;
416
+ p->funcs[OBJECT_FUN].open_object = open_object_key;
417
+ } else {
418
+ p->funcs[TOP_FUN].open_object = open_object_loc;
419
+ p->funcs[ARRAY_FUN].open_object = open_object_loc;
420
+ p->funcs[OBJECT_FUN].open_object = open_object_loc_key;
421
+ }
422
+ }
423
+ if (rb_respond_to(value, oj_array_start_id)) {
424
+ if (1 == rb_obj_method_arity(value, oj_array_start_id)) {
425
+ p->funcs[TOP_FUN].open_array = open_array;
426
+ p->funcs[ARRAY_FUN].open_array = open_array;
427
+ p->funcs[OBJECT_FUN].open_array = open_array_key;
428
+ } else {
429
+ p->funcs[TOP_FUN].open_array = open_array_loc;
430
+ p->funcs[ARRAY_FUN].open_array = open_array_loc;
431
+ p->funcs[OBJECT_FUN].open_array = open_array_loc_key;
432
+ }
433
+ }
434
+ if (rb_respond_to(value, oj_hash_end_id)) {
435
+ if (1 == rb_obj_method_arity(value, oj_hash_end_id)) {
436
+ p->funcs[TOP_FUN].close_object = close_object;
437
+ p->funcs[ARRAY_FUN].close_object = close_object;
438
+ p->funcs[OBJECT_FUN].close_object = close_object;
439
+ } else {
440
+ p->funcs[TOP_FUN].close_object = close_object_loc;
441
+ p->funcs[ARRAY_FUN].close_object = close_object_loc;
442
+ p->funcs[OBJECT_FUN].close_object = close_object_loc;
443
+ }
444
+ }
445
+ if (rb_respond_to(value, oj_array_end_id)) {
446
+ if (1 == rb_obj_method_arity(value, oj_array_end_id)) {
447
+ p->funcs[TOP_FUN].close_array = close_array;
448
+ p->funcs[ARRAY_FUN].close_array = close_array;
449
+ p->funcs[OBJECT_FUN].close_array = close_array;
450
+ } else {
451
+ p->funcs[TOP_FUN].close_array = close_array_loc;
452
+ p->funcs[ARRAY_FUN].close_array = close_array_loc;
453
+ p->funcs[OBJECT_FUN].close_array = close_array_loc;
454
+ }
455
+ }
456
+ if (rb_respond_to(value, oj_add_value_id)) {
457
+ if (2 == rb_obj_method_arity(value, oj_add_value_id)) {
458
+ p->funcs[TOP_FUN].add_null = add_null;
459
+ p->funcs[ARRAY_FUN].add_null = add_null;
460
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
461
+
462
+ p->funcs[TOP_FUN].add_true = add_true;
463
+ p->funcs[ARRAY_FUN].add_true = add_true;
464
+ p->funcs[OBJECT_FUN].add_true = add_true_key;
465
+
466
+ p->funcs[TOP_FUN].add_false = add_false;
467
+ p->funcs[ARRAY_FUN].add_false = add_false;
468
+ p->funcs[OBJECT_FUN].add_false = add_false_key;
469
+
470
+ p->funcs[TOP_FUN].add_int = add_int;
471
+ p->funcs[ARRAY_FUN].add_int = add_int;
472
+ p->funcs[OBJECT_FUN].add_int = add_int_key;
473
+
474
+ p->funcs[TOP_FUN].add_float = add_float;
475
+ p->funcs[ARRAY_FUN].add_float = add_float;
476
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
477
+
478
+ p->funcs[TOP_FUN].add_big = add_big;
479
+ p->funcs[ARRAY_FUN].add_big = add_big;
480
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
481
+
482
+ p->funcs[TOP_FUN].add_str = add_str;
483
+ p->funcs[ARRAY_FUN].add_str = add_str;
484
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
485
+ } else {
486
+ p->funcs[TOP_FUN].add_null = add_null_loc;
487
+ p->funcs[ARRAY_FUN].add_null = add_null_loc;
488
+ p->funcs[OBJECT_FUN].add_null = add_null_key_loc;
489
+
490
+ p->funcs[TOP_FUN].add_true = add_true_loc;
491
+ p->funcs[ARRAY_FUN].add_true = add_true_loc;
492
+ p->funcs[OBJECT_FUN].add_true = add_true_key_loc;
493
+
494
+ p->funcs[TOP_FUN].add_false = add_false_loc;
495
+ p->funcs[ARRAY_FUN].add_false = add_false_loc;
496
+ p->funcs[OBJECT_FUN].add_false = add_false_key_loc;
497
+
498
+ p->funcs[TOP_FUN].add_int = add_int_loc;
499
+ p->funcs[ARRAY_FUN].add_int = add_int_loc;
500
+ p->funcs[OBJECT_FUN].add_int = add_int_key_loc;
501
+
502
+ p->funcs[TOP_FUN].add_float = add_float_loc;
503
+ p->funcs[ARRAY_FUN].add_float = add_float_loc;
504
+ p->funcs[OBJECT_FUN].add_float = add_float_key_loc;
505
+
506
+ p->funcs[TOP_FUN].add_big = add_big_loc;
507
+ p->funcs[ARRAY_FUN].add_big = add_big_loc;
508
+ p->funcs[OBJECT_FUN].add_big = add_big_key_loc;
509
+
510
+ p->funcs[TOP_FUN].add_str = add_str_loc;
511
+ p->funcs[ARRAY_FUN].add_str = add_str_loc;
512
+ p->funcs[OBJECT_FUN].add_str = add_str_key_loc;
513
+ }
514
+ }
515
+ return Qnil;
516
+ }
517
+ if (0 == strcmp(key, "cache_keys")) {
518
+ return d->cache_keys ? Qtrue : Qfalse;
519
+ }
520
+ if (0 == strcmp(key, "cache_keys=")) {
521
+ d->cache_keys = (Qtrue == value);
522
+
523
+ return d->cache_keys ? Qtrue : Qfalse;
524
+ }
525
+ if (0 == strcmp(key, "cache_strings")) {
526
+ return INT2NUM((int)d->cache_str);
527
+ }
528
+ if (0 == strcmp(key, "cache_strings=")) {
529
+ int limit = NUM2INT(value);
530
+
531
+ if (CACHE_MAX_KEY < limit) {
532
+ limit = CACHE_MAX_KEY;
533
+ } else if (limit < 0) {
534
+ limit = 0;
535
+ }
536
+ d->cache_str = limit;
537
+
538
+ return INT2NUM((int)d->cache_str);
539
+ }
540
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) delegate", key);
541
+
542
+ return Qnil; // Never reached due to the raise but required by the compiler.
543
+ }
544
+
545
+ static VALUE result(ojParser p) {
546
+ return Qnil;
547
+ }
548
+
549
+ static void start(ojParser p) {
550
+ Delegate d = (Delegate)p->ctx;
551
+
552
+ d->tail = d->keys;
553
+ }
554
+
555
+ static void dfree(ojParser p) {
556
+ Delegate d = (Delegate)p->ctx;
557
+
558
+ if (NULL != d->keys) {
559
+ xfree(d->keys);
560
+ }
561
+ cache_free(d->str_cache);
562
+ xfree(p->ctx);
563
+ }
564
+
565
+ static void mark(ojParser p) {
566
+ if (NULL == p->ctx) {
567
+ return;
568
+ }
569
+ Delegate d = (Delegate)p->ctx;
570
+ VALUE *kp;
571
+
572
+ cache_mark(d->str_cache);
573
+ if (Qnil != d->handler) {
574
+ rb_gc_mark(d->handler);
575
+ }
576
+ if (!d->cache_keys) {
577
+ for (kp = d->keys; kp < d->tail; kp++) {
578
+ rb_gc_mark(*kp);
579
+ }
580
+ }
581
+ }
582
+
583
+ static VALUE form_str(const char *str, size_t len) {
584
+ return rb_str_freeze(rb_utf8_str_new(str, len));
585
+ }
586
+
587
+ void oj_set_parser_saj(ojParser p) {
588
+ Delegate d = ALLOC(struct _delegate);
589
+
590
+ d->klen = 256;
591
+ d->keys = ALLOC_N(VALUE, d->klen);
592
+ d->tail = d->keys;
593
+ d->str_cache = cache_create(0, form_str, true, false);
594
+
595
+ p->ctx = (void *)d;
596
+ reset(p);
597
+ p->option = option;
598
+ p->result = result;
599
+ p->free = dfree;
600
+ p->mark = mark;
601
+ p->start = start;
602
+ }