oj 3.13.11 → 3.13.23
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +2 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/circarray.c +1 -1
- data/ext/oj/code.c +15 -22
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +62 -108
- data/ext/oj/dump.c +85 -97
- data/ext/oj/dump.h +12 -8
- data/ext/oj/dump_compat.c +46 -88
- data/ext/oj/dump_leaf.c +14 -58
- data/ext/oj/dump_object.c +33 -156
- data/ext/oj/dump_strict.c +17 -29
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +24 -22
- data/ext/oj/intern.c +15 -11
- data/ext/oj/intern.h +1 -1
- data/ext/oj/mimic_json.c +44 -32
- data/ext/oj/object.c +42 -41
- data/ext/oj/odd.c +83 -63
- data/ext/oj/odd.h +13 -13
- data/ext/oj/oj.c +57 -22
- data/ext/oj/oj.h +24 -3
- data/ext/oj/parse.c +114 -78
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +77 -21
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +41 -65
- data/ext/oj/rails.h +1 -1
- data/ext/oj/reader.c +2 -0
- data/ext/oj/saj.c +11 -23
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/stream_writer.c +3 -1
- data/ext/oj/strict.c +13 -13
- data/ext/oj/string_writer.c +12 -5
- data/ext/oj/usual.c +82 -129
- data/ext/oj/usual.h +68 -0
- data/ext/oj/val_stack.c +1 -1
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +21 -26
- data/lib/oj/saj.rb +20 -6
- data/lib/oj/state.rb +1 -1
- data/lib/oj/version.rb +1 -1
- data/pages/Compatibility.md +1 -1
- data/pages/Options.md +6 -0
- data/test/activesupport7/abstract_unit.rb +49 -0
- data/test/activesupport7/decoding_test.rb +125 -0
- data/test/activesupport7/encoding_test.rb +486 -0
- data/test/activesupport7/encoding_test_cases.rb +104 -0
- data/test/activesupport7/time_zone_test_helpers.rb +47 -0
- data/test/bar.rb +3 -8
- data/test/foo.rb +3 -3
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +5 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- data/test/perf_dump.rb +50 -0
- data/test/test_compat.rb +25 -0
- data/test/test_custom.rb +13 -2
- data/test/test_file.rb +23 -7
- data/test/test_gc.rb +11 -0
- data/test/test_object.rb +8 -10
- data/test/test_parser.rb +3 -19
- data/test/test_parser_debug.rb +27 -0
- data/test/test_parser_saj.rb +92 -2
- data/test/test_scp.rb +2 -4
- data/test/test_strict.rb +2 -0
- data/test/test_various.rb +8 -3
- data/test/test_wab.rb +2 -0
- data/test/tests.rb +9 -0
- data/test/tests_mimic.rb +9 -0
- data/test/tests_mimic_addition.rb +9 -0
- metadata +13 -116
data/ext/oj/parse.c
CHANGED
@@ -183,6 +183,42 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
187
|
+
for (; '"' != *str; str++) {
|
188
|
+
if (end <= str || '\0' == *str || '\\' == *str) {
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
return str;
|
193
|
+
}
|
194
|
+
|
195
|
+
#ifdef OJ_USE_SSE4_2
|
196
|
+
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
197
|
+
static const char chars[16] = "\x00\\\"";
|
198
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
199
|
+
const char *_end = (const char *)(end - 16);
|
200
|
+
|
201
|
+
for (; str <= _end; str += 16) {
|
202
|
+
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
203
|
+
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
204
|
+
if (r != 16) {
|
205
|
+
str = (char*)(str + r);
|
206
|
+
return str;
|
207
|
+
}
|
208
|
+
}
|
209
|
+
|
210
|
+
return scan_string_noSIMD(str, end);
|
211
|
+
}
|
212
|
+
#endif
|
213
|
+
|
214
|
+
static const char *(*scan_func) (const char *str, const char *end) = scan_string_noSIMD;
|
215
|
+
|
216
|
+
void oj_scanner_init(void) {
|
217
|
+
#ifdef OJ_USE_SSE4_2
|
218
|
+
scan_func = scan_string_SIMD;
|
219
|
+
#endif
|
220
|
+
}
|
221
|
+
|
186
222
|
// entered at /
|
187
223
|
static void read_escaped_str(ParseInfo pi, const char *start) {
|
188
224
|
struct _buf buf;
|
@@ -192,11 +228,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
192
228
|
Val parent = stack_peek(&pi->stack);
|
193
229
|
|
194
230
|
buf_init(&buf);
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
if (
|
231
|
+
buf_append_string(&buf, start, cnt);
|
232
|
+
|
233
|
+
for (s = pi->cur; '"' != *s;) {
|
234
|
+
const char *scanned = scan_func(s, pi->end);
|
235
|
+
if (scanned >= pi->end) {
|
200
236
|
oj_set_error_at(pi,
|
201
237
|
oj_parse_error_class,
|
202
238
|
__FILE__,
|
@@ -204,7 +240,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
204
240
|
"quoted string not terminated");
|
205
241
|
buf_cleanup(&buf);
|
206
242
|
return;
|
207
|
-
}
|
243
|
+
}
|
244
|
+
|
245
|
+
buf_append_string(&buf, s, (size_t)(scanned - s));
|
246
|
+
s = scanned;
|
247
|
+
|
248
|
+
if ('\\' == *s) {
|
208
249
|
s++;
|
209
250
|
switch (*s) {
|
210
251
|
case 'n': buf_append(&buf, '\n'); break;
|
@@ -273,8 +314,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
273
314
|
buf_cleanup(&buf);
|
274
315
|
return;
|
275
316
|
}
|
276
|
-
|
277
|
-
buf_append(&buf, *s);
|
317
|
+
s++;
|
278
318
|
}
|
279
319
|
}
|
280
320
|
if (0 == parent) {
|
@@ -331,22 +371,24 @@ static void read_str(ParseInfo pi) {
|
|
331
371
|
const char *str = pi->cur;
|
332
372
|
Val parent = stack_peek(&pi->stack);
|
333
373
|
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
} else if ('\0' == *pi->cur) {
|
343
|
-
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
344
|
-
return;
|
345
|
-
} else if ('\\' == *pi->cur) {
|
346
|
-
read_escaped_str(pi, str);
|
347
|
-
return;
|
348
|
-
}
|
374
|
+
pi->cur = scan_func(pi->cur, pi->end);
|
375
|
+
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
376
|
+
oj_set_error_at(pi,
|
377
|
+
oj_parse_error_class,
|
378
|
+
__FILE__,
|
379
|
+
__LINE__,
|
380
|
+
"quoted string not terminated");
|
381
|
+
return;
|
349
382
|
}
|
383
|
+
if (RB_UNLIKELY('\0' == *pi->cur)) {
|
384
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "NULL byte in string");
|
385
|
+
return;
|
386
|
+
}
|
387
|
+
if ('\\' == *pi->cur) {
|
388
|
+
read_escaped_str(pi, str);
|
389
|
+
return;
|
390
|
+
}
|
391
|
+
|
350
392
|
if (0 == parent) { // simple add
|
351
393
|
pi->add_cstr(pi, str, pi->cur - str, str);
|
352
394
|
} else {
|
@@ -459,33 +501,31 @@ static void read_num(ParseInfo pi) {
|
|
459
501
|
int dec_cnt = 0;
|
460
502
|
bool zero1 = false;
|
461
503
|
|
504
|
+
// Skip leading zeros.
|
505
|
+
for (; '0' == *pi->cur; pi->cur++) {
|
506
|
+
zero1 = true;
|
507
|
+
}
|
508
|
+
|
462
509
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
463
|
-
|
464
|
-
zero1 = true;
|
465
|
-
}
|
466
|
-
if (0 < ni.i) {
|
467
|
-
dec_cnt++;
|
468
|
-
}
|
469
|
-
if (!ni.big) {
|
470
|
-
int d = (*pi->cur - '0');
|
510
|
+
int d = (*pi->cur - '0');
|
471
511
|
|
472
|
-
|
473
|
-
|
474
|
-
oj_set_error_at(pi,
|
475
|
-
oj_parse_error_class,
|
476
|
-
__FILE__,
|
477
|
-
__LINE__,
|
478
|
-
"not a number");
|
479
|
-
return;
|
480
|
-
}
|
481
|
-
zero1 = false;
|
482
|
-
}
|
483
|
-
ni.i = ni.i * 10 + d;
|
484
|
-
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
485
|
-
ni.big = 1;
|
486
|
-
}
|
512
|
+
if (RB_LIKELY(0 != ni.i)) {
|
513
|
+
dec_cnt++;
|
487
514
|
}
|
515
|
+
ni.i = ni.i * 10 + d;
|
488
516
|
}
|
517
|
+
if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
|
518
|
+
oj_set_error_at(pi,
|
519
|
+
oj_parse_error_class,
|
520
|
+
__FILE__,
|
521
|
+
__LINE__,
|
522
|
+
"not a number");
|
523
|
+
return;
|
524
|
+
}
|
525
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
526
|
+
ni.big = true;
|
527
|
+
}
|
528
|
+
|
489
529
|
if ('.' == *pi->cur) {
|
490
530
|
pi->cur++;
|
491
531
|
// A trailing . is not a valid decimal but if encountered allow it
|
@@ -505,25 +545,20 @@ static void read_num(ParseInfo pi) {
|
|
505
545
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
506
546
|
int d = (*pi->cur - '0');
|
507
547
|
|
508
|
-
if (0
|
548
|
+
if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
|
509
549
|
dec_cnt++;
|
510
550
|
}
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
520
|
-
if (!ni.no_big) {
|
521
|
-
ni.big = true;
|
522
|
-
}
|
523
|
-
}
|
524
|
-
}
|
551
|
+
ni.num = ni.num * 10 + d;
|
552
|
+
ni.div *= 10;
|
553
|
+
ni.di++;
|
554
|
+
}
|
555
|
+
}
|
556
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
557
|
+
if (!ni.no_big) {
|
558
|
+
ni.big = true;
|
525
559
|
}
|
526
560
|
}
|
561
|
+
|
527
562
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
528
563
|
int eneg = 0;
|
529
564
|
|
@@ -596,7 +631,7 @@ static void read_num(ParseInfo pi) {
|
|
596
631
|
}
|
597
632
|
|
598
633
|
static void array_start(ParseInfo pi) {
|
599
|
-
|
634
|
+
VALUE v = pi->start_array(pi);
|
600
635
|
|
601
636
|
stack_push(&pi->stack, v, NEXT_ARRAY_NEW);
|
602
637
|
}
|
@@ -620,13 +655,13 @@ static void array_end(ParseInfo pi) {
|
|
620
655
|
}
|
621
656
|
|
622
657
|
static void hash_start(ParseInfo pi) {
|
623
|
-
|
658
|
+
VALUE v = pi->start_hash(pi);
|
624
659
|
|
625
660
|
stack_push(&pi->stack, v, NEXT_HASH_NEW);
|
626
661
|
}
|
627
662
|
|
628
663
|
static void hash_end(ParseInfo pi) {
|
629
|
-
|
664
|
+
Val hash = stack_peek(&pi->stack);
|
630
665
|
|
631
666
|
// leave hash on stack until just before
|
632
667
|
if (0 == hash) {
|
@@ -813,7 +848,7 @@ static long double exp_plus[] = {
|
|
813
848
|
|
814
849
|
VALUE
|
815
850
|
oj_num_as_value(NumInfo ni) {
|
816
|
-
|
851
|
+
VALUE rnum = Qnil;
|
817
852
|
|
818
853
|
if (ni->infinity) {
|
819
854
|
if (ni->neg) {
|
@@ -848,7 +883,7 @@ oj_num_as_value(NumInfo ni) {
|
|
848
883
|
}
|
849
884
|
} else { // decimal
|
850
885
|
if (ni->big) {
|
851
|
-
|
886
|
+
VALUE bd = rb_str_new(ni->str, ni->len);
|
852
887
|
|
853
888
|
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
854
889
|
if (ni->no_big) {
|
@@ -876,7 +911,7 @@ oj_num_as_value(NumInfo ni) {
|
|
876
911
|
}
|
877
912
|
rnum = rb_float_new((double)ld);
|
878
913
|
} else if (RubyDec == ni->bigdec_load) {
|
879
|
-
|
914
|
+
VALUE sv = rb_str_new(ni->str, ni->len);
|
880
915
|
|
881
916
|
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
882
917
|
} else {
|
@@ -971,10 +1006,11 @@ static VALUE protect_parse(VALUE pip) {
|
|
971
1006
|
|
972
1007
|
extern int oj_utf8_index;
|
973
1008
|
|
974
|
-
static void oj_pi_set_input_str(ParseInfo pi,
|
975
|
-
|
1009
|
+
static void oj_pi_set_input_str(ParseInfo pi, VALUE *inputp) {
|
1010
|
+
int idx = RB_ENCODING_GET(*inputp);
|
976
1011
|
|
977
|
-
if (
|
1012
|
+
if (oj_utf8_encoding_index != idx) {
|
1013
|
+
rb_encoding *enc = rb_enc_from_index(idx);
|
978
1014
|
*inputp = rb_str_conv_enc(*inputp, enc, oj_utf8_encoding);
|
979
1015
|
}
|
980
1016
|
pi->json = RSTRING_PTR(*inputp);
|
@@ -983,12 +1019,12 @@ static void oj_pi_set_input_str(ParseInfo pi, volatile VALUE *inputp) {
|
|
983
1019
|
|
984
1020
|
VALUE
|
985
1021
|
oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yieldOk) {
|
986
|
-
char *
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
int
|
991
|
-
int
|
1022
|
+
char * buf = 0;
|
1023
|
+
VALUE input;
|
1024
|
+
VALUE wrapped_stack;
|
1025
|
+
VALUE result = Qnil;
|
1026
|
+
int line = 0;
|
1027
|
+
int free_json = 0;
|
992
1028
|
|
993
1029
|
if (argc < 1) {
|
994
1030
|
rb_raise(rb_eArgError, "Wrong number of arguments to parse.");
|
@@ -1024,8 +1060,8 @@ oj_pi_parse(int argc, VALUE *argv, ParseInfo pi, char *json, size_t len, int yie
|
|
1024
1060
|
rb_raise(rb_eTypeError, "Nil is not a valid JSON source.");
|
1025
1061
|
}
|
1026
1062
|
} else {
|
1027
|
-
VALUE
|
1028
|
-
|
1063
|
+
VALUE clas = rb_obj_class(input);
|
1064
|
+
VALUE s;
|
1029
1065
|
|
1030
1066
|
if (oj_stringio_class == clas) {
|
1031
1067
|
s = rb_funcall2(input, oj_string_id, 0, 0);
|
data/ext/oj/parse.h
CHANGED
data/ext/oj/parser.c
CHANGED
@@ -11,8 +11,8 @@
|
|
11
11
|
#define USE_THREAD_LIMIT 0
|
12
12
|
// #define USE_THREAD_LIMIT 100000
|
13
13
|
#define MAX_EXP 4932
|
14
|
-
// max in the pow_map
|
15
|
-
#define MAX_POW
|
14
|
+
// max in the pow_map which is the limit for double
|
15
|
+
#define MAX_POW 308
|
16
16
|
|
17
17
|
#define MIN_SLEEP (1000000000LL / (double)CLOCKS_PER_SEC)
|
18
18
|
// 9,223,372,036,854,775,807
|
@@ -385,7 +385,7 @@ static const byte hex_map[256] = "\
|
|
385
385
|
................................\
|
386
386
|
................................";
|
387
387
|
|
388
|
-
static long double pow_map[
|
388
|
+
static long double pow_map[309] = {
|
389
389
|
1.0L, 1.0e1L, 1.0e2L, 1.0e3L, 1.0e4L, 1.0e5L, 1.0e6L, 1.0e7L, 1.0e8L, 1.0e9L, 1.0e10L,
|
390
390
|
1.0e11L, 1.0e12L, 1.0e13L, 1.0e14L, 1.0e15L, 1.0e16L, 1.0e17L, 1.0e18L, 1.0e19L, 1.0e20L, 1.0e21L,
|
391
391
|
1.0e22L, 1.0e23L, 1.0e24L, 1.0e25L, 1.0e26L, 1.0e27L, 1.0e28L, 1.0e29L, 1.0e30L, 1.0e31L, 1.0e32L,
|
@@ -414,15 +414,7 @@ static long double pow_map[401] = {
|
|
414
414
|
1.0e275L, 1.0e276L, 1.0e277L, 1.0e278L, 1.0e279L, 1.0e280L, 1.0e281L, 1.0e282L, 1.0e283L, 1.0e284L, 1.0e285L,
|
415
415
|
1.0e286L, 1.0e287L, 1.0e288L, 1.0e289L, 1.0e290L, 1.0e291L, 1.0e292L, 1.0e293L, 1.0e294L, 1.0e295L, 1.0e296L,
|
416
416
|
1.0e297L, 1.0e298L, 1.0e299L, 1.0e300L, 1.0e301L, 1.0e302L, 1.0e303L, 1.0e304L, 1.0e305L, 1.0e306L, 1.0e307L,
|
417
|
-
1.0e308L
|
418
|
-
1.0e319L, 1.0e320L, 1.0e321L, 1.0e322L, 1.0e323L, 1.0e324L, 1.0e325L, 1.0e326L, 1.0e327L, 1.0e328L, 1.0e329L,
|
419
|
-
1.0e330L, 1.0e331L, 1.0e332L, 1.0e333L, 1.0e334L, 1.0e335L, 1.0e336L, 1.0e337L, 1.0e338L, 1.0e339L, 1.0e340L,
|
420
|
-
1.0e341L, 1.0e342L, 1.0e343L, 1.0e344L, 1.0e345L, 1.0e346L, 1.0e347L, 1.0e348L, 1.0e349L, 1.0e350L, 1.0e351L,
|
421
|
-
1.0e352L, 1.0e353L, 1.0e354L, 1.0e355L, 1.0e356L, 1.0e357L, 1.0e358L, 1.0e359L, 1.0e360L, 1.0e361L, 1.0e362L,
|
422
|
-
1.0e363L, 1.0e364L, 1.0e365L, 1.0e366L, 1.0e367L, 1.0e368L, 1.0e369L, 1.0e370L, 1.0e371L, 1.0e372L, 1.0e373L,
|
423
|
-
1.0e374L, 1.0e375L, 1.0e376L, 1.0e377L, 1.0e378L, 1.0e379L, 1.0e380L, 1.0e381L, 1.0e382L, 1.0e383L, 1.0e384L,
|
424
|
-
1.0e385L, 1.0e386L, 1.0e387L, 1.0e388L, 1.0e389L, 1.0e390L, 1.0e391L, 1.0e392L, 1.0e393L, 1.0e394L, 1.0e395L,
|
425
|
-
1.0e396L, 1.0e397L, 1.0e398L, 1.0e399L, 1.0e400L};
|
417
|
+
1.0e308L};
|
426
418
|
|
427
419
|
static VALUE parser_class;
|
428
420
|
|
@@ -541,6 +533,7 @@ static void calc_num(ojParser p) {
|
|
541
533
|
// nothing to do
|
542
534
|
break;
|
543
535
|
}
|
536
|
+
p->type = OJ_NONE;
|
544
537
|
}
|
545
538
|
|
546
539
|
static void big_change(ojParser p) {
|
@@ -606,6 +599,8 @@ static void parse(ojParser p, const byte *json) {
|
|
606
599
|
const byte *b = json;
|
607
600
|
int i;
|
608
601
|
|
602
|
+
p->line = 1;
|
603
|
+
p->col = -1;
|
609
604
|
#if DEBUG
|
610
605
|
printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
|
611
606
|
#endif
|
@@ -660,6 +655,7 @@ static void parse(ojParser p, const byte *json) {
|
|
660
655
|
}
|
661
656
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
662
657
|
if ('"' == *b) {
|
658
|
+
p->cur = b - json;
|
663
659
|
p->funcs[p->stack[p->depth]].add_str(p);
|
664
660
|
p->map = (0 == p->depth) ? value_map : after_map;
|
665
661
|
break;
|
@@ -669,12 +665,14 @@ static void parse(ojParser p, const byte *json) {
|
|
669
665
|
p->next_map = (0 == p->depth) ? value_map : after_map;
|
670
666
|
break;
|
671
667
|
case OPEN_OBJECT:
|
668
|
+
p->cur = b - json;
|
672
669
|
p->funcs[p->stack[p->depth]].open_object(p);
|
673
670
|
p->depth++;
|
674
671
|
p->stack[p->depth] = OBJECT_FUN;
|
675
672
|
p->map = key1_map;
|
676
673
|
break;
|
677
674
|
case NUM_CLOSE_OBJECT:
|
675
|
+
p->cur = b - json;
|
678
676
|
calc_num(p);
|
679
677
|
// flow through
|
680
678
|
case CLOSE_OBJECT:
|
@@ -685,15 +683,18 @@ static void parse(ojParser p, const byte *json) {
|
|
685
683
|
return;
|
686
684
|
}
|
687
685
|
p->depth--;
|
686
|
+
p->cur = b - json;
|
688
687
|
p->funcs[p->stack[p->depth]].close_object(p);
|
689
688
|
break;
|
690
689
|
case OPEN_ARRAY:
|
690
|
+
p->cur = b - json;
|
691
691
|
p->funcs[p->stack[p->depth]].open_array(p);
|
692
692
|
p->depth++;
|
693
693
|
p->stack[p->depth] = ARRAY_FUN;
|
694
694
|
p->map = value_map;
|
695
695
|
break;
|
696
696
|
case NUM_CLOSE_ARRAY:
|
697
|
+
p->cur = b - json;
|
697
698
|
calc_num(p);
|
698
699
|
// flow through
|
699
700
|
case CLOSE_ARRAY:
|
@@ -704,9 +705,11 @@ static void parse(ojParser p, const byte *json) {
|
|
704
705
|
return;
|
705
706
|
}
|
706
707
|
p->depth--;
|
708
|
+
p->cur = b - json;
|
707
709
|
p->funcs[p->stack[p->depth]].close_array(p);
|
708
710
|
break;
|
709
711
|
case NUM_COMMA:
|
712
|
+
p->cur = b - json;
|
710
713
|
calc_num(p);
|
711
714
|
if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
|
712
715
|
p->map = key_map;
|
@@ -868,8 +871,14 @@ static void parse(ojParser p, const byte *json) {
|
|
868
871
|
b--;
|
869
872
|
p->map = big_exp_map;
|
870
873
|
break;
|
871
|
-
case NUM_SPC:
|
872
|
-
|
874
|
+
case NUM_SPC:
|
875
|
+
p->cur = b - json;
|
876
|
+
calc_num(p);
|
877
|
+
break;
|
878
|
+
case NUM_NEWLINE:
|
879
|
+
p->cur = b - json;
|
880
|
+
calc_num(p);
|
881
|
+
b++;
|
873
882
|
#ifdef SPACE_JUMP
|
874
883
|
// for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
|
875
884
|
for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
|
@@ -890,6 +899,7 @@ static void parse(ojParser p, const byte *json) {
|
|
890
899
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
891
900
|
}
|
892
901
|
if ('"' == *b) {
|
902
|
+
p->cur = b - json;
|
893
903
|
p->funcs[p->stack[p->depth]].add_str(p);
|
894
904
|
p->map = p->next_map;
|
895
905
|
break;
|
@@ -898,6 +908,7 @@ static void parse(ojParser p, const byte *json) {
|
|
898
908
|
break;
|
899
909
|
case STR_SLASH: p->map = esc_map; break;
|
900
910
|
case STR_QUOTE:
|
911
|
+
p->cur = b - json;
|
901
912
|
p->funcs[p->stack[p->depth]].add_str(p);
|
902
913
|
p->map = p->next_map;
|
903
914
|
break;
|
@@ -975,6 +986,7 @@ static void parse(ojParser p, const byte *json) {
|
|
975
986
|
case VAL_NULL:
|
976
987
|
if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
|
977
988
|
b += 3;
|
989
|
+
p->cur = b - json;
|
978
990
|
p->funcs[p->stack[p->depth]].add_null(p);
|
979
991
|
p->map = (0 == p->depth) ? value_map : after_map;
|
980
992
|
break;
|
@@ -1000,6 +1012,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1000
1012
|
case VAL_TRUE:
|
1001
1013
|
if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
|
1002
1014
|
b += 3;
|
1015
|
+
p->cur = b - json;
|
1003
1016
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1004
1017
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1005
1018
|
break;
|
@@ -1025,6 +1038,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1025
1038
|
case VAL_FALSE:
|
1026
1039
|
if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
|
1027
1040
|
b += 4;
|
1041
|
+
p->cur = b - json;
|
1028
1042
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1029
1043
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1030
1044
|
break;
|
@@ -1058,6 +1072,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1058
1072
|
parse_error(p, "expected null");
|
1059
1073
|
return;
|
1060
1074
|
}
|
1075
|
+
p->cur = b - json;
|
1061
1076
|
p->funcs[p->stack[p->depth]].add_null(p);
|
1062
1077
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1063
1078
|
}
|
@@ -1069,6 +1084,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1069
1084
|
parse_error(p, "expected false");
|
1070
1085
|
return;
|
1071
1086
|
}
|
1087
|
+
p->cur = b - json;
|
1072
1088
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1073
1089
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1074
1090
|
}
|
@@ -1080,6 +1096,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1080
1096
|
parse_error(p, "expected true");
|
1081
1097
|
return;
|
1082
1098
|
}
|
1099
|
+
p->cur = b - json;
|
1083
1100
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1084
1101
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1085
1102
|
}
|
@@ -1097,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1097
1114
|
p->map = trail_map;
|
1098
1115
|
}
|
1099
1116
|
}
|
1117
|
+
if (0 < p->depth) {
|
1118
|
+
parse_error(p, "parse error, not closed");
|
1119
|
+
}
|
1100
1120
|
if (0 == p->depth) {
|
1101
1121
|
switch (p->map[256]) {
|
1102
1122
|
case '0':
|
@@ -1107,7 +1127,10 @@ static void parse(ojParser p, const byte *json) {
|
|
1107
1127
|
case 'D':
|
1108
1128
|
case 'g':
|
1109
1129
|
case 'B':
|
1110
|
-
case 'Y':
|
1130
|
+
case 'Y':
|
1131
|
+
p->cur = b - json;
|
1132
|
+
calc_num(p);
|
1133
|
+
break;
|
1111
1134
|
}
|
1112
1135
|
}
|
1113
1136
|
return;
|
@@ -1122,7 +1145,9 @@ static void parser_free(void *ptr) {
|
|
1122
1145
|
p = (ojParser)ptr;
|
1123
1146
|
buf_cleanup(&p->key);
|
1124
1147
|
buf_cleanup(&p->buf);
|
1125
|
-
p->free
|
1148
|
+
if (NULL != p->free) {
|
1149
|
+
p->free(p);
|
1150
|
+
}
|
1126
1151
|
xfree(ptr);
|
1127
1152
|
}
|
1128
1153
|
|
@@ -1133,7 +1158,9 @@ static void parser_mark(void *ptr) {
|
|
1133
1158
|
if (0 != p->reader) {
|
1134
1159
|
rb_gc_mark(p->reader);
|
1135
1160
|
}
|
1136
|
-
p->mark
|
1161
|
+
if (NULL != p->mark) {
|
1162
|
+
p->mark(p);
|
1163
|
+
}
|
1137
1164
|
}
|
1138
1165
|
}
|
1139
1166
|
|
@@ -1190,7 +1217,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1190
1217
|
p->map = value_map;
|
1191
1218
|
|
1192
1219
|
if (argc < 1) {
|
1193
|
-
|
1220
|
+
oj_set_parser_validator(p);
|
1194
1221
|
} else {
|
1195
1222
|
VALUE mode = argv[0];
|
1196
1223
|
|
@@ -1231,6 +1258,32 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1231
1258
|
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1232
1259
|
}
|
1233
1260
|
|
1261
|
+
// Create a new parser without setting the delegate. The parser is
|
1262
|
+
// wrapped. The parser is (ojParser)DATA_PTR(value) where value is the return
|
1263
|
+
// from this function. A delegate must be added before the parser can be
|
1264
|
+
// used. Optionally oj_parser_set_options can be called if the options are not
|
1265
|
+
// set directly.
|
1266
|
+
VALUE oj_parser_new() {
|
1267
|
+
ojParser p = ALLOC(struct _ojParser);
|
1268
|
+
|
1269
|
+
#if HAVE_RB_EXT_RACTOR_SAFE
|
1270
|
+
// This doesn't seem to do anything.
|
1271
|
+
rb_ext_ractor_safe(true);
|
1272
|
+
#endif
|
1273
|
+
memset(p, 0, sizeof(struct _ojParser));
|
1274
|
+
buf_init(&p->key);
|
1275
|
+
buf_init(&p->buf);
|
1276
|
+
p->map = value_map;
|
1277
|
+
|
1278
|
+
return Data_Wrap_Struct(parser_class, parser_mark, parser_free, p);
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
// Set set the options from a hash (ropts).
|
1282
|
+
void oj_parser_set_option(ojParser p, VALUE ropts) {
|
1283
|
+
Check_Type(ropts, T_HASH);
|
1284
|
+
rb_hash_foreach(ropts, opt_cb, (VALUE)p);
|
1285
|
+
}
|
1286
|
+
|
1234
1287
|
/* Document-method: method_missing(value)
|
1235
1288
|
* call-seq: method_missing(value)
|
1236
1289
|
*
|
@@ -1284,7 +1337,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1284
1337
|
*/
|
1285
1338
|
static VALUE parser_missing(int argc, VALUE *argv, VALUE self) {
|
1286
1339
|
ojParser p = (ojParser)DATA_PTR(self);
|
1287
|
-
const char
|
1340
|
+
const char *key = NULL;
|
1288
1341
|
volatile VALUE rkey = *argv;
|
1289
1342
|
volatile VALUE rv = Qnil;
|
1290
1343
|
|
@@ -1464,7 +1517,7 @@ static VALUE saj_parser = Qundef;
|
|
1464
1517
|
/* Document-method: saj
|
1465
1518
|
* call-seq: saj
|
1466
1519
|
*
|
1467
|
-
* Returns the default
|
1520
|
+
* Returns the default SAJ parser. Note the default SAJ parser can not be used
|
1468
1521
|
* concurrently in more than one thread.
|
1469
1522
|
*/
|
1470
1523
|
static VALUE parser_saj(VALUE self) {
|
@@ -1515,8 +1568,11 @@ static VALUE parser_validate(VALUE self) {
|
|
1515
1568
|
* isolates options to just the parser so that other parts of the code are not
|
1516
1569
|
* forced to use the same options.
|
1517
1570
|
*/
|
1518
|
-
void oj_parser_init() {
|
1571
|
+
void oj_parser_init(void) {
|
1519
1572
|
parser_class = rb_define_class_under(Oj, "Parser", rb_cObject);
|
1573
|
+
rb_gc_register_address(&parser_class);
|
1574
|
+
rb_undef_alloc_func(parser_class);
|
1575
|
+
|
1520
1576
|
rb_define_module_function(parser_class, "new", parser_new, -1);
|
1521
1577
|
rb_define_method(parser_class, "parse", parser_parse, 1);
|
1522
1578
|
rb_define_method(parser_class, "load", parser_load, 1);
|
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 */
|