oj 3.13.11 → 3.15.0

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 (158) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +74 -0
  3. data/README.md +4 -2
  4. data/ext/oj/buf.h +11 -6
  5. data/ext/oj/cache.c +25 -24
  6. data/ext/oj/cache8.c +10 -9
  7. data/ext/oj/circarray.c +8 -6
  8. data/ext/oj/circarray.h +2 -2
  9. data/ext/oj/code.c +17 -24
  10. data/ext/oj/code.h +2 -2
  11. data/ext/oj/compat.c +17 -44
  12. data/ext/oj/custom.c +70 -141
  13. data/ext/oj/debug.c +3 -9
  14. data/ext/oj/dump.c +128 -118
  15. data/ext/oj/dump.h +12 -8
  16. data/ext/oj/dump_compat.c +564 -641
  17. data/ext/oj/dump_leaf.c +17 -63
  18. data/ext/oj/dump_object.c +70 -199
  19. data/ext/oj/dump_strict.c +22 -46
  20. data/ext/oj/encoder.c +1 -1
  21. data/ext/oj/err.c +2 -13
  22. data/ext/oj/err.h +9 -12
  23. data/ext/oj/extconf.rb +14 -5
  24. data/ext/oj/fast.c +75 -103
  25. data/ext/oj/intern.c +52 -50
  26. data/ext/oj/intern.h +4 -8
  27. data/ext/oj/mem.c +318 -0
  28. data/ext/oj/mem.h +53 -0
  29. data/ext/oj/mimic_json.c +75 -47
  30. data/ext/oj/object.c +49 -66
  31. data/ext/oj/odd.c +89 -67
  32. data/ext/oj/odd.h +15 -15
  33. data/ext/oj/oj.c +140 -99
  34. data/ext/oj/oj.h +80 -51
  35. data/ext/oj/parse.c +162 -184
  36. data/ext/oj/parse.h +7 -10
  37. data/ext/oj/parser.c +89 -34
  38. data/ext/oj/parser.h +18 -7
  39. data/ext/oj/rails.c +82 -146
  40. data/ext/oj/rails.h +1 -1
  41. data/ext/oj/reader.c +11 -12
  42. data/ext/oj/reader.h +4 -2
  43. data/ext/oj/resolve.c +3 -4
  44. data/ext/oj/rxclass.c +6 -5
  45. data/ext/oj/rxclass.h +1 -1
  46. data/ext/oj/saj.c +20 -31
  47. data/ext/oj/saj2.c +329 -93
  48. data/ext/oj/saj2.h +23 -0
  49. data/ext/oj/scp.c +3 -14
  50. data/ext/oj/sparse.c +26 -70
  51. data/ext/oj/stream_writer.c +12 -22
  52. data/ext/oj/strict.c +20 -52
  53. data/ext/oj/string_writer.c +21 -21
  54. data/ext/oj/trace.h +31 -4
  55. data/ext/oj/usual.c +105 -150
  56. data/ext/oj/usual.h +68 -0
  57. data/ext/oj/util.h +1 -1
  58. data/ext/oj/val_stack.c +1 -1
  59. data/ext/oj/val_stack.h +8 -7
  60. data/ext/oj/validate.c +21 -26
  61. data/ext/oj/wab.c +31 -68
  62. data/lib/oj/active_support_helper.rb +0 -1
  63. data/lib/oj/bag.rb +7 -1
  64. data/lib/oj/easy_hash.rb +4 -5
  65. data/lib/oj/error.rb +0 -1
  66. data/lib/oj/json.rb +4 -2
  67. data/lib/oj/mimic.rb +4 -2
  68. data/lib/oj/saj.rb +20 -6
  69. data/lib/oj/state.rb +9 -6
  70. data/lib/oj/version.rb +1 -2
  71. data/lib/oj.rb +2 -0
  72. data/pages/Compatibility.md +1 -1
  73. data/pages/InstallOptions.md +20 -0
  74. data/pages/Options.md +10 -0
  75. data/test/_test_active.rb +8 -9
  76. data/test/_test_active_mimic.rb +7 -8
  77. data/test/_test_mimic_rails.rb +17 -20
  78. data/test/activerecord/result_test.rb +5 -6
  79. data/test/{activesupport5 → activesupport7}/abstract_unit.rb +16 -12
  80. data/test/{activesupport5 → activesupport7}/decoding_test.rb +2 -10
  81. data/test/{activesupport5 → activesupport7}/encoding_test.rb +20 -34
  82. data/test/{activesupport5 → activesupport7}/encoding_test_cases.rb +6 -0
  83. data/test/{activesupport5 → activesupport7}/time_zone_test_helpers.rb +8 -0
  84. data/test/files.rb +15 -15
  85. data/test/foo.rb +9 -71
  86. data/test/helper.rb +11 -8
  87. data/test/isolated/shared.rb +3 -2
  88. data/test/json_gem/json_addition_test.rb +2 -2
  89. data/test/json_gem/json_common_interface_test.rb +4 -4
  90. data/test/json_gem/json_encoding_test.rb +0 -0
  91. data/test/json_gem/json_ext_parser_test.rb +1 -0
  92. data/test/json_gem/json_fixtures_test.rb +3 -2
  93. data/test/json_gem/json_generator_test.rb +48 -36
  94. data/test/json_gem/json_generic_object_test.rb +11 -11
  95. data/test/json_gem/json_parser_test.rb +54 -47
  96. data/test/json_gem/json_string_matching_test.rb +9 -9
  97. data/test/json_gem/test_helper.rb +7 -3
  98. data/test/mem.rb +13 -12
  99. data/test/perf.rb +21 -26
  100. data/test/perf_compat.rb +31 -33
  101. data/test/perf_dump.rb +50 -0
  102. data/test/perf_fast.rb +80 -82
  103. data/test/perf_file.rb +27 -29
  104. data/test/perf_object.rb +65 -69
  105. data/test/perf_once.rb +12 -11
  106. data/test/perf_parser.rb +42 -48
  107. data/test/perf_saj.rb +46 -54
  108. data/test/perf_scp.rb +57 -69
  109. data/test/perf_simple.rb +41 -39
  110. data/test/perf_strict.rb +68 -70
  111. data/test/perf_wab.rb +67 -69
  112. data/test/prec.rb +3 -3
  113. data/test/sample/change.rb +0 -1
  114. data/test/sample/dir.rb +0 -1
  115. data/test/sample/doc.rb +0 -1
  116. data/test/sample/file.rb +0 -1
  117. data/test/sample/group.rb +0 -1
  118. data/test/sample/hasprops.rb +0 -1
  119. data/test/sample/layer.rb +0 -1
  120. data/test/sample/rect.rb +0 -1
  121. data/test/sample/shape.rb +0 -1
  122. data/test/sample/text.rb +0 -1
  123. data/test/sample.rb +16 -16
  124. data/test/sample_json.rb +8 -8
  125. data/test/test_compat.rb +76 -42
  126. data/test/test_custom.rb +72 -51
  127. data/test/test_debian.rb +7 -10
  128. data/test/test_fast.rb +86 -90
  129. data/test/test_file.rb +41 -30
  130. data/test/test_gc.rb +16 -5
  131. data/test/test_generate.rb +5 -5
  132. data/test/test_hash.rb +4 -4
  133. data/test/test_integer_range.rb +9 -9
  134. data/test/test_null.rb +20 -20
  135. data/test/test_object.rb +85 -96
  136. data/test/test_parser.rb +6 -22
  137. data/test/test_parser_debug.rb +27 -0
  138. data/test/test_parser_saj.rb +115 -23
  139. data/test/test_parser_usual.rb +6 -6
  140. data/test/test_rails.rb +2 -2
  141. data/test/test_saj.rb +10 -8
  142. data/test/test_scp.rb +37 -39
  143. data/test/test_strict.rb +30 -32
  144. data/test/test_various.rb +147 -99
  145. data/test/test_wab.rb +48 -44
  146. data/test/test_writer.rb +47 -47
  147. data/test/tests.rb +13 -4
  148. data/test/tests_mimic.rb +12 -3
  149. data/test/tests_mimic_addition.rb +12 -3
  150. metadata +33 -144
  151. data/test/activesupport4/decoding_test.rb +0 -108
  152. data/test/activesupport4/encoding_test.rb +0 -531
  153. data/test/activesupport4/test_helper.rb +0 -41
  154. data/test/activesupport5/test_helper.rb +0 -72
  155. data/test/bar.rb +0 -16
  156. data/test/baz.rb +0 -16
  157. data/test/bug.rb +0 -16
  158. data/test/zoo.rb +0 -13
data/ext/oj/saj2.c CHANGED
@@ -1,23 +1,15 @@
1
1
  // Copyright (c) 2021, Peter Ohler, All rights reserved.
2
2
 
3
+ #include "saj2.h"
4
+
3
5
  #include "cache.h"
6
+ #include "mem.h"
4
7
  #include "oj.h"
5
8
  #include "parser.h"
6
9
 
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
10
  static VALUE get_key(ojParser p) {
19
- Delegate d = (Delegate)p->ctx;
20
- const char * key = buf_str(&p->key);
11
+ Saj d = (Saj)p->ctx;
12
+ const char *key = buf_str(&p->key);
21
13
  size_t len = buf_len(&p->key);
22
14
  volatile VALUE rkey;
23
15
 
@@ -29,12 +21,12 @@ static VALUE get_key(ojParser p) {
29
21
  return rkey;
30
22
  }
31
23
 
32
- static void push_key(Delegate d, VALUE key) {
24
+ static void push_key(Saj d, VALUE key) {
33
25
  if (d->klen <= (size_t)(d->tail - d->keys)) {
34
26
  size_t off = d->tail - d->keys;
35
27
 
36
28
  d->klen += d->klen / 2;
37
- REALLOC_N(d->keys, VALUE, d->klen);
29
+ OJ_R_REALLOC_N(d->keys, VALUE, d->klen);
38
30
  d->tail = d->keys + off;
39
31
  }
40
32
  *d->tail = key;
@@ -45,32 +37,56 @@ static void noop(ojParser p) {
45
37
  }
46
38
 
47
39
  static void open_object(ojParser p) {
48
- rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
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));
49
45
  }
50
46
 
51
47
  static void open_object_key(ojParser p) {
52
- Delegate d = (Delegate)p->ctx;
48
+ Saj d = (Saj)p->ctx;
53
49
  volatile VALUE key = get_key(p);
54
50
 
55
51
  push_key(d, key);
56
52
  rb_funcall(d->handler, oj_hash_start_id, 1, key);
57
53
  }
58
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
+
59
63
  static void open_array(ojParser p) {
60
- rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 1, Qnil);
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));
61
69
  }
62
70
 
63
71
  static void open_array_key(ojParser p) {
64
- Delegate d = (Delegate)p->ctx;
72
+ Saj d = (Saj)p->ctx;
65
73
  volatile VALUE key = get_key(p);
66
74
 
67
75
  push_key(d, key);
68
76
  rb_funcall(d->handler, oj_array_start_id, 1, key);
69
77
  }
70
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
+
71
87
  static void close_object(ojParser p) {
72
- Delegate d = (Delegate)p->ctx;
73
- VALUE key = Qnil;
88
+ Saj d = (Saj)p->ctx;
89
+ VALUE key = Qnil;
74
90
 
75
91
  if (OBJECT_FUN == p->stack[p->depth]) {
76
92
  d->tail--;
@@ -82,9 +98,23 @@ static void close_object(ojParser p) {
82
98
  rb_funcall(d->handler, oj_hash_end_id, 1, key);
83
99
  }
84
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
+
85
115
  static void close_array(ojParser p) {
86
- Delegate d = (Delegate)p->ctx;
87
- VALUE key = Qnil;
116
+ Saj d = (Saj)p->ctx;
117
+ VALUE key = Qnil;
88
118
 
89
119
  if (OBJECT_FUN == p->stack[p->depth]) {
90
120
  d->tail--;
@@ -96,66 +126,182 @@ static void close_array(ojParser p) {
96
126
  rb_funcall(d->handler, oj_array_end_id, 1, key);
97
127
  }
98
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
+
99
143
  static void add_null(ojParser p) {
100
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
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));
101
149
  }
102
150
 
103
151
  static void add_null_key(ojParser p) {
104
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(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));
105
163
  }
106
164
 
107
165
  static void add_true(ojParser p) {
108
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
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));
109
171
  }
110
172
 
111
173
  static void add_true_key(ojParser p) {
112
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(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));
113
185
  }
114
186
 
115
187
  static void add_false(ojParser p) {
116
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
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));
117
193
  }
118
194
 
119
195
  static void add_false_key(ojParser p) {
120
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(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));
121
207
  }
122
208
 
123
209
  static void add_int(ojParser p) {
124
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
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));
125
221
  }
126
222
 
127
223
  static void add_int_key(ojParser p) {
128
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(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));
129
235
  }
130
236
 
131
237
  static void add_float(ojParser p) {
132
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
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));
133
249
  }
134
250
 
135
251
  static void add_float_key(ojParser p) {
136
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(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));
137
263
  }
138
264
 
139
265
  static void add_big(ojParser p) {
140
- rb_funcall((VALUE)p->ctx,
266
+ rb_funcall(((Saj)p->ctx)->handler,
141
267
  oj_add_value_id,
142
268
  2,
143
269
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
144
270
  Qnil);
145
271
  }
146
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
+
147
283
  static void add_big_key(ojParser p) {
148
- rb_funcall((VALUE)p->ctx,
284
+ rb_funcall(((Saj)p->ctx)->handler,
149
285
  oj_add_value_id,
150
286
  2,
151
287
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
152
288
  get_key(p));
153
289
  }
154
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
+
155
301
  static void add_str(ojParser p) {
156
- Delegate d = (Delegate)p->ctx;
302
+ Saj d = (Saj)p->ctx;
157
303
  volatile VALUE rstr;
158
- const char * str = buf_str(&p->buf);
304
+ const char *str = buf_str(&p->buf);
159
305
  size_t len = buf_len(&p->buf);
160
306
 
161
307
  if (d->cache_str < len) {
@@ -166,10 +312,24 @@ static void add_str(ojParser p) {
166
312
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
167
313
  }
168
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
+
169
329
  static void add_str_key(ojParser p) {
170
- Delegate d = (Delegate)p->ctx;
330
+ Saj d = (Saj)p->ctx;
171
331
  volatile VALUE rstr;
172
- const char * str = buf_str(&p->buf);
332
+ const char *str = buf_str(&p->buf);
173
333
  size_t len = buf_len(&p->buf);
174
334
 
175
335
  if (d->cache_str < len) {
@@ -180,6 +340,20 @@ static void add_str_key(ojParser p) {
180
340
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
181
341
  }
182
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
+
183
357
  static void reset(ojParser p) {
184
358
  Funcs end = p->funcs + 3;
185
359
  Funcs f;
@@ -200,7 +374,7 @@ static void reset(ojParser p) {
200
374
  }
201
375
 
202
376
  static VALUE option(ojParser p, const char *key, VALUE value) {
203
- Delegate d = (Delegate)p->ctx;
377
+ Saj d = (Saj)p->ctx;
204
378
 
205
379
  if (0 == strcmp(key, "handler")) {
206
380
  return d->handler;
@@ -210,53 +384,107 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
210
384
  d->handler = value;
211
385
  reset(p);
212
386
  if (rb_respond_to(value, oj_hash_start_id)) {
213
- p->funcs[TOP_FUN].open_object = open_object;
214
- p->funcs[ARRAY_FUN].open_object = open_object;
215
- p->funcs[OBJECT_FUN].open_object = open_object_key;
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
+ }
216
396
  }
217
397
  if (rb_respond_to(value, oj_array_start_id)) {
218
- p->funcs[TOP_FUN].open_array = open_array;
219
- p->funcs[ARRAY_FUN].open_array = open_array;
220
- p->funcs[OBJECT_FUN].open_array = open_array_key;
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
+ }
221
407
  }
222
408
  if (rb_respond_to(value, oj_hash_end_id)) {
223
- p->funcs[TOP_FUN].close_object = close_object;
224
- p->funcs[ARRAY_FUN].close_object = close_object;
225
- p->funcs[OBJECT_FUN].close_object = close_object;
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
+ }
226
418
  }
227
419
  if (rb_respond_to(value, oj_array_end_id)) {
228
- p->funcs[TOP_FUN].close_array = close_array;
229
- p->funcs[ARRAY_FUN].close_array = close_array;
230
- p->funcs[OBJECT_FUN].close_array = close_array;
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
+ }
231
429
  }
232
430
  if (rb_respond_to(value, oj_add_value_id)) {
233
- p->funcs[TOP_FUN].add_null = add_null;
234
- p->funcs[ARRAY_FUN].add_null = add_null;
235
- p->funcs[OBJECT_FUN].add_null = add_null_key;
236
-
237
- p->funcs[TOP_FUN].add_true = add_true;
238
- p->funcs[ARRAY_FUN].add_true = add_true;
239
- p->funcs[OBJECT_FUN].add_true = add_true_key;
240
-
241
- p->funcs[TOP_FUN].add_false = add_false;
242
- p->funcs[ARRAY_FUN].add_false = add_false;
243
- p->funcs[OBJECT_FUN].add_false = add_false_key;
244
-
245
- p->funcs[TOP_FUN].add_int = add_int;
246
- p->funcs[ARRAY_FUN].add_int = add_int;
247
- p->funcs[OBJECT_FUN].add_int = add_int_key;
248
-
249
- p->funcs[TOP_FUN].add_float = add_float;
250
- p->funcs[ARRAY_FUN].add_float = add_float;
251
- p->funcs[OBJECT_FUN].add_float = add_float_key;
252
-
253
- p->funcs[TOP_FUN].add_big = add_big;
254
- p->funcs[ARRAY_FUN].add_big = add_big;
255
- p->funcs[OBJECT_FUN].add_big = add_big_key;
256
-
257
- p->funcs[TOP_FUN].add_str = add_str;
258
- p->funcs[ARRAY_FUN].add_str = add_str;
259
- p->funcs[OBJECT_FUN].add_str = add_str_key;
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
+ }
260
488
  }
261
489
  return Qnil;
262
490
  }
@@ -283,7 +511,7 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
283
511
 
284
512
  return INT2NUM((int)d->cache_str);
285
513
  }
286
- rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) delegate", key);
514
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) saj", key);
287
515
 
288
516
  return Qnil; // Never reached due to the raise but required by the compiler.
289
517
  }
@@ -293,26 +521,26 @@ static VALUE result(ojParser p) {
293
521
  }
294
522
 
295
523
  static void start(ojParser p) {
296
- Delegate d = (Delegate)p->ctx;
524
+ Saj d = (Saj)p->ctx;
297
525
 
298
526
  d->tail = d->keys;
299
527
  }
300
528
 
301
529
  static void dfree(ojParser p) {
302
- Delegate d = (Delegate)p->ctx;
530
+ Saj d = (Saj)p->ctx;
303
531
 
304
532
  if (NULL != d->keys) {
305
- xfree(d->keys);
533
+ OJ_R_FREE(d->keys);
306
534
  }
307
535
  cache_free(d->str_cache);
308
- xfree(p->ctx);
536
+ OJ_R_FREE(p->ctx);
309
537
  }
310
538
 
311
539
  static void mark(ojParser p) {
312
- if (NULL == p->ctx) {
540
+ if (NULL == p || NULL == p->ctx) {
313
541
  return;
314
542
  }
315
- Delegate d = (Delegate)p->ctx;
543
+ Saj d = (Saj)p->ctx;
316
544
  VALUE *kp;
317
545
 
318
546
  cache_mark(d->str_cache);
@@ -330,13 +558,15 @@ static VALUE form_str(const char *str, size_t len) {
330
558
  return rb_str_freeze(rb_utf8_str_new(str, len));
331
559
  }
332
560
 
333
- void oj_set_parser_saj(ojParser p) {
334
- Delegate d = ALLOC(struct _delegate);
335
-
336
- d->klen = 256;
337
- d->keys = ALLOC_N(VALUE, d->klen);
338
- d->tail = d->keys;
339
- d->str_cache = cache_create(0, form_str, true, false);
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;
340
570
 
341
571
  p->ctx = (void *)d;
342
572
  reset(p);
@@ -346,3 +576,9 @@ void oj_set_parser_saj(ojParser p) {
346
576
  p->mark = mark;
347
577
  p->start = start;
348
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
@@ -33,8 +33,7 @@ static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
33
33
  return Qundef;
34
34
  }
35
35
 
36
- static void
37
- 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) {
38
37
  }
39
38
 
40
39
  static void noop_hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
@@ -91,12 +90,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
91
90
  volatile VALUE rstr = rb_str_new(str, len);
92
91
 
93
92
  rstr = oj_encode(rstr);
94
- rb_funcall(pi->handler,
95
- oj_hash_set_id,
96
- 3,
97
- stack_peek(&pi->stack)->val,
98
- oj_calc_hash_key(pi, kval),
99
- rstr);
93
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, kval), rstr);
100
94
  }
101
95
 
102
96
  static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
@@ -109,12 +103,7 @@ static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
109
103
  }
110
104
 
111
105
  static void hash_set_value(ParseInfo pi, Val kval, VALUE value) {
112
- rb_funcall(pi->handler,
113
- oj_hash_set_id,
114
- 3,
115
- stack_peek(&pi->stack)->val,
116
- oj_calc_hash_key(pi, kval),
117
- value);
106
+ rb_funcall(pi->handler, oj_hash_set_id, 3, stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, kval), value);
118
107
  }
119
108
 
120
109
  static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {