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/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
+ }