oj 3.11.5 → 3.16.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1421 -0
  3. data/README.md +19 -5
  4. data/RELEASE_NOTES.md +61 -0
  5. data/ext/oj/buf.h +20 -6
  6. data/ext/oj/cache.c +329 -0
  7. data/ext/oj/cache.h +22 -0
  8. data/ext/oj/cache8.c +10 -9
  9. data/ext/oj/circarray.c +8 -6
  10. data/ext/oj/circarray.h +2 -2
  11. data/ext/oj/code.c +19 -33
  12. data/ext/oj/code.h +2 -2
  13. data/ext/oj/compat.c +27 -77
  14. data/ext/oj/custom.c +86 -179
  15. data/ext/oj/debug.c +126 -0
  16. data/ext/oj/dump.c +256 -249
  17. data/ext/oj/dump.h +26 -12
  18. data/ext/oj/dump_compat.c +565 -642
  19. data/ext/oj/dump_leaf.c +17 -63
  20. data/ext/oj/dump_object.c +65 -187
  21. data/ext/oj/dump_strict.c +27 -51
  22. data/ext/oj/encoder.c +43 -0
  23. data/ext/oj/err.c +2 -13
  24. data/ext/oj/err.h +24 -8
  25. data/ext/oj/extconf.rb +21 -6
  26. data/ext/oj/fast.c +149 -149
  27. data/ext/oj/intern.c +313 -0
  28. data/ext/oj/intern.h +22 -0
  29. data/ext/oj/mem.c +318 -0
  30. data/ext/oj/mem.h +53 -0
  31. data/ext/oj/mimic_json.c +121 -106
  32. data/ext/oj/object.c +85 -162
  33. data/ext/oj/odd.c +89 -67
  34. data/ext/oj/odd.h +15 -15
  35. data/ext/oj/oj.c +542 -411
  36. data/ext/oj/oj.h +99 -73
  37. data/ext/oj/parse.c +175 -187
  38. data/ext/oj/parse.h +26 -24
  39. data/ext/oj/parser.c +1600 -0
  40. data/ext/oj/parser.h +101 -0
  41. data/ext/oj/rails.c +112 -159
  42. data/ext/oj/rails.h +1 -1
  43. data/ext/oj/reader.c +11 -14
  44. data/ext/oj/reader.h +4 -2
  45. data/ext/oj/resolve.c +5 -24
  46. data/ext/oj/rxclass.c +7 -6
  47. data/ext/oj/rxclass.h +1 -1
  48. data/ext/oj/saj.c +22 -33
  49. data/ext/oj/saj2.c +584 -0
  50. data/ext/oj/saj2.h +23 -0
  51. data/ext/oj/scp.c +5 -28
  52. data/ext/oj/sparse.c +28 -72
  53. data/ext/oj/stream_writer.c +50 -40
  54. data/ext/oj/strict.c +56 -61
  55. data/ext/oj/string_writer.c +72 -39
  56. data/ext/oj/trace.h +31 -4
  57. data/ext/oj/usual.c +1218 -0
  58. data/ext/oj/usual.h +69 -0
  59. data/ext/oj/util.h +1 -1
  60. data/ext/oj/val_stack.c +14 -3
  61. data/ext/oj/val_stack.h +8 -7
  62. data/ext/oj/validate.c +46 -0
  63. data/ext/oj/wab.c +63 -88
  64. data/lib/oj/active_support_helper.rb +1 -3
  65. data/lib/oj/bag.rb +7 -1
  66. data/lib/oj/easy_hash.rb +4 -5
  67. data/lib/oj/error.rb +1 -2
  68. data/lib/oj/json.rb +162 -150
  69. data/lib/oj/mimic.rb +9 -7
  70. data/lib/oj/saj.rb +20 -6
  71. data/lib/oj/schandler.rb +5 -4
  72. data/lib/oj/state.rb +12 -8
  73. data/lib/oj/version.rb +1 -2
  74. data/lib/oj.rb +2 -0
  75. data/pages/Compatibility.md +1 -1
  76. data/pages/InstallOptions.md +20 -0
  77. data/pages/JsonGem.md +15 -0
  78. data/pages/Modes.md +8 -3
  79. data/pages/Options.md +43 -5
  80. data/pages/Parser.md +309 -0
  81. data/pages/Rails.md +14 -2
  82. data/test/_test_active.rb +8 -9
  83. data/test/_test_active_mimic.rb +7 -8
  84. data/test/_test_mimic_rails.rb +17 -20
  85. data/test/activerecord/result_test.rb +5 -6
  86. data/test/activesupport6/encoding_test.rb +63 -28
  87. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  88. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  89. data/test/{activesupport5 → activesupport7}/encoding_test.rb +86 -50
  90. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  91. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  92. data/test/files.rb +15 -15
  93. data/test/foo.rb +16 -45
  94. data/test/helper.rb +11 -8
  95. data/test/isolated/shared.rb +3 -2
  96. data/test/json_gem/json_addition_test.rb +2 -2
  97. data/test/json_gem/json_common_interface_test.rb +8 -6
  98. data/test/json_gem/json_encoding_test.rb +0 -0
  99. data/test/json_gem/json_ext_parser_test.rb +1 -0
  100. data/test/json_gem/json_fixtures_test.rb +3 -2
  101. data/test/json_gem/json_generator_test.rb +56 -38
  102. data/test/json_gem/json_generic_object_test.rb +11 -11
  103. data/test/json_gem/json_parser_test.rb +54 -47
  104. data/test/json_gem/json_string_matching_test.rb +9 -9
  105. data/test/json_gem/test_helper.rb +7 -3
  106. data/test/mem.rb +34 -0
  107. data/test/perf.rb +22 -27
  108. data/test/perf_compat.rb +31 -33
  109. data/test/perf_dump.rb +50 -0
  110. data/test/perf_fast.rb +80 -82
  111. data/test/perf_file.rb +27 -29
  112. data/test/perf_object.rb +65 -69
  113. data/test/perf_once.rb +59 -0
  114. data/test/perf_parser.rb +183 -0
  115. data/test/perf_saj.rb +46 -54
  116. data/test/perf_scp.rb +58 -69
  117. data/test/perf_simple.rb +41 -39
  118. data/test/perf_strict.rb +74 -82
  119. data/test/perf_wab.rb +67 -69
  120. data/test/prec.rb +5 -5
  121. data/test/sample/change.rb +0 -1
  122. data/test/sample/dir.rb +0 -1
  123. data/test/sample/doc.rb +0 -1
  124. data/test/sample/file.rb +0 -1
  125. data/test/sample/group.rb +0 -1
  126. data/test/sample/hasprops.rb +0 -1
  127. data/test/sample/layer.rb +0 -1
  128. data/test/sample/rect.rb +0 -1
  129. data/test/sample/shape.rb +0 -1
  130. data/test/sample/text.rb +0 -1
  131. data/test/sample.rb +16 -16
  132. data/test/sample_json.rb +8 -8
  133. data/test/test_compat.rb +95 -43
  134. data/test/test_custom.rb +73 -51
  135. data/test/test_debian.rb +7 -10
  136. data/test/test_fast.rb +135 -79
  137. data/test/test_file.rb +41 -30
  138. data/test/test_gc.rb +16 -5
  139. data/test/test_generate.rb +5 -5
  140. data/test/test_hash.rb +5 -5
  141. data/test/test_integer_range.rb +9 -9
  142. data/test/test_null.rb +20 -20
  143. data/test/test_object.rb +99 -96
  144. data/test/test_parser.rb +11 -0
  145. data/test/test_parser_debug.rb +27 -0
  146. data/test/test_parser_saj.rb +337 -0
  147. data/test/test_parser_usual.rb +251 -0
  148. data/test/test_rails.rb +2 -2
  149. data/test/test_saj.rb +10 -8
  150. data/test/test_scp.rb +37 -39
  151. data/test/test_strict.rb +40 -32
  152. data/test/test_various.rb +165 -84
  153. data/test/test_wab.rb +48 -44
  154. data/test/test_writer.rb +47 -47
  155. data/test/tests.rb +13 -5
  156. data/test/tests_mimic.rb +12 -3
  157. data/test/tests_mimic_addition.rb +12 -3
  158. metadata +74 -128
  159. data/ext/oj/hash.c +0 -131
  160. data/ext/oj/hash.h +0 -19
  161. data/ext/oj/hash_test.c +0 -491
  162. data/test/activesupport4/decoding_test.rb +0 -108
  163. data/test/activesupport4/encoding_test.rb +0 -531
  164. data/test/activesupport4/test_helper.rb +0 -41
  165. data/test/activesupport5/test_helper.rb +0 -72
  166. data/test/bar.rb +0 -35
  167. data/test/baz.rb +0 -16
  168. data/test/zoo.rb +0 -13
data/ext/oj/saj2.c ADDED
@@ -0,0 +1,584 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include "saj2.h"
4
+
5
+ #include "cache.h"
6
+ #include "mem.h"
7
+ #include "oj.h"
8
+ #include "parser.h"
9
+
10
+ static VALUE get_key(ojParser p) {
11
+ Saj d = (Saj)p->ctx;
12
+ const char *key = buf_str(&p->key);
13
+ size_t len = buf_len(&p->key);
14
+ volatile VALUE rkey;
15
+
16
+ if (d->cache_keys) {
17
+ rkey = cache_intern(d->str_cache, key, len);
18
+ } else {
19
+ rkey = rb_utf8_str_new(key, len);
20
+ }
21
+ return rkey;
22
+ }
23
+
24
+ static void push_key(Saj d, VALUE key) {
25
+ if (d->klen <= (size_t)(d->tail - d->keys)) {
26
+ size_t off = d->tail - d->keys;
27
+
28
+ d->klen += d->klen / 2;
29
+ OJ_R_REALLOC_N(d->keys, VALUE, d->klen);
30
+ d->tail = d->keys + off;
31
+ }
32
+ *d->tail = key;
33
+ d->tail++;
34
+ }
35
+
36
+ static void noop(ojParser p) {
37
+ }
38
+
39
+ static void open_object(ojParser p) {
40
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
41
+ }
42
+
43
+ static void open_object_loc(ojParser p) {
44
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
45
+ }
46
+
47
+ static void open_object_key(ojParser p) {
48
+ Saj d = (Saj)p->ctx;
49
+ volatile VALUE key = get_key(p);
50
+
51
+ push_key(d, key);
52
+ rb_funcall(d->handler, oj_hash_start_id, 1, key);
53
+ }
54
+
55
+ static void open_object_loc_key(ojParser p) {
56
+ Saj d = (Saj)p->ctx;
57
+ volatile VALUE key = get_key(p);
58
+
59
+ push_key(d, key);
60
+ rb_funcall(d->handler, oj_hash_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
61
+ }
62
+
63
+ static void open_array(ojParser p) {
64
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 1, Qnil);
65
+ }
66
+
67
+ static void open_array_loc(ojParser p) {
68
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
69
+ }
70
+
71
+ static void open_array_key(ojParser p) {
72
+ Saj d = (Saj)p->ctx;
73
+ volatile VALUE key = get_key(p);
74
+
75
+ push_key(d, key);
76
+ rb_funcall(d->handler, oj_array_start_id, 1, key);
77
+ }
78
+
79
+ static void open_array_loc_key(ojParser p) {
80
+ Saj d = (Saj)p->ctx;
81
+ volatile VALUE key = get_key(p);
82
+
83
+ push_key(d, key);
84
+ rb_funcall(d->handler, oj_array_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
85
+ }
86
+
87
+ static void close_object(ojParser p) {
88
+ Saj d = (Saj)p->ctx;
89
+ VALUE key = Qnil;
90
+
91
+ if (OBJECT_FUN == p->stack[p->depth]) {
92
+ d->tail--;
93
+ if (d->tail < d->keys) {
94
+ rb_raise(rb_eIndexError, "accessing key stack");
95
+ }
96
+ key = *d->tail;
97
+ }
98
+ rb_funcall(d->handler, oj_hash_end_id, 1, key);
99
+ }
100
+
101
+ static void close_object_loc(ojParser p) {
102
+ Saj d = (Saj)p->ctx;
103
+ VALUE key = Qnil;
104
+
105
+ if (OBJECT_FUN == p->stack[p->depth]) {
106
+ d->tail--;
107
+ if (d->tail < d->keys) {
108
+ rb_raise(rb_eIndexError, "accessing key stack");
109
+ }
110
+ key = *d->tail;
111
+ }
112
+ rb_funcall(d->handler, oj_hash_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
113
+ }
114
+
115
+ static void close_array(ojParser p) {
116
+ Saj d = (Saj)p->ctx;
117
+ VALUE key = Qnil;
118
+
119
+ if (OBJECT_FUN == p->stack[p->depth]) {
120
+ d->tail--;
121
+ if (d->tail < d->keys) {
122
+ rb_raise(rb_eIndexError, "accessing key stack");
123
+ }
124
+ key = *d->tail;
125
+ }
126
+ rb_funcall(d->handler, oj_array_end_id, 1, key);
127
+ }
128
+
129
+ static void close_array_loc(ojParser p) {
130
+ Saj d = (Saj)p->ctx;
131
+ VALUE key = Qnil;
132
+
133
+ if (OBJECT_FUN == p->stack[p->depth]) {
134
+ d->tail--;
135
+ if (d->tail < d->keys) {
136
+ rb_raise(rb_eIndexError, "accessing key stack");
137
+ }
138
+ key = *d->tail;
139
+ }
140
+ rb_funcall(d->handler, oj_array_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
141
+ }
142
+
143
+ static void add_null(ojParser p) {
144
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
145
+ }
146
+
147
+ static void add_null_loc(ojParser p) {
148
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 4, Qnil, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
149
+ }
150
+
151
+ static void add_null_key(ojParser p) {
152
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
153
+ }
154
+
155
+ static void add_null_key_loc(ojParser p) {
156
+ rb_funcall(((Saj)p->ctx)->handler,
157
+ oj_add_value_id,
158
+ 4,
159
+ Qnil,
160
+ get_key(p),
161
+ LONG2FIX(p->line),
162
+ LONG2FIX(p->cur - p->col));
163
+ }
164
+
165
+ static void add_true(ojParser p) {
166
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
167
+ }
168
+
169
+ static void add_true_loc(ojParser p) {
170
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 4, Qtrue, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
171
+ }
172
+
173
+ static void add_true_key(ojParser p) {
174
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
175
+ }
176
+
177
+ static void add_true_key_loc(ojParser p) {
178
+ rb_funcall(((Saj)p->ctx)->handler,
179
+ oj_add_value_id,
180
+ 4,
181
+ Qtrue,
182
+ get_key(p),
183
+ LONG2FIX(p->line),
184
+ LONG2FIX(p->cur - p->col));
185
+ }
186
+
187
+ static void add_false(ojParser p) {
188
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
189
+ }
190
+
191
+ static void add_false_loc(ojParser p) {
192
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 4, Qfalse, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
193
+ }
194
+
195
+ static void add_false_key(ojParser p) {
196
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
197
+ }
198
+
199
+ static void add_false_key_loc(ojParser p) {
200
+ rb_funcall(((Saj)p->ctx)->handler,
201
+ oj_add_value_id,
202
+ 4,
203
+ Qfalse,
204
+ get_key(p),
205
+ LONG2FIX(p->line),
206
+ LONG2FIX(p->cur - p->col));
207
+ }
208
+
209
+ static void add_int(ojParser p) {
210
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
211
+ }
212
+
213
+ static void add_int_loc(ojParser p) {
214
+ rb_funcall(((Saj)p->ctx)->handler,
215
+ oj_add_value_id,
216
+ 4,
217
+ LONG2NUM(p->num.fixnum),
218
+ Qnil,
219
+ LONG2FIX(p->line),
220
+ LONG2FIX(p->cur - p->col));
221
+ }
222
+
223
+ static void add_int_key(ojParser p) {
224
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
225
+ }
226
+
227
+ static void add_int_key_loc(ojParser p) {
228
+ rb_funcall(((Saj)p->ctx)->handler,
229
+ oj_add_value_id,
230
+ 4,
231
+ LONG2NUM(p->num.fixnum),
232
+ get_key(p),
233
+ LONG2FIX(p->line),
234
+ LONG2FIX(p->cur - p->col));
235
+ }
236
+
237
+ static void add_float(ojParser p) {
238
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
239
+ }
240
+
241
+ static void add_float_loc(ojParser p) {
242
+ rb_funcall(((Saj)p->ctx)->handler,
243
+ oj_add_value_id,
244
+ 4,
245
+ rb_float_new(p->num.dub),
246
+ Qnil,
247
+ LONG2FIX(p->line),
248
+ LONG2FIX(p->cur - p->col));
249
+ }
250
+
251
+ static void add_float_key(ojParser p) {
252
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
253
+ }
254
+
255
+ static void add_float_key_loc(ojParser p) {
256
+ rb_funcall(((Saj)p->ctx)->handler,
257
+ oj_add_value_id,
258
+ 4,
259
+ rb_float_new(p->num.dub),
260
+ get_key(p),
261
+ LONG2FIX(p->line),
262
+ LONG2FIX(p->cur - p->col));
263
+ }
264
+
265
+ static void add_big(ojParser p) {
266
+ rb_funcall(((Saj)p->ctx)->handler,
267
+ oj_add_value_id,
268
+ 2,
269
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
270
+ Qnil);
271
+ }
272
+
273
+ static void add_big_loc(ojParser p) {
274
+ rb_funcall(((Saj)p->ctx)->handler,
275
+ oj_add_value_id,
276
+ 4,
277
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
278
+ Qnil,
279
+ LONG2FIX(p->line),
280
+ LONG2FIX(p->cur - p->col));
281
+ }
282
+
283
+ static void add_big_key(ojParser p) {
284
+ rb_funcall(((Saj)p->ctx)->handler,
285
+ oj_add_value_id,
286
+ 2,
287
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
288
+ get_key(p));
289
+ }
290
+
291
+ static void add_big_key_loc(ojParser p) {
292
+ rb_funcall(((Saj)p->ctx)->handler,
293
+ oj_add_value_id,
294
+ 4,
295
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
296
+ get_key(p),
297
+ LONG2FIX(p->line),
298
+ LONG2FIX(p->cur - p->col));
299
+ }
300
+
301
+ static void add_str(ojParser p) {
302
+ Saj d = (Saj)p->ctx;
303
+ volatile VALUE rstr;
304
+ const char *str = buf_str(&p->buf);
305
+ size_t len = buf_len(&p->buf);
306
+
307
+ if (d->cache_str < len) {
308
+ rstr = cache_intern(d->str_cache, str, len);
309
+ } else {
310
+ rstr = rb_utf8_str_new(str, len);
311
+ }
312
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
313
+ }
314
+
315
+ static void add_str_loc(ojParser p) {
316
+ Saj d = (Saj)p->ctx;
317
+ volatile VALUE rstr;
318
+ const char *str = buf_str(&p->buf);
319
+ size_t len = buf_len(&p->buf);
320
+
321
+ if (d->cache_str < len) {
322
+ rstr = cache_intern(d->str_cache, str, len);
323
+ } else {
324
+ rstr = rb_utf8_str_new(str, len);
325
+ }
326
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
327
+ }
328
+
329
+ static void add_str_key(ojParser p) {
330
+ Saj d = (Saj)p->ctx;
331
+ volatile VALUE rstr;
332
+ const char *str = buf_str(&p->buf);
333
+ size_t len = buf_len(&p->buf);
334
+
335
+ if (d->cache_str < len) {
336
+ rstr = cache_intern(d->str_cache, str, len);
337
+ } else {
338
+ rstr = rb_utf8_str_new(str, len);
339
+ }
340
+ rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
341
+ }
342
+
343
+ static void add_str_key_loc(ojParser p) {
344
+ Saj d = (Saj)p->ctx;
345
+ volatile VALUE rstr;
346
+ const char *str = buf_str(&p->buf);
347
+ size_t len = buf_len(&p->buf);
348
+
349
+ if (d->cache_str < len) {
350
+ rstr = cache_intern(d->str_cache, str, len);
351
+ } else {
352
+ rstr = rb_utf8_str_new(str, len);
353
+ }
354
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, get_key(p), LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
355
+ }
356
+
357
+ static void reset(ojParser p) {
358
+ Funcs end = p->funcs + 3;
359
+ Funcs f;
360
+
361
+ for (f = p->funcs; f < end; f++) {
362
+ f->add_null = noop;
363
+ f->add_true = noop;
364
+ f->add_false = noop;
365
+ f->add_int = noop;
366
+ f->add_float = noop;
367
+ f->add_big = noop;
368
+ f->add_str = noop;
369
+ f->open_array = noop;
370
+ f->close_array = noop;
371
+ f->open_object = noop;
372
+ f->close_object = noop;
373
+ }
374
+ }
375
+
376
+ static VALUE option(ojParser p, const char *key, VALUE value) {
377
+ Saj d = (Saj)p->ctx;
378
+
379
+ if (0 == strcmp(key, "handler")) {
380
+ return d->handler;
381
+ }
382
+ if (0 == strcmp(key, "handler=")) {
383
+ d->tail = d->keys;
384
+ d->handler = value;
385
+ reset(p);
386
+ if (rb_respond_to(value, oj_hash_start_id)) {
387
+ if (1 == rb_obj_method_arity(value, oj_hash_start_id)) {
388
+ p->funcs[TOP_FUN].open_object = open_object;
389
+ p->funcs[ARRAY_FUN].open_object = open_object;
390
+ p->funcs[OBJECT_FUN].open_object = open_object_key;
391
+ } else {
392
+ p->funcs[TOP_FUN].open_object = open_object_loc;
393
+ p->funcs[ARRAY_FUN].open_object = open_object_loc;
394
+ p->funcs[OBJECT_FUN].open_object = open_object_loc_key;
395
+ }
396
+ }
397
+ if (rb_respond_to(value, oj_array_start_id)) {
398
+ if (1 == rb_obj_method_arity(value, oj_array_start_id)) {
399
+ p->funcs[TOP_FUN].open_array = open_array;
400
+ p->funcs[ARRAY_FUN].open_array = open_array;
401
+ p->funcs[OBJECT_FUN].open_array = open_array_key;
402
+ } else {
403
+ p->funcs[TOP_FUN].open_array = open_array_loc;
404
+ p->funcs[ARRAY_FUN].open_array = open_array_loc;
405
+ p->funcs[OBJECT_FUN].open_array = open_array_loc_key;
406
+ }
407
+ }
408
+ if (rb_respond_to(value, oj_hash_end_id)) {
409
+ if (1 == rb_obj_method_arity(value, oj_hash_end_id)) {
410
+ p->funcs[TOP_FUN].close_object = close_object;
411
+ p->funcs[ARRAY_FUN].close_object = close_object;
412
+ p->funcs[OBJECT_FUN].close_object = close_object;
413
+ } else {
414
+ p->funcs[TOP_FUN].close_object = close_object_loc;
415
+ p->funcs[ARRAY_FUN].close_object = close_object_loc;
416
+ p->funcs[OBJECT_FUN].close_object = close_object_loc;
417
+ }
418
+ }
419
+ if (rb_respond_to(value, oj_array_end_id)) {
420
+ if (1 == rb_obj_method_arity(value, oj_array_end_id)) {
421
+ p->funcs[TOP_FUN].close_array = close_array;
422
+ p->funcs[ARRAY_FUN].close_array = close_array;
423
+ p->funcs[OBJECT_FUN].close_array = close_array;
424
+ } else {
425
+ p->funcs[TOP_FUN].close_array = close_array_loc;
426
+ p->funcs[ARRAY_FUN].close_array = close_array_loc;
427
+ p->funcs[OBJECT_FUN].close_array = close_array_loc;
428
+ }
429
+ }
430
+ if (rb_respond_to(value, oj_add_value_id)) {
431
+ if (2 == rb_obj_method_arity(value, oj_add_value_id)) {
432
+ p->funcs[TOP_FUN].add_null = add_null;
433
+ p->funcs[ARRAY_FUN].add_null = add_null;
434
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
435
+
436
+ p->funcs[TOP_FUN].add_true = add_true;
437
+ p->funcs[ARRAY_FUN].add_true = add_true;
438
+ p->funcs[OBJECT_FUN].add_true = add_true_key;
439
+
440
+ p->funcs[TOP_FUN].add_false = add_false;
441
+ p->funcs[ARRAY_FUN].add_false = add_false;
442
+ p->funcs[OBJECT_FUN].add_false = add_false_key;
443
+
444
+ p->funcs[TOP_FUN].add_int = add_int;
445
+ p->funcs[ARRAY_FUN].add_int = add_int;
446
+ p->funcs[OBJECT_FUN].add_int = add_int_key;
447
+
448
+ p->funcs[TOP_FUN].add_float = add_float;
449
+ p->funcs[ARRAY_FUN].add_float = add_float;
450
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
451
+
452
+ p->funcs[TOP_FUN].add_big = add_big;
453
+ p->funcs[ARRAY_FUN].add_big = add_big;
454
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
455
+
456
+ p->funcs[TOP_FUN].add_str = add_str;
457
+ p->funcs[ARRAY_FUN].add_str = add_str;
458
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
459
+ } else {
460
+ p->funcs[TOP_FUN].add_null = add_null_loc;
461
+ p->funcs[ARRAY_FUN].add_null = add_null_loc;
462
+ p->funcs[OBJECT_FUN].add_null = add_null_key_loc;
463
+
464
+ p->funcs[TOP_FUN].add_true = add_true_loc;
465
+ p->funcs[ARRAY_FUN].add_true = add_true_loc;
466
+ p->funcs[OBJECT_FUN].add_true = add_true_key_loc;
467
+
468
+ p->funcs[TOP_FUN].add_false = add_false_loc;
469
+ p->funcs[ARRAY_FUN].add_false = add_false_loc;
470
+ p->funcs[OBJECT_FUN].add_false = add_false_key_loc;
471
+
472
+ p->funcs[TOP_FUN].add_int = add_int_loc;
473
+ p->funcs[ARRAY_FUN].add_int = add_int_loc;
474
+ p->funcs[OBJECT_FUN].add_int = add_int_key_loc;
475
+
476
+ p->funcs[TOP_FUN].add_float = add_float_loc;
477
+ p->funcs[ARRAY_FUN].add_float = add_float_loc;
478
+ p->funcs[OBJECT_FUN].add_float = add_float_key_loc;
479
+
480
+ p->funcs[TOP_FUN].add_big = add_big_loc;
481
+ p->funcs[ARRAY_FUN].add_big = add_big_loc;
482
+ p->funcs[OBJECT_FUN].add_big = add_big_key_loc;
483
+
484
+ p->funcs[TOP_FUN].add_str = add_str_loc;
485
+ p->funcs[ARRAY_FUN].add_str = add_str_loc;
486
+ p->funcs[OBJECT_FUN].add_str = add_str_key_loc;
487
+ }
488
+ }
489
+ return Qnil;
490
+ }
491
+ if (0 == strcmp(key, "cache_keys")) {
492
+ return d->cache_keys ? Qtrue : Qfalse;
493
+ }
494
+ if (0 == strcmp(key, "cache_keys=")) {
495
+ d->cache_keys = (Qtrue == value);
496
+
497
+ return d->cache_keys ? Qtrue : Qfalse;
498
+ }
499
+ if (0 == strcmp(key, "cache_strings")) {
500
+ return INT2NUM((int)d->cache_str);
501
+ }
502
+ if (0 == strcmp(key, "cache_strings=")) {
503
+ int limit = NUM2INT(value);
504
+
505
+ if (CACHE_MAX_KEY < limit) {
506
+ limit = CACHE_MAX_KEY;
507
+ } else if (limit < 0) {
508
+ limit = 0;
509
+ }
510
+ d->cache_str = limit;
511
+
512
+ return INT2NUM((int)d->cache_str);
513
+ }
514
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) saj", key);
515
+
516
+ return Qnil; // Never reached due to the raise but required by the compiler.
517
+ }
518
+
519
+ static VALUE result(ojParser p) {
520
+ return Qnil;
521
+ }
522
+
523
+ static void start(ojParser p) {
524
+ Saj d = (Saj)p->ctx;
525
+
526
+ d->tail = d->keys;
527
+ }
528
+
529
+ static void dfree(ojParser p) {
530
+ Saj d = (Saj)p->ctx;
531
+
532
+ if (NULL != d->keys) {
533
+ OJ_R_FREE(d->keys);
534
+ }
535
+ cache_free(d->str_cache);
536
+ OJ_R_FREE(p->ctx);
537
+ }
538
+
539
+ static void mark(ojParser p) {
540
+ if (NULL == p || NULL == p->ctx) {
541
+ return;
542
+ }
543
+ Saj d = (Saj)p->ctx;
544
+ VALUE *kp;
545
+
546
+ cache_mark(d->str_cache);
547
+ if (Qnil != d->handler) {
548
+ rb_gc_mark(d->handler);
549
+ }
550
+ if (!d->cache_keys) {
551
+ for (kp = d->keys; kp < d->tail; kp++) {
552
+ rb_gc_mark(*kp);
553
+ }
554
+ }
555
+ }
556
+
557
+ static VALUE form_str(const char *str, size_t len) {
558
+ return rb_str_freeze(rb_utf8_str_new(str, len));
559
+ }
560
+
561
+ void oj_init_saj(ojParser p, Saj d) {
562
+ d->klen = 256;
563
+ d->keys = OJ_R_ALLOC_N(VALUE, d->klen);
564
+ d->tail = d->keys;
565
+ d->handler = Qnil;
566
+ d->str_cache = cache_create(0, form_str, true, false);
567
+ d->cache_str = 16;
568
+ d->cache_keys = true;
569
+ d->thread_safe = false;
570
+
571
+ p->ctx = (void *)d;
572
+ reset(p);
573
+ p->option = option;
574
+ p->result = result;
575
+ p->free = dfree;
576
+ p->mark = mark;
577
+ p->start = start;
578
+ }
579
+
580
+ void oj_set_parser_saj(ojParser p) {
581
+ Saj d = OJ_R_ALLOC(struct _saj);
582
+
583
+ oj_init_saj(p, d);
584
+ }
data/ext/oj/saj2.h ADDED
@@ -0,0 +1,23 @@
1
+ // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
+
3
+ #include <ruby.h>
4
+ #include <stdbool.h>
5
+
6
+ struct _cache;
7
+ struct _ojParser;
8
+
9
+ typedef struct _saj {
10
+ VALUE handler;
11
+ VALUE *keys;
12
+ VALUE *tail;
13
+ size_t klen;
14
+ struct _cache *str_cache;
15
+ uint8_t cache_str;
16
+ bool cache_keys;
17
+ bool thread_safe;
18
+ } *Saj;
19
+
20
+ // Initialize the parser with the SAJ delegate. If the SAJ delegate is wrapped
21
+ // then this function is called first and then the parser functions can be
22
+ // replaced.
23
+ extern void oj_init_saj(struct _ojParser *p, Saj d);
data/ext/oj/scp.c CHANGED
@@ -9,6 +9,7 @@
9
9
  #include <unistd.h>
10
10
 
11
11
  #include "encode.h"
12
+ #include "intern.h"
12
13
  #include "oj.h"
13
14
  #include "parse.h"
14
15
 
@@ -32,8 +33,7 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
32
33
  return Qundef;
33
34
  }
34
35
 
35
- static void
36
- noop_hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
36
+ static void noop_hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
37
37
  }
38
38
 
39
39
  static void noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
@@ -82,19 +82,6 @@ static void end_array(ParseInfo pi) {
82
82
  rb_funcall(pi->handler, oj_array_end_id, 0);
83
83
  }
84
84
 
85
- static VALUE calc_hash_key(ParseInfo pi, Val kval) {
86
- volatile VALUE rkey = kval->key_val;
87
-
88
- if (Qundef == rkey) {
89
- rkey = rb_str_new(kval->key, kval->klen);
90
- rkey = oj_encode(rkey);
91
- if (Yes == pi->options.sym_key) {
92
- rkey = rb_str_intern(rkey);
93
- }
94
- }
95
- return rkey;
96
- }
97
-
98
85
  static VALUE hash_key(ParseInfo pi, const char *key, size_t klen) {
99
86
  return rb_funcall(pi->handler, oj_hash_key_id, 1, rb_str_new(key, klen));
100
87
  }
@@ -103,12 +90,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
103
90
  volatile VALUE rstr = rb_str_new(str, len);
104
91
 
105
92
  rstr = oj_encode(rstr);
106
- rb_funcall(pi->handler,
107
- oj_hash_set_id,
108
- 3,
109
- stack_peek(&pi->stack)->val,
110
- calc_hash_key(pi, kval),
111
- rstr);
93
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, kval), rstr);
112
94
  }
113
95
 
114
96
  static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
@@ -116,17 +98,12 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
116
98
  oj_hash_set_id,
117
99
  3,
118
100
  stack_peek(&pi->stack)->val,
119
- calc_hash_key(pi, kval),
101
+ oj_calc_hash_key(pi, kval),
120
102
  oj_num_as_value(ni));
121
103
  }
122
104
 
123
105
  static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
124
- rb_funcall(pi->handler,
125
- oj_hash_set_id,
126
- 3,
127
- stack_peek(&pi->stack)->val,
128
- calc_hash_key(pi, kval),
129
- value);
106
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, kval), value);
130
107
  }
131
108
 
132
109
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {