oj 3.13.14 → 3.13.22

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/compat.c +10 -10
  6. data/ext/oj/custom.c +34 -53
  7. data/ext/oj/dump.c +24 -13
  8. data/ext/oj/dump_compat.c +5 -10
  9. data/ext/oj/dump_object.c +5 -60
  10. data/ext/oj/dump_strict.c +5 -5
  11. data/ext/oj/extconf.rb +5 -4
  12. data/ext/oj/fast.c +15 -13
  13. data/ext/oj/intern.c +6 -9
  14. data/ext/oj/introspect.c +96 -0
  15. data/ext/oj/mimic_json.c +18 -8
  16. data/ext/oj/object.c +42 -41
  17. data/ext/oj/oj.c +27 -4
  18. data/ext/oj/oj.h +4 -1
  19. data/ext/oj/parse.c +111 -76
  20. data/ext/oj/parse.h +2 -0
  21. data/ext/oj/parser.c +61 -4
  22. data/ext/oj/parser.h +12 -0
  23. data/ext/oj/rails.c +5 -10
  24. data/ext/oj/saj2.c +333 -85
  25. data/ext/oj/saj2.h +23 -0
  26. data/ext/oj/sparse.c +4 -0
  27. data/ext/oj/strict.c +13 -13
  28. data/ext/oj/usual.c +82 -129
  29. data/ext/oj/usual.h +68 -0
  30. data/ext/oj/val_stack.c +1 -1
  31. data/ext/oj/validate.c +21 -26
  32. data/ext/oj/wab.c +15 -20
  33. data/lib/oj/saj.rb +20 -6
  34. data/lib/oj/state.rb +1 -1
  35. data/lib/oj/version.rb +1 -1
  36. data/pages/Compatibility.md +1 -1
  37. data/test/bar.rb +3 -1
  38. data/test/helper.rb +8 -2
  39. data/test/json_gem/json_generator_test.rb +3 -4
  40. data/test/json_gem/json_parser_test.rb +8 -1
  41. data/test/json_gem/test_helper.rb +7 -3
  42. data/test/test_compat.rb +25 -0
  43. data/test/test_custom.rb +13 -2
  44. data/test/test_file.rb +23 -7
  45. data/test/test_gc.rb +11 -0
  46. data/test/test_object.rb +3 -10
  47. data/test/test_parser.rb +3 -19
  48. data/test/test_parser_debug.rb +27 -0
  49. data/test/test_parser_saj.rb +92 -2
  50. data/test/test_scp.rb +2 -4
  51. data/test/test_strict.rb +2 -0
  52. data/test/test_various.rb +8 -3
  53. data/test/test_wab.rb +2 -0
  54. data/test/tests.rb +9 -0
  55. data/test/tests_mimic.rb +9 -0
  56. data/test/tests_mimic_addition.rb +9 -0
  57. metadata +7 -107
data/ext/oj/parser.h CHANGED
@@ -80,6 +80,7 @@ typedef struct _ojParser {
80
80
 
81
81
  char token[8];
82
82
  long line;
83
+ long cur; // only set before call to a function
83
84
  long col;
84
85
  int ri;
85
86
  uint32_t ucode;
@@ -87,4 +88,15 @@ typedef struct _ojParser {
87
88
  bool just_one;
88
89
  } * ojParser;
89
90
 
91
+ // Create a new parser without setting the delegate. The parser is
92
+ // wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
93
+ // from this function. A delegate must be added before the parser can be
94
+ // used. Optionally oj_parser_set_options can be called if the options are not
95
+ // set directly.
96
+ extern VALUE oj_parser_new();
97
+
98
+ // Set set the options from a hash (ropts).
99
+ extern void oj_parser_set_option(ojParser p, VALUE ropts);
100
+
101
+
90
102
  #endif /* OJ_PARSER_H */
data/ext/oj/rails.c CHANGED
@@ -320,7 +320,6 @@ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
320
320
  long long sec;
321
321
  long long nsec;
322
322
 
323
- #ifdef HAVE_RB_TIME_TIMESPEC
324
323
  if (16 <= sizeof(struct timespec)) {
325
324
  struct timespec ts = rb_time_timespec(obj);
326
325
 
@@ -330,10 +329,6 @@ static void dump_time(VALUE obj, int depth, Out out, bool as_ok) {
330
329
  sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
331
330
  nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
332
331
  }
333
- #else
334
- sec = NUM2LL(rb_funcall2(obj, oj_tv_sec_id, 0, 0));
335
- nsec = NUM2LL(rb_funcall2(obj, oj_tv_nsec_id, 0, 0));
336
- #endif
337
332
  dump_sec_nano(obj, sec, nsec, out);
338
333
  }
339
334
 
@@ -522,7 +517,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
522
517
  static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
523
518
  volatile VALUE ja;
524
519
 
525
- if (Yes == out->opts->trace) {
520
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
526
521
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
527
522
  }
528
523
  // Some classes elect to not take an options argument so check the arity
@@ -532,7 +527,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
532
527
  } else {
533
528
  ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
534
529
  }
535
- if (Yes == out->opts->trace) {
530
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
536
531
  oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
537
532
  }
538
533
 
@@ -1469,7 +1464,7 @@ static DumpFunc rails_funcs[] = {
1469
1464
  static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1470
1465
  int type = rb_type(obj);
1471
1466
 
1472
- if (Yes == out->opts->trace) {
1467
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1473
1468
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
1474
1469
  }
1475
1470
  if (MAX_DEPTH < depth) {
@@ -1480,14 +1475,14 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
1480
1475
 
1481
1476
  if (NULL != f) {
1482
1477
  f(obj, depth, out, as_ok);
1483
- if (Yes == out->opts->trace) {
1478
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1484
1479
  oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
1485
1480
  }
1486
1481
  return;
1487
1482
  }
1488
1483
  }
1489
1484
  oj_dump_nil(Qnil, depth, out, false);
1490
- if (Yes == out->opts->trace) {
1485
+ if (RB_UNLIKELY(Yes == out->opts->trace)) {
1491
1486
  oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
1492
1487
  }
1493
1488
  }
data/ext/oj/saj2.c CHANGED
@@ -3,21 +3,11 @@
3
3
  #include "cache.h"
4
4
  #include "oj.h"
5
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;
6
+ #include "saj2.h"
17
7
 
18
8
  static VALUE get_key(ojParser p) {
19
- Delegate d = (Delegate)p->ctx;
20
- const char * key = buf_str(&p->key);
9
+ Saj d = (Saj)p->ctx;
10
+ const char *key = buf_str(&p->key);
21
11
  size_t len = buf_len(&p->key);
22
12
  volatile VALUE rkey;
23
13
 
@@ -29,7 +19,7 @@ static VALUE get_key(ojParser p) {
29
19
  return rkey;
30
20
  }
31
21
 
32
- static void push_key(Delegate d, VALUE key) {
22
+ static void push_key(Saj d, VALUE key) {
33
23
  if (d->klen <= (size_t)(d->tail - d->keys)) {
34
24
  size_t off = d->tail - d->keys;
35
25
 
@@ -45,31 +35,55 @@ static void noop(ojParser p) {
45
35
  }
46
36
 
47
37
  static void open_object(ojParser p) {
48
- rb_funcall(((Delegate)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
38
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
39
+ }
40
+
41
+ static void open_object_loc(ojParser p) {
42
+ rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
49
43
  }
50
44
 
51
45
  static void open_object_key(ojParser p) {
52
- Delegate d = (Delegate)p->ctx;
46
+ Saj d = (Saj)p->ctx;
53
47
  volatile VALUE key = get_key(p);
54
48
 
55
49
  push_key(d, key);
56
50
  rb_funcall(d->handler, oj_hash_start_id, 1, key);
57
51
  }
58
52
 
53
+ static void open_object_loc_key(ojParser p) {
54
+ Saj d = (Saj)p->ctx;
55
+ volatile VALUE key = get_key(p);
56
+
57
+ push_key(d, key);
58
+ rb_funcall(d->handler, oj_hash_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
59
+ }
60
+
59
61
  static void open_array(ojParser p) {
60
- rb_funcall(((Delegate)p->ctx)->handler, oj_array_start_id, 1, Qnil);
62
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 1, Qnil);
63
+ }
64
+
65
+ static void open_array_loc(ojParser p) {
66
+ rb_funcall(((Saj)p->ctx)->handler, oj_array_start_id, 3, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
61
67
  }
62
68
 
63
69
  static void open_array_key(ojParser p) {
64
- Delegate d = (Delegate)p->ctx;
70
+ Saj d = (Saj)p->ctx;
65
71
  volatile VALUE key = get_key(p);
66
72
 
67
73
  push_key(d, key);
68
74
  rb_funcall(d->handler, oj_array_start_id, 1, key);
69
75
  }
70
76
 
77
+ static void open_array_loc_key(ojParser p) {
78
+ Saj d = (Saj)p->ctx;
79
+ volatile VALUE key = get_key(p);
80
+
81
+ push_key(d, key);
82
+ rb_funcall(d->handler, oj_array_start_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
83
+ }
84
+
71
85
  static void close_object(ojParser p) {
72
- Delegate d = (Delegate)p->ctx;
86
+ Saj d = (Saj)p->ctx;
73
87
  VALUE key = Qnil;
74
88
 
75
89
  if (OBJECT_FUN == p->stack[p->depth]) {
@@ -82,8 +96,22 @@ static void close_object(ojParser p) {
82
96
  rb_funcall(d->handler, oj_hash_end_id, 1, key);
83
97
  }
84
98
 
99
+ static void close_object_loc(ojParser p) {
100
+ Saj d = (Saj)p->ctx;
101
+ VALUE key = Qnil;
102
+
103
+ if (OBJECT_FUN == p->stack[p->depth]) {
104
+ d->tail--;
105
+ if (d->tail < d->keys) {
106
+ rb_raise(rb_eIndexError, "accessing key stack");
107
+ }
108
+ key = *d->tail;
109
+ }
110
+ rb_funcall(d->handler, oj_hash_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
111
+ }
112
+
85
113
  static void close_array(ojParser p) {
86
- Delegate d = (Delegate)p->ctx;
114
+ Saj d = (Saj)p->ctx;
87
115
  VALUE key = Qnil;
88
116
 
89
117
  if (OBJECT_FUN == p->stack[p->depth]) {
@@ -96,66 +124,200 @@ static void close_array(ojParser p) {
96
124
  rb_funcall(d->handler, oj_array_end_id, 1, key);
97
125
  }
98
126
 
127
+ static void close_array_loc(ojParser p) {
128
+ Saj d = (Saj)p->ctx;
129
+ VALUE key = Qnil;
130
+
131
+ if (OBJECT_FUN == p->stack[p->depth]) {
132
+ d->tail--;
133
+ if (d->tail < d->keys) {
134
+ rb_raise(rb_eIndexError, "accessing key stack");
135
+ }
136
+ key = *d->tail;
137
+ }
138
+ rb_funcall(d->handler, oj_array_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
139
+ }
140
+
99
141
  static void add_null(ojParser p) {
100
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
142
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, Qnil);
143
+ }
144
+
145
+ static void add_null_loc(ojParser p) {
146
+ rb_funcall(((Saj)p->ctx)->handler,
147
+ oj_add_value_id,
148
+ 4,
149
+ Qnil,
150
+ Qnil,
151
+ LONG2FIX(p->line),
152
+ LONG2FIX(p->cur - p->col));
101
153
  }
102
154
 
103
155
  static void add_null_key(ojParser p) {
104
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
156
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qnil, get_key(p));
157
+ }
158
+
159
+ static void add_null_key_loc(ojParser p) {
160
+ rb_funcall(((Saj)p->ctx)->handler,
161
+ oj_add_value_id,
162
+ 4,
163
+ Qnil,
164
+ get_key(p),
165
+ LONG2FIX(p->line),
166
+ LONG2FIX(p->cur - p->col));
105
167
  }
106
168
 
107
169
  static void add_true(ojParser p) {
108
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
170
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, Qnil);
171
+ }
172
+
173
+ static void add_true_loc(ojParser p) {
174
+ rb_funcall(((Saj)p->ctx)->handler,
175
+ oj_add_value_id,
176
+ 4,
177
+ Qtrue,
178
+ Qnil,
179
+ LONG2FIX(p->line),
180
+ LONG2FIX(p->cur - p->col));
109
181
  }
110
182
 
111
183
  static void add_true_key(ojParser p) {
112
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
184
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qtrue, get_key(p));
185
+ }
186
+
187
+ static void add_true_key_loc(ojParser p) {
188
+ rb_funcall(((Saj)p->ctx)->handler,
189
+ oj_add_value_id,
190
+ 4,
191
+ Qtrue,
192
+ get_key(p),
193
+ LONG2FIX(p->line),
194
+ LONG2FIX(p->cur - p->col));
113
195
  }
114
196
 
115
197
  static void add_false(ojParser p) {
116
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
198
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, Qnil);
199
+ }
200
+
201
+ static void add_false_loc(ojParser p) {
202
+ rb_funcall(((Saj)p->ctx)->handler,
203
+ oj_add_value_id,
204
+ 4,
205
+ Qfalse,
206
+ Qnil,
207
+ LONG2FIX(p->line),
208
+ LONG2FIX(p->cur - p->col));
117
209
  }
118
210
 
119
211
  static void add_false_key(ojParser p) {
120
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
212
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, Qfalse, get_key(p));
213
+ }
214
+
215
+ static void add_false_key_loc(ojParser p) {
216
+ rb_funcall(((Saj)p->ctx)->handler,
217
+ oj_add_value_id,
218
+ 4,
219
+ Qfalse,
220
+ get_key(p),
221
+ LONG2FIX(p->line),
222
+ LONG2FIX(p->cur - p->col));
121
223
  }
122
224
 
123
225
  static void add_int(ojParser p) {
124
- rb_funcall(((Delegate)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
226
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), Qnil);
227
+ }
228
+
229
+ static void add_int_loc(ojParser p) {
230
+ rb_funcall(((Saj)p->ctx)->handler,
231
+ oj_add_value_id,
232
+ 4,
233
+ LONG2NUM(p->num.fixnum),
234
+ Qnil,
235
+ LONG2FIX(p->line),
236
+ LONG2FIX(p->cur - p->col));
125
237
  }
126
238
 
127
239
  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));
240
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, LONG2NUM(p->num.fixnum), get_key(p));
241
+ }
242
+
243
+ static void add_int_key_loc(ojParser p) {
244
+ rb_funcall(((Saj)p->ctx)->handler,
245
+ oj_add_value_id,
246
+ 4,
247
+ LONG2NUM(p->num.fixnum),
248
+ get_key(p),
249
+ LONG2FIX(p->line),
250
+ LONG2FIX(p->cur - p->col));
129
251
  }
130
252
 
131
253
  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);
254
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), Qnil);
255
+ }
256
+
257
+ static void add_float_loc(ojParser p) {
258
+ rb_funcall(((Saj)p->ctx)->handler,
259
+ oj_add_value_id,
260
+ 4,
261
+ rb_float_new(p->num.dub),
262
+ Qnil,
263
+ LONG2FIX(p->line),
264
+ LONG2FIX(p->cur - p->col));
133
265
  }
134
266
 
135
267
  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));
268
+ rb_funcall(((Saj)p->ctx)->handler, oj_add_value_id, 2, rb_float_new(p->num.dub), get_key(p));
269
+ }
270
+
271
+ static void add_float_key_loc(ojParser p) {
272
+ rb_funcall(((Saj)p->ctx)->handler,
273
+ oj_add_value_id,
274
+ 4,
275
+ rb_float_new(p->num.dub),
276
+ get_key(p),
277
+ LONG2FIX(p->line),
278
+ LONG2FIX(p->cur - p->col));
137
279
  }
138
280
 
139
281
  static void add_big(ojParser p) {
140
- rb_funcall((VALUE)p->ctx,
282
+ rb_funcall(((Saj)p->ctx)->handler,
141
283
  oj_add_value_id,
142
284
  2,
143
285
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
144
286
  Qnil);
145
287
  }
146
288
 
289
+ static void add_big_loc(ojParser p) {
290
+ rb_funcall(((Saj)p->ctx)->handler,
291
+ oj_add_value_id,
292
+ 4,
293
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
294
+ Qnil,
295
+ LONG2FIX(p->line),
296
+ LONG2FIX(p->cur - p->col));
297
+ }
298
+
147
299
  static void add_big_key(ojParser p) {
148
- rb_funcall((VALUE)p->ctx,
300
+ rb_funcall(((Saj)p->ctx)->handler,
149
301
  oj_add_value_id,
150
302
  2,
151
303
  rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
152
304
  get_key(p));
153
305
  }
154
306
 
307
+ static void add_big_key_loc(ojParser p) {
308
+ rb_funcall(((Saj)p->ctx)->handler,
309
+ oj_add_value_id,
310
+ 4,
311
+ rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
312
+ get_key(p),
313
+ LONG2FIX(p->line),
314
+ LONG2FIX(p->cur - p->col));
315
+ }
316
+
155
317
  static void add_str(ojParser p) {
156
- Delegate d = (Delegate)p->ctx;
318
+ Saj d = (Saj)p->ctx;
157
319
  volatile VALUE rstr;
158
- const char * str = buf_str(&p->buf);
320
+ const char *str = buf_str(&p->buf);
159
321
  size_t len = buf_len(&p->buf);
160
322
 
161
323
  if (d->cache_str < len) {
@@ -166,10 +328,24 @@ static void add_str(ojParser p) {
166
328
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, Qnil);
167
329
  }
168
330
 
331
+ static void add_str_loc(ojParser p) {
332
+ Saj d = (Saj)p->ctx;
333
+ volatile VALUE rstr;
334
+ const char *str = buf_str(&p->buf);
335
+ size_t len = buf_len(&p->buf);
336
+
337
+ if (d->cache_str < len) {
338
+ rstr = cache_intern(d->str_cache, str, len);
339
+ } else {
340
+ rstr = rb_utf8_str_new(str, len);
341
+ }
342
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, Qnil, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
343
+ }
344
+
169
345
  static void add_str_key(ojParser p) {
170
- Delegate d = (Delegate)p->ctx;
346
+ Saj d = (Saj)p->ctx;
171
347
  volatile VALUE rstr;
172
- const char * str = buf_str(&p->buf);
348
+ const char *str = buf_str(&p->buf);
173
349
  size_t len = buf_len(&p->buf);
174
350
 
175
351
  if (d->cache_str < len) {
@@ -180,6 +356,20 @@ static void add_str_key(ojParser p) {
180
356
  rb_funcall(d->handler, oj_add_value_id, 2, rstr, get_key(p));
181
357
  }
182
358
 
359
+ static void add_str_key_loc(ojParser p) {
360
+ Saj d = (Saj)p->ctx;
361
+ volatile VALUE rstr;
362
+ const char *str = buf_str(&p->buf);
363
+ size_t len = buf_len(&p->buf);
364
+
365
+ if (d->cache_str < len) {
366
+ rstr = cache_intern(d->str_cache, str, len);
367
+ } else {
368
+ rstr = rb_utf8_str_new(str, len);
369
+ }
370
+ rb_funcall(d->handler, oj_add_value_id, 4, rstr, get_key(p), LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
371
+ }
372
+
183
373
  static void reset(ojParser p) {
184
374
  Funcs end = p->funcs + 3;
185
375
  Funcs f;
@@ -200,7 +390,7 @@ static void reset(ojParser p) {
200
390
  }
201
391
 
202
392
  static VALUE option(ojParser p, const char *key, VALUE value) {
203
- Delegate d = (Delegate)p->ctx;
393
+ Saj d = (Saj)p->ctx;
204
394
 
205
395
  if (0 == strcmp(key, "handler")) {
206
396
  return d->handler;
@@ -210,53 +400,107 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
210
400
  d->handler = value;
211
401
  reset(p);
212
402
  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;
403
+ if (1 == rb_obj_method_arity(value, oj_hash_start_id)) {
404
+ p->funcs[TOP_FUN].open_object = open_object;
405
+ p->funcs[ARRAY_FUN].open_object = open_object;
406
+ p->funcs[OBJECT_FUN].open_object = open_object_key;
407
+ } else {
408
+ p->funcs[TOP_FUN].open_object = open_object_loc;
409
+ p->funcs[ARRAY_FUN].open_object = open_object_loc;
410
+ p->funcs[OBJECT_FUN].open_object = open_object_loc_key;
411
+ }
216
412
  }
217
413
  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;
414
+ if (1 == rb_obj_method_arity(value, oj_array_start_id)) {
415
+ p->funcs[TOP_FUN].open_array = open_array;
416
+ p->funcs[ARRAY_FUN].open_array = open_array;
417
+ p->funcs[OBJECT_FUN].open_array = open_array_key;
418
+ } else {
419
+ p->funcs[TOP_FUN].open_array = open_array_loc;
420
+ p->funcs[ARRAY_FUN].open_array = open_array_loc;
421
+ p->funcs[OBJECT_FUN].open_array = open_array_loc_key;
422
+ }
221
423
  }
222
424
  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;
425
+ if (1 == rb_obj_method_arity(value, oj_hash_end_id)) {
426
+ p->funcs[TOP_FUN].close_object = close_object;
427
+ p->funcs[ARRAY_FUN].close_object = close_object;
428
+ p->funcs[OBJECT_FUN].close_object = close_object;
429
+ } else {
430
+ p->funcs[TOP_FUN].close_object = close_object_loc;
431
+ p->funcs[ARRAY_FUN].close_object = close_object_loc;
432
+ p->funcs[OBJECT_FUN].close_object = close_object_loc;
433
+ }
226
434
  }
227
435
  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;
436
+ if (1 == rb_obj_method_arity(value, oj_array_end_id)) {
437
+ p->funcs[TOP_FUN].close_array = close_array;
438
+ p->funcs[ARRAY_FUN].close_array = close_array;
439
+ p->funcs[OBJECT_FUN].close_array = close_array;
440
+ } else {
441
+ p->funcs[TOP_FUN].close_array = close_array_loc;
442
+ p->funcs[ARRAY_FUN].close_array = close_array_loc;
443
+ p->funcs[OBJECT_FUN].close_array = close_array_loc;
444
+ }
231
445
  }
232
446
  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;
447
+ if (2 == rb_obj_method_arity(value, oj_add_value_id)) {
448
+ p->funcs[TOP_FUN].add_null = add_null;
449
+ p->funcs[ARRAY_FUN].add_null = add_null;
450
+ p->funcs[OBJECT_FUN].add_null = add_null_key;
451
+
452
+ p->funcs[TOP_FUN].add_true = add_true;
453
+ p->funcs[ARRAY_FUN].add_true = add_true;
454
+ p->funcs[OBJECT_FUN].add_true = add_true_key;
455
+
456
+ p->funcs[TOP_FUN].add_false = add_false;
457
+ p->funcs[ARRAY_FUN].add_false = add_false;
458
+ p->funcs[OBJECT_FUN].add_false = add_false_key;
459
+
460
+ p->funcs[TOP_FUN].add_int = add_int;
461
+ p->funcs[ARRAY_FUN].add_int = add_int;
462
+ p->funcs[OBJECT_FUN].add_int = add_int_key;
463
+
464
+ p->funcs[TOP_FUN].add_float = add_float;
465
+ p->funcs[ARRAY_FUN].add_float = add_float;
466
+ p->funcs[OBJECT_FUN].add_float = add_float_key;
467
+
468
+ p->funcs[TOP_FUN].add_big = add_big;
469
+ p->funcs[ARRAY_FUN].add_big = add_big;
470
+ p->funcs[OBJECT_FUN].add_big = add_big_key;
471
+
472
+ p->funcs[TOP_FUN].add_str = add_str;
473
+ p->funcs[ARRAY_FUN].add_str = add_str;
474
+ p->funcs[OBJECT_FUN].add_str = add_str_key;
475
+ } else {
476
+ p->funcs[TOP_FUN].add_null = add_null_loc;
477
+ p->funcs[ARRAY_FUN].add_null = add_null_loc;
478
+ p->funcs[OBJECT_FUN].add_null = add_null_key_loc;
479
+
480
+ p->funcs[TOP_FUN].add_true = add_true_loc;
481
+ p->funcs[ARRAY_FUN].add_true = add_true_loc;
482
+ p->funcs[OBJECT_FUN].add_true = add_true_key_loc;
483
+
484
+ p->funcs[TOP_FUN].add_false = add_false_loc;
485
+ p->funcs[ARRAY_FUN].add_false = add_false_loc;
486
+ p->funcs[OBJECT_FUN].add_false = add_false_key_loc;
487
+
488
+ p->funcs[TOP_FUN].add_int = add_int_loc;
489
+ p->funcs[ARRAY_FUN].add_int = add_int_loc;
490
+ p->funcs[OBJECT_FUN].add_int = add_int_key_loc;
491
+
492
+ p->funcs[TOP_FUN].add_float = add_float_loc;
493
+ p->funcs[ARRAY_FUN].add_float = add_float_loc;
494
+ p->funcs[OBJECT_FUN].add_float = add_float_key_loc;
495
+
496
+ p->funcs[TOP_FUN].add_big = add_big_loc;
497
+ p->funcs[ARRAY_FUN].add_big = add_big_loc;
498
+ p->funcs[OBJECT_FUN].add_big = add_big_key_loc;
499
+
500
+ p->funcs[TOP_FUN].add_str = add_str_loc;
501
+ p->funcs[ARRAY_FUN].add_str = add_str_loc;
502
+ p->funcs[OBJECT_FUN].add_str = add_str_key_loc;
503
+ }
260
504
  }
261
505
  return Qnil;
262
506
  }
@@ -283,7 +527,7 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
283
527
 
284
528
  return INT2NUM((int)d->cache_str);
285
529
  }
286
- rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) delegate", key);
530
+ rb_raise(rb_eArgError, "%s is not an option for the SAJ (Simple API for JSON) saj", key);
287
531
 
288
532
  return Qnil; // Never reached due to the raise but required by the compiler.
289
533
  }
@@ -293,13 +537,13 @@ static VALUE result(ojParser p) {
293
537
  }
294
538
 
295
539
  static void start(ojParser p) {
296
- Delegate d = (Delegate)p->ctx;
540
+ Saj d = (Saj)p->ctx;
297
541
 
298
542
  d->tail = d->keys;
299
543
  }
300
544
 
301
545
  static void dfree(ojParser p) {
302
- Delegate d = (Delegate)p->ctx;
546
+ Saj d = (Saj)p->ctx;
303
547
 
304
548
  if (NULL != d->keys) {
305
549
  xfree(d->keys);
@@ -309,11 +553,11 @@ static void dfree(ojParser p) {
309
553
  }
310
554
 
311
555
  static void mark(ojParser p) {
312
- if (NULL == p->ctx) {
556
+ if (NULL == p || NULL == p->ctx) {
313
557
  return;
314
558
  }
315
- Delegate d = (Delegate)p->ctx;
316
- VALUE *kp;
559
+ Saj d = (Saj)p->ctx;
560
+ VALUE *kp;
317
561
 
318
562
  cache_mark(d->str_cache);
319
563
  if (Qnil != d->handler) {
@@ -330,9 +574,7 @@ static VALUE form_str(const char *str, size_t len) {
330
574
  return rb_str_freeze(rb_utf8_str_new(str, len));
331
575
  }
332
576
 
333
- void oj_set_parser_saj(ojParser p) {
334
- Delegate d = ALLOC(struct _delegate);
335
-
577
+ void oj_init_saj(ojParser p, Saj d) {
336
578
  d->klen = 256;
337
579
  d->keys = ALLOC_N(VALUE, d->klen);
338
580
  d->tail = d->keys;
@@ -346,3 +588,9 @@ void oj_set_parser_saj(ojParser p) {
346
588
  p->mark = mark;
347
589
  p->start = start;
348
590
  }
591
+
592
+ void oj_set_parser_saj(ojParser p) {
593
+ Saj d = ALLOC(struct _saj);
594
+
595
+ oj_init_saj(p, d);
596
+ }