oj 3.13.14 → 3.13.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/README.md +2 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/compat.c +10 -10
- data/ext/oj/custom.c +34 -53
- data/ext/oj/dump.c +24 -13
- data/ext/oj/dump_compat.c +5 -10
- data/ext/oj/dump_object.c +5 -60
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +5 -4
- data/ext/oj/fast.c +15 -13
- data/ext/oj/intern.c +6 -9
- data/ext/oj/introspect.c +96 -0
- data/ext/oj/mimic_json.c +18 -8
- data/ext/oj/object.c +42 -41
- data/ext/oj/oj.c +27 -4
- data/ext/oj/oj.h +4 -1
- data/ext/oj/parse.c +111 -76
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +61 -4
- data/ext/oj/parser.h +12 -0
- data/ext/oj/rails.c +5 -10
- data/ext/oj/saj2.c +333 -85
- data/ext/oj/saj2.h +23 -0
- data/ext/oj/sparse.c +4 -0
- data/ext/oj/strict.c +13 -13
- 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 +15 -20
- 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/test/bar.rb +3 -1
- data/test/helper.rb +8 -2
- data/test/json_gem/json_generator_test.rb +3 -4
- data/test/json_gem/json_parser_test.rb +8 -1
- data/test/json_gem/test_helper.rb +7 -3
- 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 +3 -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 +7 -107
data/ext/oj/dump_object.c
CHANGED
@@ -315,7 +315,6 @@ static void dump_hash_class(VALUE obj, VALUE clas, int depth, Out out) {
|
|
315
315
|
*out->cur = '\0';
|
316
316
|
}
|
317
317
|
|
318
|
-
#ifdef HAVE_RB_IVAR_FOREACH
|
319
318
|
static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
320
319
|
Out out = (Out)ov;
|
321
320
|
int depth = out->depth;
|
@@ -358,7 +357,6 @@ static int dump_attr_cb(ID key, VALUE value, VALUE ov) {
|
|
358
357
|
|
359
358
|
return ST_CONTINUE;
|
360
359
|
}
|
361
|
-
#endif
|
362
360
|
|
363
361
|
static void dump_hash(VALUE obj, int depth, Out out, bool as_ok) {
|
364
362
|
dump_hash_class(obj, rb_obj_class(obj), depth, out);
|
@@ -510,19 +508,8 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
510
508
|
default: break;
|
511
509
|
}
|
512
510
|
{
|
513
|
-
int cnt;
|
514
|
-
|
515
|
-
cnt = (int)rb_ivar_count(obj);
|
516
|
-
#else
|
517
|
-
volatile VALUE vars = rb_funcall2(obj, oj_instance_variables_id, 0, 0);
|
518
|
-
VALUE * np = RARRAY_PTR(vars);
|
519
|
-
ID vid;
|
520
|
-
const char * attr;
|
521
|
-
int i;
|
522
|
-
int first = 1;
|
523
|
-
|
524
|
-
cnt = (int)RARRAY_LEN(vars);
|
525
|
-
#endif
|
511
|
+
int cnt = (int)rb_ivar_count(obj);
|
512
|
+
|
526
513
|
if (Qundef != clas && 0 < cnt) {
|
527
514
|
*out->cur++ = ',';
|
528
515
|
}
|
@@ -535,52 +522,10 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
535
522
|
}
|
536
523
|
}
|
537
524
|
out->depth = depth + 1;
|
538
|
-
#ifdef HAVE_RB_IVAR_FOREACH
|
539
525
|
rb_ivar_foreach(obj, dump_attr_cb, (VALUE)out);
|
540
526
|
if (',' == *(out->cur - 1)) {
|
541
527
|
out->cur--; // backup to overwrite last comma
|
542
528
|
}
|
543
|
-
#else
|
544
|
-
size = d2 * out->indent + 1;
|
545
|
-
for (i = cnt; 0 < i; i--, np++) {
|
546
|
-
VALUE value;
|
547
|
-
|
548
|
-
vid = rb_to_id(*np);
|
549
|
-
attr = rb_id2name(vid);
|
550
|
-
if (Yes == out->opts->ignore_under && '@' == *attr && '_' == attr[1]) {
|
551
|
-
continue;
|
552
|
-
}
|
553
|
-
value = rb_ivar_get(obj, vid);
|
554
|
-
|
555
|
-
if (dump_ignore(out->opts, value)) {
|
556
|
-
continue;
|
557
|
-
}
|
558
|
-
if (out->omit_nil && Qnil == value) {
|
559
|
-
continue;
|
560
|
-
}
|
561
|
-
if (first) {
|
562
|
-
first = 0;
|
563
|
-
} else {
|
564
|
-
*out->cur++ = ',';
|
565
|
-
}
|
566
|
-
assure_size(out, size);
|
567
|
-
fill_indent(out, d2);
|
568
|
-
if ('@' == *attr) {
|
569
|
-
attr++;
|
570
|
-
oj_dump_cstr(attr, strlen(attr), 0, 0, out);
|
571
|
-
} else {
|
572
|
-
char buf[32];
|
573
|
-
|
574
|
-
*buf = '~';
|
575
|
-
strncpy(buf + 1, attr, sizeof(buf) - 2);
|
576
|
-
buf[sizeof(buf) - 1] = '\0';
|
577
|
-
oj_dump_cstr(buf, strlen(attr) + 1, 0, 0, out);
|
578
|
-
}
|
579
|
-
*out->cur++ = ':';
|
580
|
-
oj_dump_obj_val(value, d2, out);
|
581
|
-
assure_size(out, 2);
|
582
|
-
}
|
583
|
-
#endif
|
584
529
|
if (rb_obj_is_kind_of(obj, rb_eException)) {
|
585
530
|
volatile VALUE rv;
|
586
531
|
|
@@ -737,7 +682,7 @@ static DumpFunc obj_funcs[] = {
|
|
737
682
|
void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
738
683
|
int type = rb_type(obj);
|
739
684
|
|
740
|
-
if (Yes == out->opts->trace) {
|
685
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
741
686
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
742
687
|
}
|
743
688
|
if (MAX_DEPTH < depth) {
|
@@ -748,14 +693,14 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
748
693
|
|
749
694
|
if (NULL != f) {
|
750
695
|
f(obj, depth, out, false);
|
751
|
-
if (Yes == out->opts->trace) {
|
696
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
752
697
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
753
698
|
}
|
754
699
|
return;
|
755
700
|
}
|
756
701
|
}
|
757
702
|
oj_dump_nil(Qnil, depth, out, false);
|
758
|
-
if (Yes == out->opts->trace) {
|
703
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
759
704
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
760
705
|
}
|
761
706
|
}
|
data/ext/oj/dump_strict.c
CHANGED
@@ -338,7 +338,7 @@ static DumpFunc strict_funcs[] = {
|
|
338
338
|
void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
339
339
|
int type = rb_type(obj);
|
340
340
|
|
341
|
-
if (Yes == out->opts->trace) {
|
341
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
342
342
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
343
343
|
}
|
344
344
|
if (MAX_DEPTH < depth) {
|
@@ -349,7 +349,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
|
349
349
|
|
350
350
|
if (NULL != f) {
|
351
351
|
f(obj, depth, out, false);
|
352
|
-
if (Yes == out->opts->trace) {
|
352
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
353
353
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
354
354
|
}
|
355
355
|
return;
|
@@ -386,7 +386,7 @@ static DumpFunc null_funcs[] = {
|
|
386
386
|
void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
387
387
|
int type = rb_type(obj);
|
388
388
|
|
389
|
-
if (Yes == out->opts->trace) {
|
389
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
390
390
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
391
391
|
}
|
392
392
|
if (MAX_DEPTH < depth) {
|
@@ -397,14 +397,14 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
|
397
397
|
|
398
398
|
if (NULL != f) {
|
399
399
|
f(obj, depth, out, false);
|
400
|
-
if (Yes == out->opts->trace) {
|
400
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
401
401
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
402
402
|
}
|
403
403
|
return;
|
404
404
|
}
|
405
405
|
}
|
406
406
|
oj_dump_nil(Qnil, depth, out, false);
|
407
|
-
if (Yes == out->opts->trace) {
|
407
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
408
408
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
409
409
|
}
|
410
410
|
}
|
data/ext/oj/extconf.rb
CHANGED
@@ -23,14 +23,10 @@ dflags = {
|
|
23
23
|
'RSTRUCT_LEN_RETURNS_INTEGER_OBJECT' => ('ruby' == type && '2' == version[0] && '4' == version[1] && '1' >= version[2]) ? 1 : 0,
|
24
24
|
}
|
25
25
|
|
26
|
-
have_func('rb_time_timespec')
|
27
|
-
have_func('rb_ivar_count')
|
28
|
-
have_func('rb_ivar_foreach')
|
29
26
|
# Support for compaction.
|
30
27
|
have_func('rb_gc_mark_movable')
|
31
28
|
have_func('stpcpy')
|
32
29
|
have_func('pthread_mutex_init')
|
33
|
-
have_func('rb_enc_associate')
|
34
30
|
have_func('rb_enc_interned_str')
|
35
31
|
have_func('rb_ext_ractor_safe', 'ruby.h')
|
36
32
|
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
@@ -38,6 +34,11 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
|
|
38
34
|
|
39
35
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
40
36
|
|
37
|
+
if with_config('--with-sse42')
|
38
|
+
$CPPFLAGS += ' -msse4.2'
|
39
|
+
dflags['OJ_USE_SSE4_2'] = 1
|
40
|
+
end
|
41
|
+
|
41
42
|
dflags.each do |k,v|
|
42
43
|
if v.nil?
|
43
44
|
$CPPFLAGS += " -D#{k}"
|
data/ext/oj/fast.c
CHANGED
@@ -677,21 +677,23 @@ static void free_doc_cb(void *x) {
|
|
677
677
|
}
|
678
678
|
|
679
679
|
static void mark_leaf(Leaf leaf) {
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
680
|
+
if (NULL != leaf) {
|
681
|
+
switch (leaf->value_type) {
|
682
|
+
case COL_VAL:
|
683
|
+
if (NULL != leaf->elements) {
|
684
|
+
Leaf first = leaf->elements->next;
|
685
|
+
Leaf e = first;
|
685
686
|
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
|
690
|
-
|
691
|
-
|
692
|
-
|
687
|
+
do {
|
688
|
+
mark_leaf(e);
|
689
|
+
e = e->next;
|
690
|
+
} while (e != first);
|
691
|
+
}
|
692
|
+
break;
|
693
|
+
case RUBY_VAL: mark(leaf->value); break;
|
693
694
|
|
694
|
-
|
695
|
+
default: break;
|
696
|
+
}
|
695
697
|
}
|
696
698
|
}
|
697
699
|
|
data/ext/oj/intern.c
CHANGED
@@ -37,13 +37,10 @@ typedef struct _hash {
|
|
37
37
|
struct _hash class_hash;
|
38
38
|
struct _hash attr_hash;
|
39
39
|
|
40
|
-
static struct _cache *str_cache = NULL;
|
41
40
|
static VALUE str_cache_obj;
|
42
41
|
|
43
|
-
static struct _cache *sym_cache = NULL;
|
44
42
|
static VALUE sym_cache_obj;
|
45
43
|
|
46
|
-
static struct _cache *attr_cache = NULL;
|
47
44
|
static VALUE attr_cache_obj;
|
48
45
|
|
49
46
|
static VALUE form_str(const char *str, size_t len) {
|
@@ -93,15 +90,15 @@ void oj_hash_init(void) {
|
|
93
90
|
rb_gc_register_address(&cache_class);
|
94
91
|
rb_undef_alloc_func(cache_class);
|
95
92
|
|
96
|
-
str_cache = cache_create(0, form_str, true, true);
|
93
|
+
struct _cache *str_cache = cache_create(0, form_str, true, true);
|
97
94
|
str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
|
98
95
|
rb_gc_register_address(&str_cache_obj);
|
99
96
|
|
100
|
-
sym_cache = cache_create(0, form_sym, true, true);
|
97
|
+
struct _cache *sym_cache = cache_create(0, form_sym, true, true);
|
101
98
|
sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
|
102
99
|
rb_gc_register_address(&sym_cache_obj);
|
103
100
|
|
104
|
-
attr_cache
|
101
|
+
struct _cache *attr_cache = cache_create(0, form_attr, false, true);
|
105
102
|
attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
|
106
103
|
rb_gc_register_address(&attr_cache_obj);
|
107
104
|
|
@@ -122,18 +119,18 @@ oj_str_intern(const char *key, size_t len) {
|
|
122
119
|
#if HAVE_RB_ENC_INTERNED_STR && 0
|
123
120
|
return rb_enc_interned_str(key, len, rb_utf8_encoding());
|
124
121
|
#else
|
125
|
-
return cache_intern(
|
122
|
+
return cache_intern(DATA_PTR(str_cache_obj), key, len);
|
126
123
|
#endif
|
127
124
|
}
|
128
125
|
|
129
126
|
VALUE
|
130
127
|
oj_sym_intern(const char *key, size_t len) {
|
131
|
-
|
128
|
+
return cache_intern(DATA_PTR(sym_cache_obj), key, len);
|
132
129
|
}
|
133
130
|
|
134
131
|
ID
|
135
132
|
oj_attr_intern(const char *key, size_t len) {
|
136
|
-
|
133
|
+
return cache_intern(DATA_PTR(attr_cache_obj), key, len);
|
137
134
|
}
|
138
135
|
|
139
136
|
static uint64_t hash_calc(const uint8_t *key, size_t len) {
|
data/ext/oj/introspect.c
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
|
2
|
+
#include "cache.h"
|
3
|
+
#include "oj.h"
|
4
|
+
#include "parser.h"
|
5
|
+
#include "usual.h"
|
6
|
+
|
7
|
+
#define BYTE_OFFSETS_STACK_INC_SIZE 256
|
8
|
+
|
9
|
+
VALUE mod = Qnil;
|
10
|
+
|
11
|
+
typedef struct _introspect {
|
12
|
+
struct _usual usual;
|
13
|
+
void (*start)(struct _ojParser *p);
|
14
|
+
void (*free)(struct _ojParser *p);
|
15
|
+
void (*mark)(struct _ojParser *p);
|
16
|
+
void (*open_object)(struct _ojParser *p);
|
17
|
+
void (*close_object)(struct _ojParser *p);
|
18
|
+
|
19
|
+
int len;
|
20
|
+
int cur;
|
21
|
+
long *stack;
|
22
|
+
|
23
|
+
} * Introspect;
|
24
|
+
|
25
|
+
static void dfree(ojParser p) {
|
26
|
+
Introspect d = (Introspect)p->ctx;
|
27
|
+
|
28
|
+
xfree(d->stack);
|
29
|
+
// As with the mark() function, this function should still work.
|
30
|
+
d->free(p);
|
31
|
+
}
|
32
|
+
|
33
|
+
static void start(ojParser p) {
|
34
|
+
Introspect d = (Introspect)p->ctx;
|
35
|
+
|
36
|
+
d->start(p);
|
37
|
+
|
38
|
+
d->stack = ALLOC_N(long, BYTE_OFFSETS_STACK_INC_SIZE);
|
39
|
+
d->len = BYTE_OFFSETS_STACK_INC_SIZE;
|
40
|
+
d->cur = 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void open_object(ojParser p) {
|
44
|
+
Introspect d = (Introspect)p->ctx;
|
45
|
+
|
46
|
+
d->open_object(p);
|
47
|
+
|
48
|
+
// TBD add offset
|
49
|
+
}
|
50
|
+
|
51
|
+
static void close_object(ojParser p) {
|
52
|
+
Introspect d = (Introspect)p->ctx;
|
53
|
+
|
54
|
+
d->close_object(p);
|
55
|
+
|
56
|
+
// TBD set offset on hash
|
57
|
+
}
|
58
|
+
|
59
|
+
static VALUE new_parser(VALUE self, VALUE ropts) {
|
60
|
+
volatile VALUE pv = oj_parser_new();
|
61
|
+
ojParser p = (ojParser)DATA_PTR(pv);
|
62
|
+
Introspect d = ALLOC(struct _introspect);
|
63
|
+
|
64
|
+
oj_init_usual(p, &d->usual);
|
65
|
+
|
66
|
+
// Set the options before switching to the Introspect delegate.
|
67
|
+
p->ctx = (void *)d;
|
68
|
+
|
69
|
+
d->free = p->free;
|
70
|
+
p->free = dfree;
|
71
|
+
|
72
|
+
d->start = p->start;
|
73
|
+
p->start = start;
|
74
|
+
|
75
|
+
// We are cheating with the mark, free, and options functions. Since
|
76
|
+
// struct _usual is the first member of struct _introspect the cast to
|
77
|
+
// Usual in the usual.c mark() function should still work just fine.
|
78
|
+
|
79
|
+
d->open_object = p->funcs[TOP_FUN].open_object;
|
80
|
+
p->funcs[TOP_FUN].open_object = open_object;
|
81
|
+
|
82
|
+
d->close_object = p->funcs[TOP_FUN].close_object;
|
83
|
+
p->funcs[TOP_FUN].close_object = close_object;
|
84
|
+
|
85
|
+
Check_Type(ropts, T_HASH);
|
86
|
+
oj_parser_set_option(p, ropts);
|
87
|
+
|
88
|
+
return pv;
|
89
|
+
}
|
90
|
+
|
91
|
+
void Init_introspect(void) {
|
92
|
+
mod = rb_define_module("Introspect");
|
93
|
+
rb_gc_register_address(&mod);
|
94
|
+
|
95
|
+
rb_define_module_function(mod, "parser", new_parser, 1);
|
96
|
+
}
|
data/ext/oj/mimic_json.c
CHANGED
@@ -388,6 +388,10 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
|
|
388
388
|
VALUE active_hack[1];
|
389
389
|
|
390
390
|
if (Qundef == state_class) {
|
391
|
+
rb_warn(
|
392
|
+
"Oj::Rails.mimic_JSON was called implicitly. "
|
393
|
+
"Call it explicitly beforehand if you want to remove this warning."
|
394
|
+
);
|
391
395
|
oj_define_mimic_json(0, NULL, Qnil);
|
392
396
|
}
|
393
397
|
active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
|
@@ -481,6 +485,10 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
|
|
481
485
|
rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
|
482
486
|
}
|
483
487
|
if (Qundef == state_class) {
|
488
|
+
rb_warn(
|
489
|
+
"Oj::Rails.mimic_JSON was called implicitly. "
|
490
|
+
"Call it explicitly beforehand if you want to remove this warning."
|
491
|
+
);
|
484
492
|
oj_define_mimic_json(0, NULL, Qnil);
|
485
493
|
}
|
486
494
|
rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
|
@@ -536,14 +544,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
|
|
536
544
|
}
|
537
545
|
} else if (oj_decimal_class_sym == k) {
|
538
546
|
pi->options.compat_bigdec = (oj_bigdecimal_class == v);
|
539
|
-
} else if (oj_max_nesting_sym == k) {
|
540
|
-
if (Qtrue == v) {
|
541
|
-
pi->max_depth = 100;
|
542
|
-
} else if (Qfalse == v || Qnil == v) {
|
543
|
-
pi->max_depth = 0;
|
544
|
-
} else if (T_FIXNUM == rb_type(v)) {
|
545
|
-
pi->max_depth = NUM2INT(v);
|
546
|
-
}
|
547
547
|
}
|
548
548
|
return ST_CONTINUE;
|
549
549
|
}
|
@@ -573,11 +573,21 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
573
573
|
pi.max_depth = 100;
|
574
574
|
|
575
575
|
if (Qnil != ropts) {
|
576
|
+
VALUE v;
|
577
|
+
|
576
578
|
if (T_HASH != rb_type(ropts)) {
|
577
579
|
rb_raise(rb_eArgError, "options must be a hash.");
|
578
580
|
}
|
579
581
|
|
580
582
|
rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
|
583
|
+
v = rb_hash_lookup(ropts, oj_max_nesting_sym);
|
584
|
+
if (Qtrue == v) {
|
585
|
+
pi.max_depth = 100;
|
586
|
+
} else if (Qfalse == v || Qnil == v) {
|
587
|
+
pi.max_depth = 0;
|
588
|
+
} else if (T_FIXNUM == rb_type(v)) {
|
589
|
+
pi.max_depth = NUM2INT(v);
|
590
|
+
}
|
581
591
|
oj_parse_opt_match_string(&pi.options.str_rx, ropts);
|
582
592
|
if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
|
583
593
|
rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
|
data/ext/oj/object.c
CHANGED
@@ -67,9 +67,9 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
|
|
67
67
|
|
68
68
|
// The much faster approach (4x faster)
|
69
69
|
static int parse_num(const char *str, const char *end, int cnt) {
|
70
|
-
int
|
70
|
+
int n = 0;
|
71
71
|
char c;
|
72
|
-
int
|
72
|
+
int i;
|
73
73
|
|
74
74
|
for (i = cnt; 0 < i; i--, str++) {
|
75
75
|
c = *str;
|
@@ -83,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
|
|
83
83
|
|
84
84
|
VALUE
|
85
85
|
oj_parse_xml_time(const char *str, int len) {
|
86
|
-
VALUE
|
86
|
+
VALUE args[8];
|
87
87
|
const char *end = str + len;
|
88
|
-
int
|
88
|
+
int n;
|
89
89
|
|
90
90
|
// year
|
91
91
|
if (0 > (n = parse_num(str, end, 4))) {
|
@@ -269,19 +269,10 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
269
269
|
// match the expected value.
|
270
270
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
271
271
|
} else if (ni->has_exp) {
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
sec_as_time(t, &ti);
|
277
|
-
args[0] = LONG2NUM((long)(ti.year));
|
278
|
-
args[1] = LONG2NUM(ti.mon);
|
279
|
-
args[2] = LONG2NUM(ti.day);
|
280
|
-
args[3] = LONG2NUM(ti.hour);
|
281
|
-
args[4] = LONG2NUM(ti.min);
|
282
|
-
args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
|
283
|
-
args[6] = LONG2NUM(ni->exp);
|
284
|
-
parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
|
272
|
+
struct timespec ts;
|
273
|
+
ts.tv_sec = ni->i;
|
274
|
+
ts.tv_nsec = nsec;
|
275
|
+
parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
|
285
276
|
} else {
|
286
277
|
parent->val = rb_time_nano_new(ni->i, (long)nsec);
|
287
278
|
}
|
@@ -333,26 +324,30 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
333
324
|
// If struct is not defined then we let this fail and raise an exception.
|
334
325
|
sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
|
335
326
|
}
|
336
|
-
|
337
|
-
|
338
|
-
|
327
|
+
if (sc == rb_cRange) {
|
328
|
+
parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
|
329
|
+
} else {
|
330
|
+
// Create a properly initialized struct instance without calling the initialize method.
|
331
|
+
parent->val = rb_obj_alloc(sc);
|
332
|
+
// If the JSON array has more entries than the struct class allows, we record an error.
|
339
333
|
#ifdef RSTRUCT_LEN
|
340
334
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
341
335
|
slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
|
342
336
|
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
343
|
-
|
337
|
+
slen = (int)RSTRUCT_LEN(parent->val);
|
344
338
|
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
345
339
|
#else
|
346
|
-
|
340
|
+
slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
|
347
341
|
#endif
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
342
|
+
// MRI >= 1.9
|
343
|
+
if (len - 1 > slen) {
|
344
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
|
345
|
+
} else {
|
346
|
+
int i;
|
353
347
|
|
354
|
-
|
355
|
-
|
348
|
+
for (i = 0; i < len - 1; i++) {
|
349
|
+
rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
|
350
|
+
}
|
356
351
|
}
|
357
352
|
}
|
358
353
|
return 1;
|
@@ -374,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
|
|
374
369
|
}
|
375
370
|
|
376
371
|
void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
|
377
|
-
|
372
|
+
if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
373
|
+
parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
|
374
|
+
} else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
|
375
|
+
rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
|
376
|
+
} else {
|
377
|
+
rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
|
378
|
+
}
|
378
379
|
}
|
379
380
|
|
380
381
|
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
381
|
-
const char
|
382
|
+
const char *key = kval->key;
|
382
383
|
int klen = kval->klen;
|
383
384
|
Val parent = stack_peek(&pi->stack);
|
384
385
|
volatile VALUE rval = Qnil;
|
@@ -445,13 +446,13 @@ WHICH_TYPE:
|
|
445
446
|
rb_class2name(rb_obj_class(parent->val)));
|
446
447
|
return;
|
447
448
|
}
|
448
|
-
if (Yes == pi->options.trace) {
|
449
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
449
450
|
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
|
450
451
|
}
|
451
452
|
}
|
452
453
|
|
453
454
|
static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
|
454
|
-
const char
|
455
|
+
const char *key = kval->key;
|
455
456
|
int klen = kval->klen;
|
456
457
|
Val parent = stack_peek(&pi->stack);
|
457
458
|
volatile VALUE rval = Qnil;
|
@@ -516,7 +517,7 @@ WHICH_TYPE:
|
|
516
517
|
rb_class2name(rb_obj_class(parent->val)));
|
517
518
|
return;
|
518
519
|
}
|
519
|
-
if (Yes == pi->options.trace) {
|
520
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
520
521
|
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
|
521
522
|
}
|
522
523
|
}
|
@@ -602,13 +603,13 @@ WHICH_TYPE:
|
|
602
603
|
rb_class2name(rb_obj_class(parent->val)));
|
603
604
|
return;
|
604
605
|
}
|
605
|
-
if (Yes == pi->options.trace) {
|
606
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
606
607
|
oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
|
607
608
|
}
|
608
609
|
}
|
609
610
|
|
610
611
|
static VALUE start_hash(ParseInfo pi) {
|
611
|
-
if (Yes == pi->options.trace) {
|
612
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
612
613
|
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
613
614
|
}
|
614
615
|
return Qnil;
|
@@ -626,7 +627,7 @@ static void end_hash(ParseInfo pi) {
|
|
626
627
|
oj_odd_free(oa);
|
627
628
|
parent->odd_args = NULL;
|
628
629
|
}
|
629
|
-
if (Yes == pi->options.trace) {
|
630
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
630
631
|
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
631
632
|
}
|
632
633
|
}
|
@@ -654,7 +655,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
654
655
|
}
|
655
656
|
rval = str_to_value(pi, str, len, orig);
|
656
657
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
657
|
-
if (Yes == pi->options.trace) {
|
658
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
658
659
|
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
|
659
660
|
}
|
660
661
|
}
|
@@ -663,21 +664,21 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
|
|
663
664
|
volatile VALUE rval = oj_num_as_value(ni);
|
664
665
|
|
665
666
|
rb_ary_push(stack_peek(&pi->stack)->val, rval);
|
666
|
-
if (Yes == pi->options.trace) {
|
667
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
667
668
|
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
668
669
|
}
|
669
670
|
}
|
670
671
|
|
671
672
|
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
672
673
|
pi->stack.head->val = str_to_value(pi, str, len, orig);
|
673
|
-
if (Yes == pi->options.trace) {
|
674
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
674
675
|
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
|
675
676
|
}
|
676
677
|
}
|
677
678
|
|
678
679
|
static void add_num(ParseInfo pi, NumInfo ni) {
|
679
680
|
pi->stack.head->val = oj_num_as_value(ni);
|
680
|
-
if (Yes == pi->options.trace) {
|
681
|
+
if (RB_UNLIKELY(Yes == pi->options.trace)) {
|
681
682
|
oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
|
682
683
|
}
|
683
684
|
}
|