oj 3.17.6 → 3.17.8
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +67 -0
- data/ext/oj/cache.c +64 -47
- data/ext/oj/cache.h +1 -1
- data/ext/oj/code.c +38 -28
- data/ext/oj/code.h +2 -0
- data/ext/oj/compat.c +61 -29
- data/ext/oj/custom.c +38 -5
- data/ext/oj/dump.c +93 -29
- data/ext/oj/dump_compat.c +8 -11
- data/ext/oj/dump_object.c +18 -2
- data/ext/oj/dump_strict.c +2 -1
- data/ext/oj/extconf.rb +7 -1
- data/ext/oj/fast.c +46 -29
- data/ext/oj/intern.c +75 -77
- data/ext/oj/mimic_json.c +5 -29
- data/ext/oj/object.c +21 -2
- data/ext/oj/oj.c +136 -33
- data/ext/oj/oj.h +9 -7
- data/ext/oj/parse.c +58 -4
- data/ext/oj/parse.h +23 -1
- data/ext/oj/parser.c +99 -36
- data/ext/oj/parser.h +1 -1
- data/ext/oj/rails.c +8 -3
- data/ext/oj/reader.c +4 -0
- data/ext/oj/reader.h +1 -0
- data/ext/oj/resolve.c +5 -4
- data/ext/oj/resolve.h +9 -0
- data/ext/oj/saj.c +14 -7
- data/ext/oj/saj2.c +44 -28
- data/ext/oj/simd.h +5 -3
- data/ext/oj/sparse.c +7 -0
- data/ext/oj/stream_writer.c +3 -0
- data/ext/oj/strict.c +42 -4
- data/ext/oj/string_writer.c +17 -3
- data/ext/oj/usual.c +12 -4
- data/ext/oj/val_stack.c +11 -22
- data/ext/oj/val_stack.h +45 -24
- data/ext/oj/wab.c +3 -0
- data/lib/oj/generic_object.rb +82 -0
- data/lib/oj/json.rb +1 -71
- data/lib/oj/mimic.rb +0 -1
- data/lib/oj/version.rb +1 -1
- metadata +16 -15
data/ext/oj/saj2.c
CHANGED
|
@@ -33,9 +33,30 @@ static void push_key(Saj d, VALUE key) {
|
|
|
33
33
|
d->tail++;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
static VALUE pop_key(Saj d) {
|
|
37
|
+
if (d->tail <= d->keys) {
|
|
38
|
+
rb_raise(rb_eIndexError, "accessing key stack");
|
|
39
|
+
}
|
|
40
|
+
d->tail--;
|
|
41
|
+
|
|
42
|
+
return *d->tail;
|
|
43
|
+
}
|
|
44
|
+
|
|
36
45
|
static void noop(ojParser p) {
|
|
37
46
|
}
|
|
38
47
|
|
|
48
|
+
static void open_push_key(ojParser p) {
|
|
49
|
+
push_key((Saj)p->ctx, get_key(p));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static void close_pop_key(ojParser p) {
|
|
53
|
+
Saj d = (Saj)p->ctx;
|
|
54
|
+
|
|
55
|
+
if (d->keys < d->tail) {
|
|
56
|
+
d->tail--;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
static void open_object(ojParser p) {
|
|
40
61
|
rb_funcall(((Saj)p->ctx)->handler, oj_hash_start_id, 1, Qnil);
|
|
41
62
|
}
|
|
@@ -89,11 +110,7 @@ static void close_object(ojParser p) {
|
|
|
89
110
|
VALUE key = Qnil;
|
|
90
111
|
|
|
91
112
|
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
92
|
-
d
|
|
93
|
-
if (d->tail < d->keys) {
|
|
94
|
-
rb_raise(rb_eIndexError, "accessing key stack");
|
|
95
|
-
}
|
|
96
|
-
key = *d->tail;
|
|
113
|
+
key = pop_key(d);
|
|
97
114
|
}
|
|
98
115
|
rb_funcall(d->handler, oj_hash_end_id, 1, key);
|
|
99
116
|
}
|
|
@@ -103,11 +120,7 @@ static void close_object_loc(ojParser p) {
|
|
|
103
120
|
VALUE key = Qnil;
|
|
104
121
|
|
|
105
122
|
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
106
|
-
d
|
|
107
|
-
if (d->tail < d->keys) {
|
|
108
|
-
rb_raise(rb_eIndexError, "accessing key stack");
|
|
109
|
-
}
|
|
110
|
-
key = *d->tail;
|
|
123
|
+
key = pop_key(d);
|
|
111
124
|
}
|
|
112
125
|
rb_funcall(d->handler, oj_hash_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
|
|
113
126
|
}
|
|
@@ -117,11 +130,7 @@ static void close_array(ojParser p) {
|
|
|
117
130
|
VALUE key = Qnil;
|
|
118
131
|
|
|
119
132
|
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
120
|
-
d
|
|
121
|
-
if (d->tail < d->keys) {
|
|
122
|
-
rb_raise(rb_eIndexError, "accessing key stack");
|
|
123
|
-
}
|
|
124
|
-
key = *d->tail;
|
|
133
|
+
key = pop_key(d);
|
|
125
134
|
}
|
|
126
135
|
rb_funcall(d->handler, oj_array_end_id, 1, key);
|
|
127
136
|
}
|
|
@@ -131,11 +140,7 @@ static void close_array_loc(ojParser p) {
|
|
|
131
140
|
VALUE key = Qnil;
|
|
132
141
|
|
|
133
142
|
if (OBJECT_FUN == p->stack[p->depth]) {
|
|
134
|
-
d
|
|
135
|
-
if (d->tail < d->keys) {
|
|
136
|
-
rb_raise(rb_eIndexError, "accessing key stack");
|
|
137
|
-
}
|
|
138
|
-
key = *d->tail;
|
|
143
|
+
key = pop_key(d);
|
|
139
144
|
}
|
|
140
145
|
rb_funcall(d->handler, oj_array_end_id, 3, key, LONG2FIX(p->line), LONG2FIX(p->cur - p->col));
|
|
141
146
|
}
|
|
@@ -380,10 +385,15 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
|
|
|
380
385
|
return d->handler;
|
|
381
386
|
}
|
|
382
387
|
if (0 == strcmp(key, "handler=")) {
|
|
388
|
+
int hash_start = rb_respond_to(value, oj_hash_start_id);
|
|
389
|
+
int hash_end = rb_respond_to(value, oj_hash_end_id);
|
|
390
|
+
int array_start = rb_respond_to(value, oj_array_start_id);
|
|
391
|
+
int array_end = rb_respond_to(value, oj_array_end_id);
|
|
392
|
+
|
|
383
393
|
d->tail = d->keys;
|
|
384
394
|
d->handler = value;
|
|
385
395
|
reset(p);
|
|
386
|
-
if (
|
|
396
|
+
if (hash_start) {
|
|
387
397
|
if (1 == rb_obj_method_arity(value, oj_hash_start_id)) {
|
|
388
398
|
p->funcs[TOP_FUN].open_object = open_object;
|
|
389
399
|
p->funcs[ARRAY_FUN].open_object = open_object;
|
|
@@ -393,8 +403,10 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
|
|
|
393
403
|
p->funcs[ARRAY_FUN].open_object = open_object_loc;
|
|
394
404
|
p->funcs[OBJECT_FUN].open_object = open_object_loc_key;
|
|
395
405
|
}
|
|
406
|
+
} else if (hash_end) {
|
|
407
|
+
p->funcs[OBJECT_FUN].open_object = open_push_key;
|
|
396
408
|
}
|
|
397
|
-
if (
|
|
409
|
+
if (array_start) {
|
|
398
410
|
if (1 == rb_obj_method_arity(value, oj_array_start_id)) {
|
|
399
411
|
p->funcs[TOP_FUN].open_array = open_array;
|
|
400
412
|
p->funcs[ARRAY_FUN].open_array = open_array;
|
|
@@ -404,8 +416,10 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
|
|
|
404
416
|
p->funcs[ARRAY_FUN].open_array = open_array_loc;
|
|
405
417
|
p->funcs[OBJECT_FUN].open_array = open_array_loc_key;
|
|
406
418
|
}
|
|
419
|
+
} else if (array_end) {
|
|
420
|
+
p->funcs[OBJECT_FUN].open_array = open_push_key;
|
|
407
421
|
}
|
|
408
|
-
if (
|
|
422
|
+
if (hash_end) {
|
|
409
423
|
if (1 == rb_obj_method_arity(value, oj_hash_end_id)) {
|
|
410
424
|
p->funcs[TOP_FUN].close_object = close_object;
|
|
411
425
|
p->funcs[ARRAY_FUN].close_object = close_object;
|
|
@@ -415,8 +429,10 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
|
|
|
415
429
|
p->funcs[ARRAY_FUN].close_object = close_object_loc;
|
|
416
430
|
p->funcs[OBJECT_FUN].close_object = close_object_loc;
|
|
417
431
|
}
|
|
432
|
+
} else if (hash_start) {
|
|
433
|
+
p->funcs[OBJECT_FUN].close_object = close_pop_key;
|
|
418
434
|
}
|
|
419
|
-
if (
|
|
435
|
+
if (array_end) {
|
|
420
436
|
if (1 == rb_obj_method_arity(value, oj_array_end_id)) {
|
|
421
437
|
p->funcs[TOP_FUN].close_array = close_array;
|
|
422
438
|
p->funcs[ARRAY_FUN].close_array = close_array;
|
|
@@ -426,6 +442,8 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
|
|
|
426
442
|
p->funcs[ARRAY_FUN].close_array = close_array_loc;
|
|
427
443
|
p->funcs[OBJECT_FUN].close_array = close_array_loc;
|
|
428
444
|
}
|
|
445
|
+
} else if (array_start) {
|
|
446
|
+
p->funcs[OBJECT_FUN].close_array = close_pop_key;
|
|
429
447
|
}
|
|
430
448
|
if (rb_respond_to(value, oj_add_value_id)) {
|
|
431
449
|
if (2 == rb_obj_method_arity(value, oj_add_value_id)) {
|
|
@@ -547,10 +565,8 @@ static void mark(ojParser p) {
|
|
|
547
565
|
if (Qnil != d->handler) {
|
|
548
566
|
rb_gc_mark(d->handler);
|
|
549
567
|
}
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
rb_gc_mark(*kp);
|
|
553
|
-
}
|
|
568
|
+
for (kp = d->keys; kp < d->tail; kp++) {
|
|
569
|
+
rb_gc_mark(*kp);
|
|
554
570
|
}
|
|
555
571
|
}
|
|
556
572
|
|
data/ext/oj/simd.h
CHANGED
|
@@ -98,10 +98,10 @@ static inline int oj_ctz64_fallback(uint64_t x) {
|
|
|
98
98
|
#elif defined(__GNUC__) || defined(__clang__)
|
|
99
99
|
// GCC/Clang: check for header availability and include them
|
|
100
100
|
// We include headers but use target attributes to enable instructions per-function
|
|
101
|
-
// Include cpuid.h for __get_cpuid fallback when __builtin_cpu_supports is unavailable
|
|
102
|
-
|
|
101
|
+
// Include cpuid.h for __get_cpuid fallback when __builtin_cpu_supports is unavailable.
|
|
102
|
+
// cpuid.h is available on all GCC since 4.3 and all Clang versions, so include
|
|
103
|
+
// it unconditionally rather than gating on __has_include (which GCC < 5 lacks).
|
|
103
104
|
#include <cpuid.h>
|
|
104
|
-
#endif
|
|
105
105
|
#if defined(__SSE4_2__) || defined(__SSE2__)
|
|
106
106
|
// If any SSE is enabled globally, x86intrin.h should be available
|
|
107
107
|
#include <x86intrin.h>
|
|
@@ -109,6 +109,7 @@ static inline int oj_ctz64_fallback(uint64_t x) {
|
|
|
109
109
|
#define HAVE_SIMD_SSE2 1
|
|
110
110
|
#else
|
|
111
111
|
// Try to include headers anyway for target attribute functions
|
|
112
|
+
#ifdef __has_include
|
|
112
113
|
#if __has_include(<x86intrin.h>)
|
|
113
114
|
#include <x86intrin.h>
|
|
114
115
|
#define HAVE_SIMD_SSE4_2 1
|
|
@@ -123,6 +124,7 @@ static inline int oj_ctz64_fallback(uint64_t x) {
|
|
|
123
124
|
#endif
|
|
124
125
|
#endif
|
|
125
126
|
#endif
|
|
127
|
+
#endif
|
|
126
128
|
|
|
127
129
|
// Target attribute macros for function-level SIMD enabling
|
|
128
130
|
#if defined(__clang__) || defined(__GNUC__)
|
data/ext/oj/sparse.c
CHANGED
|
@@ -274,6 +274,10 @@ static void read_escaped_str(ParseInfo pi) {
|
|
|
274
274
|
buf_cleanup(&buf);
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
|
+
} else if ((unsigned char)c < 0x20 && (StrictMode == pi->options.mode || CompatMode == pi->options.mode)) {
|
|
278
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid control character in string");
|
|
279
|
+
buf_cleanup(&buf);
|
|
280
|
+
return;
|
|
277
281
|
} else {
|
|
278
282
|
buf_append(&buf, c);
|
|
279
283
|
}
|
|
@@ -341,6 +345,9 @@ static void read_str(ParseInfo pi) {
|
|
|
341
345
|
read_escaped_str(pi);
|
|
342
346
|
reader_release(&pi->rd);
|
|
343
347
|
return;
|
|
348
|
+
} else if ((unsigned char)c < 0x20 && (StrictMode == pi->options.mode || CompatMode == pi->options.mode)) {
|
|
349
|
+
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid control character in string");
|
|
350
|
+
return;
|
|
344
351
|
}
|
|
345
352
|
}
|
|
346
353
|
if (0 == parent) { // simple add
|
data/ext/oj/stream_writer.c
CHANGED
|
@@ -16,6 +16,9 @@ static void stream_writer_free(void *ptr) {
|
|
|
16
16
|
return;
|
|
17
17
|
}
|
|
18
18
|
sw = (StreamWriter)ptr;
|
|
19
|
+
if (NULL != sw->sw.out.circ_cache) {
|
|
20
|
+
oj_cache8_delete(sw->sw.out.circ_cache);
|
|
21
|
+
}
|
|
19
22
|
oj_options_release(&sw->sw.opts);
|
|
20
23
|
OJ_R_FREE(sw->sw.out.buf);
|
|
21
24
|
OJ_R_FREE(sw->sw.types);
|
data/ext/oj/strict.c
CHANGED
|
@@ -47,7 +47,29 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
|
|
|
47
47
|
return rkey;
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// With the default Hash class the pairs of the just closed hash sit on top
|
|
51
|
+
// of the pair buffer; build the Hash in one bulk insert with the final size
|
|
52
|
+
// known instead of one rb_hash_aset per pair (which converts the small
|
|
53
|
+
// ar_table to an st_table mid-insertion for hashes above 8 entries).
|
|
50
54
|
static void hash_end(ParseInfo pi) {
|
|
55
|
+
if (Qnil == pi->options.hash_class) {
|
|
56
|
+
ValStack stack = &pi->stack;
|
|
57
|
+
Val hash = stack_peek(stack);
|
|
58
|
+
size_t cnt = hash->pcnt;
|
|
59
|
+
volatile VALUE h;
|
|
60
|
+
|
|
61
|
+
#if HAVE_RB_HASH_NEW_CAPA
|
|
62
|
+
h = rb_hash_new_capa((long)(cnt / 2));
|
|
63
|
+
#else
|
|
64
|
+
h = rb_hash_new();
|
|
65
|
+
#endif
|
|
66
|
+
if (0 < cnt) {
|
|
67
|
+
rb_hash_bulk_insert((long)cnt, stack->pairs + stack->pcnt - cnt, h);
|
|
68
|
+
stack->pcnt -= cnt;
|
|
69
|
+
hash->pcnt = 0;
|
|
70
|
+
}
|
|
71
|
+
hash->val = h;
|
|
72
|
+
}
|
|
51
73
|
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
|
52
74
|
}
|
|
53
75
|
|
|
@@ -84,13 +106,19 @@ static VALUE start_hash(ParseInfo pi) {
|
|
|
84
106
|
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
|
85
107
|
}
|
|
86
108
|
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
|
87
|
-
|
|
109
|
+
// The Hash is built at hash_end from the buffered pairs.
|
|
110
|
+
return Qundef;
|
|
88
111
|
}
|
|
89
112
|
|
|
90
113
|
static void hash_set_cstr(ParseInfo pi, Val parent, const char *str, size_t len, const char *orig) {
|
|
91
114
|
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
|
92
115
|
|
|
93
|
-
|
|
116
|
+
if (Qnil == pi->options.hash_class) {
|
|
117
|
+
stack_pair_push(&pi->stack, oj_calc_hash_key(pi, parent), rstr);
|
|
118
|
+
parent->pcnt += 2;
|
|
119
|
+
} else {
|
|
120
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rstr);
|
|
121
|
+
}
|
|
94
122
|
TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
|
|
95
123
|
}
|
|
96
124
|
|
|
@@ -101,12 +129,22 @@ static void hash_set_num(ParseInfo pi, Val parent, NumInfo ni) {
|
|
|
101
129
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number or other value");
|
|
102
130
|
}
|
|
103
131
|
v = oj_num_as_value(ni);
|
|
104
|
-
|
|
132
|
+
if (Qnil == pi->options.hash_class) {
|
|
133
|
+
stack_pair_push(&pi->stack, oj_calc_hash_key(pi, parent), v);
|
|
134
|
+
parent->pcnt += 2;
|
|
135
|
+
} else {
|
|
136
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), v);
|
|
137
|
+
}
|
|
105
138
|
TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, v);
|
|
106
139
|
}
|
|
107
140
|
|
|
108
141
|
static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
109
|
-
|
|
142
|
+
if (Qnil == pi->options.hash_class) {
|
|
143
|
+
stack_pair_push(&pi->stack, oj_calc_hash_key(pi, parent), value);
|
|
144
|
+
parent->pcnt += 2;
|
|
145
|
+
} else {
|
|
146
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
|
|
147
|
+
}
|
|
110
148
|
TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
|
|
111
149
|
}
|
|
112
150
|
|
data/ext/oj/string_writer.c
CHANGED
|
@@ -169,6 +169,11 @@ void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
|
|
|
169
169
|
*out->cur++ = ':';
|
|
170
170
|
}
|
|
171
171
|
}
|
|
172
|
+
if (NULL != out->circ_cache) {
|
|
173
|
+
oj_cache8_delete(out->circ_cache);
|
|
174
|
+
out->circ_cache = NULL;
|
|
175
|
+
}
|
|
176
|
+
out->circ_cnt = 0;
|
|
172
177
|
switch (out->opts->mode) {
|
|
173
178
|
case StrictMode: oj_dump_strict_val(val, sw->depth, out); break;
|
|
174
179
|
case NullMode: oj_dump_null_val(val, sw->depth, out); break;
|
|
@@ -178,6 +183,10 @@ void oj_str_writer_push_value(StrWriter sw, VALUE val, const char *key) {
|
|
|
178
183
|
case CustomMode: oj_dump_custom_val(val, sw->depth, out, true); break;
|
|
179
184
|
default: oj_dump_custom_val(val, sw->depth, out, true); break;
|
|
180
185
|
}
|
|
186
|
+
if (NULL != out->circ_cache) {
|
|
187
|
+
oj_cache8_delete(out->circ_cache);
|
|
188
|
+
out->circ_cache = NULL;
|
|
189
|
+
}
|
|
181
190
|
}
|
|
182
191
|
|
|
183
192
|
void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
|
|
@@ -203,16 +212,17 @@ void oj_str_writer_push_json(StrWriter sw, const char *json, const char *key) {
|
|
|
203
212
|
|
|
204
213
|
void oj_str_writer_pop(StrWriter sw) {
|
|
205
214
|
long size;
|
|
206
|
-
DumpType type
|
|
215
|
+
DumpType type;
|
|
207
216
|
|
|
208
217
|
if (sw->keyWritten) {
|
|
209
218
|
sw->keyWritten = 0;
|
|
210
219
|
rb_raise(rb_eStandardError, "Can not pop after writing a key but no value.");
|
|
211
220
|
}
|
|
212
|
-
sw->depth
|
|
213
|
-
if (0 > sw->depth) {
|
|
221
|
+
if (0 >= sw->depth) {
|
|
214
222
|
rb_raise(rb_eStandardError, "Can not pop with no open array or object.");
|
|
215
223
|
}
|
|
224
|
+
type = sw->types[sw->depth];
|
|
225
|
+
sw->depth--;
|
|
216
226
|
size = sw->depth * sw->out.indent + 2;
|
|
217
227
|
assure_size(&sw->out, size);
|
|
218
228
|
fill_indent(&sw->out, sw->depth);
|
|
@@ -241,6 +251,10 @@ static void string_writer_free(void *ptr) {
|
|
|
241
251
|
}
|
|
242
252
|
sw = (StrWriter)ptr;
|
|
243
253
|
|
|
254
|
+
if (NULL != sw->out.circ_cache) {
|
|
255
|
+
oj_cache8_delete(sw->out.circ_cache);
|
|
256
|
+
sw->out.circ_cache = NULL;
|
|
257
|
+
}
|
|
244
258
|
oj_out_free(&sw->out);
|
|
245
259
|
oj_options_release(&sw->opts);
|
|
246
260
|
|
data/ext/oj/usual.c
CHANGED
|
@@ -49,7 +49,12 @@ static VALUE form_str(const char *str, size_t len) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
static VALUE form_sym(const char *str, size_t len) {
|
|
52
|
-
|
|
52
|
+
VALUE sym = rb_check_symbol_cstr(str, (long)len, oj_utf8_encoding);
|
|
53
|
+
|
|
54
|
+
if (Qnil == sym) {
|
|
55
|
+
sym = rb_str_intern(rb_utf8_str_new(str, len));
|
|
56
|
+
}
|
|
57
|
+
return sym;
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
static VALUE form_attr(const char *str, size_t len) {
|
|
@@ -80,6 +85,9 @@ static VALUE resolve_classname(VALUE mod, const char *classname, bool auto_defin
|
|
|
80
85
|
|
|
81
86
|
if (rb_const_defined_at(mod, ci)) {
|
|
82
87
|
clas = rb_const_get_at(mod, ci);
|
|
88
|
+
if (!RB_TYPE_P(clas, T_CLASS) && !RB_TYPE_P(clas, T_MODULE)) {
|
|
89
|
+
clas = Qundef;
|
|
90
|
+
}
|
|
83
91
|
} else if (auto_define) {
|
|
84
92
|
clas = rb_define_class_under(mod, classname, oj_bag_class);
|
|
85
93
|
} else {
|
|
@@ -172,9 +180,9 @@ static VALUE str_key(ojParser p, Key kp) {
|
|
|
172
180
|
|
|
173
181
|
static VALUE sym_key(ojParser p, Key kp) {
|
|
174
182
|
if ((size_t)kp->len < sizeof(kp->buf)) {
|
|
175
|
-
return
|
|
183
|
+
return form_sym(kp->buf, kp->len);
|
|
176
184
|
}
|
|
177
|
-
return
|
|
185
|
+
return form_sym(kp->key, kp->len);
|
|
178
186
|
}
|
|
179
187
|
|
|
180
188
|
static ID get_attr_id(ojParser p, Key kp) {
|
|
@@ -809,7 +817,7 @@ static VALUE opt_class_cache_set(ojParser p, VALUE value) {
|
|
|
809
817
|
|
|
810
818
|
if (Qtrue == value) {
|
|
811
819
|
if (NULL == d->class_cache) {
|
|
812
|
-
d->class_cache = cache_create(0, form_class_auto,
|
|
820
|
+
d->class_cache = cache_create(0, form_class_auto, true, false);
|
|
813
821
|
}
|
|
814
822
|
} else if (NULL != d->class_cache) {
|
|
815
823
|
cache_free(d->class_cache);
|
data/ext/oj/val_stack.c
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
#include "val_stack.h"
|
|
5
5
|
|
|
6
|
-
#include <string.h>
|
|
7
|
-
|
|
8
6
|
#include "odd.h"
|
|
9
7
|
#include "oj.h"
|
|
10
8
|
|
|
@@ -15,12 +13,13 @@ static void stack_mark(void *ptr) {
|
|
|
15
13
|
if (NULL == ptr) {
|
|
16
14
|
return;
|
|
17
15
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
{
|
|
17
|
+
size_t i;
|
|
18
|
+
|
|
19
|
+
for (i = 0; i < stack->pcnt; i++) {
|
|
20
|
+
rb_gc_mark(stack->pairs[i]);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
24
23
|
for (v = stack->head; v < stack->tail; v++) {
|
|
25
24
|
if (Qnil != v->val && Qundef != v->val) {
|
|
26
25
|
rb_gc_mark(v->val);
|
|
@@ -39,11 +38,6 @@ static void stack_mark(void *ptr) {
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
|
43
|
-
pthread_mutex_unlock(&stack->mutex);
|
|
44
|
-
#else
|
|
45
|
-
rb_mutex_unlock(stack->mutex);
|
|
46
|
-
#endif
|
|
47
41
|
}
|
|
48
42
|
|
|
49
43
|
static const rb_data_type_t oj_stack_type = {
|
|
@@ -59,18 +53,12 @@ static const rb_data_type_t oj_stack_type = {
|
|
|
59
53
|
|
|
60
54
|
VALUE
|
|
61
55
|
oj_stack_init(ValStack stack) {
|
|
62
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
|
63
|
-
int err;
|
|
64
|
-
|
|
65
|
-
if (0 != (err = pthread_mutex_init(&stack->mutex, 0))) {
|
|
66
|
-
rb_raise(rb_eException, "failed to initialize a mutex. %s", strerror(err));
|
|
67
|
-
}
|
|
68
|
-
#else
|
|
69
|
-
stack->mutex = rb_mutex_new();
|
|
70
|
-
#endif
|
|
71
56
|
stack->head = stack->base;
|
|
72
57
|
stack->end = stack->base + sizeof(stack->base) / sizeof(struct _val);
|
|
73
58
|
stack->tail = stack->head;
|
|
59
|
+
stack->pairs = stack->pbase;
|
|
60
|
+
stack->pcnt = 0;
|
|
61
|
+
stack->pend = sizeof(stack->pbase) / sizeof(VALUE);
|
|
74
62
|
stack->head->val = Qundef;
|
|
75
63
|
stack->head->key = NULL;
|
|
76
64
|
stack->head->key_val = Qundef;
|
|
@@ -79,6 +67,7 @@ oj_stack_init(ValStack stack) {
|
|
|
79
67
|
stack->head->clas = Qundef;
|
|
80
68
|
stack->head->klen = 0;
|
|
81
69
|
stack->head->clen = 0;
|
|
70
|
+
stack->head->pcnt = 0;
|
|
82
71
|
stack->head->next = NEXT_NONE;
|
|
83
72
|
|
|
84
73
|
return TypedData_Wrap_Struct(oj_cstack_class, &oj_stack_type, stack);
|
data/ext/oj/val_stack.h
CHANGED
|
@@ -9,9 +9,6 @@
|
|
|
9
9
|
#include "mem.h"
|
|
10
10
|
#include "odd.h"
|
|
11
11
|
#include "ruby.h"
|
|
12
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
|
13
|
-
#include <pthread.h>
|
|
14
|
-
#endif
|
|
15
12
|
|
|
16
13
|
#define STACK_INC 64
|
|
17
14
|
|
|
@@ -37,22 +34,27 @@ typedef struct _val {
|
|
|
37
34
|
OddArgs odd_args;
|
|
38
35
|
size_t klen;
|
|
39
36
|
size_t clen;
|
|
37
|
+
size_t pcnt; // VALUEs this open hash holds in the stack pair buffer
|
|
40
38
|
char next; // ValNext
|
|
41
39
|
char k1; // first original character in the key
|
|
42
40
|
char kalloc;
|
|
43
41
|
} *Val;
|
|
44
42
|
|
|
43
|
+
#define PAIR_BASE_CNT 64
|
|
44
|
+
|
|
45
45
|
typedef struct _valStack {
|
|
46
46
|
struct _val base[STACK_INC];
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
47
|
+
VALUE pbase[PAIR_BASE_CNT]; // initial buffer for pairs
|
|
48
|
+
// Flat key/value pair buffer for hash modes that build each Hash in one
|
|
49
|
+
// rb_hash_bulk_insert at the closing brace instead of one rb_hash_aset
|
|
50
|
+
// per pair. Nesting is strictly LIFO so each open hash's pairs occupy
|
|
51
|
+
// the top of the buffer; the per-hash count lives in its Val's clen.
|
|
52
|
+
VALUE *pairs;
|
|
53
|
+
size_t pcnt; // number of live VALUEs in pairs
|
|
54
|
+
size_t pend; // capacity of pairs in VALUEs
|
|
55
|
+
Val head; // current stack
|
|
56
|
+
Val end; // stack end
|
|
57
|
+
Val tail; // pointer to one past last element name on stack
|
|
56
58
|
} *ValStack;
|
|
57
59
|
|
|
58
60
|
extern VALUE oj_stack_init(ValStack stack);
|
|
@@ -76,6 +78,11 @@ inline static void stack_cleanup(ValStack stack) {
|
|
|
76
78
|
OJ_R_FREE(stack->head);
|
|
77
79
|
stack->head = NULL;
|
|
78
80
|
}
|
|
81
|
+
if (stack->pbase != stack->pairs) {
|
|
82
|
+
OJ_R_FREE(stack->pairs);
|
|
83
|
+
stack->pairs = NULL;
|
|
84
|
+
}
|
|
85
|
+
stack->pcnt = 0;
|
|
79
86
|
}
|
|
80
87
|
|
|
81
88
|
inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
|
|
@@ -86,8 +93,8 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
|
|
|
86
93
|
const char *old = (const char *)stack->head;
|
|
87
94
|
size_t i;
|
|
88
95
|
|
|
89
|
-
// A realloc can trigger a GC
|
|
90
|
-
//
|
|
96
|
+
// A realloc can trigger a GC that marks the stack, so change the
|
|
97
|
+
// pointers only after it returns.
|
|
91
98
|
if (stack->base == stack->head) {
|
|
92
99
|
head = OJ_R_ALLOC_N(struct _val, len + STACK_INC);
|
|
93
100
|
memcpy(head, stack->base, sizeof(struct _val) * len);
|
|
@@ -101,19 +108,9 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
|
|
|
101
108
|
head[i].key = head[i].karray;
|
|
102
109
|
}
|
|
103
110
|
}
|
|
104
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
|
105
|
-
pthread_mutex_lock(&stack->mutex);
|
|
106
|
-
#else
|
|
107
|
-
rb_mutex_lock(stack->mutex);
|
|
108
|
-
#endif
|
|
109
111
|
stack->head = head;
|
|
110
112
|
stack->tail = stack->head + toff;
|
|
111
113
|
stack->end = stack->head + len + STACK_INC;
|
|
112
|
-
#ifdef HAVE_PTHREAD_MUTEX_INIT
|
|
113
|
-
pthread_mutex_unlock(&stack->mutex);
|
|
114
|
-
#else
|
|
115
|
-
rb_mutex_unlock(stack->mutex);
|
|
116
|
-
#endif
|
|
117
114
|
}
|
|
118
115
|
stack->tail->val = val;
|
|
119
116
|
stack->tail->next = next;
|
|
@@ -124,6 +121,7 @@ inline static void stack_push(ValStack stack, VALUE val, ValNext next) {
|
|
|
124
121
|
stack->tail->key_val = Qundef;
|
|
125
122
|
stack->tail->clen = 0;
|
|
126
123
|
stack->tail->klen = 0;
|
|
124
|
+
stack->tail->pcnt = 0;
|
|
127
125
|
stack->tail->kalloc = 0;
|
|
128
126
|
stack->tail++;
|
|
129
127
|
}
|
|
@@ -165,6 +163,29 @@ inline static Val stack_pop(ValStack stack) {
|
|
|
165
163
|
return 0;
|
|
166
164
|
}
|
|
167
165
|
|
|
166
|
+
// Append one key/value pair to the pair buffer. The same GC discipline as
|
|
167
|
+
// stack_push: the allocation can trigger a GC that marks the pairs, so the
|
|
168
|
+
// buffer pointer only changes after it returns.
|
|
169
|
+
inline static void stack_pair_push(ValStack stack, VALUE key, VALUE value) {
|
|
170
|
+
if (stack->pend <= stack->pcnt + 2) {
|
|
171
|
+
size_t cnt = stack->pend * 2;
|
|
172
|
+
VALUE *pairs;
|
|
173
|
+
|
|
174
|
+
if (stack->pbase == stack->pairs) {
|
|
175
|
+
pairs = OJ_R_ALLOC_N(VALUE, cnt);
|
|
176
|
+
memcpy(pairs, stack->pairs, sizeof(VALUE) * stack->pcnt);
|
|
177
|
+
} else {
|
|
178
|
+
pairs = stack->pairs;
|
|
179
|
+
OJ_R_REALLOC_N(pairs, VALUE, cnt);
|
|
180
|
+
}
|
|
181
|
+
stack->pairs = pairs;
|
|
182
|
+
stack->pend = cnt;
|
|
183
|
+
}
|
|
184
|
+
stack->pairs[stack->pcnt] = key;
|
|
185
|
+
stack->pairs[stack->pcnt + 1] = value;
|
|
186
|
+
stack->pcnt += 2;
|
|
187
|
+
}
|
|
188
|
+
|
|
168
189
|
extern const char *oj_stack_next_string(ValNext n);
|
|
169
190
|
|
|
170
191
|
#endif /* OJ_VAL_STACK_H */
|
data/ext/oj/wab.c
CHANGED
|
@@ -40,6 +40,7 @@ static VALUE resolve_wab_uuid_class(void) {
|
|
|
40
40
|
volatile VALUE wab_module;
|
|
41
41
|
|
|
42
42
|
wab_uuid_clas = Qnil;
|
|
43
|
+
rb_gc_register_address(&wab_uuid_clas);
|
|
43
44
|
if (rb_const_defined_at(rb_cObject, rb_intern("WAB"))) {
|
|
44
45
|
wab_module = rb_const_get_at(rb_cObject, rb_intern("WAB"));
|
|
45
46
|
if (rb_const_defined_at(wab_module, rb_intern("UUID"))) {
|
|
@@ -53,6 +54,7 @@ static VALUE resolve_wab_uuid_class(void) {
|
|
|
53
54
|
static VALUE resolve_uri_class(void) {
|
|
54
55
|
if (Qundef == uri_clas) {
|
|
55
56
|
uri_clas = Qnil;
|
|
57
|
+
rb_gc_register_address(&uri_clas);
|
|
56
58
|
if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
|
|
57
59
|
uri_clas = rb_const_get_at(rb_cObject, rb_intern("URI"));
|
|
58
60
|
}
|
|
@@ -65,6 +67,7 @@ static VALUE resolve_uri_http_class(void) {
|
|
|
65
67
|
volatile VALUE uri_module;
|
|
66
68
|
|
|
67
69
|
uri_http_clas = Qnil;
|
|
70
|
+
rb_gc_register_address(&uri_http_clas);
|
|
68
71
|
if (rb_const_defined_at(rb_cObject, rb_intern("URI"))) {
|
|
69
72
|
uri_module = rb_const_get_at(rb_cObject, rb_intern("URI"));
|
|
70
73
|
if (rb_const_defined_at(uri_module, rb_intern("HTTP"))) {
|