oj 3.11.5 → 3.16.5

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 (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) {