oj 3.10.6 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +6 -1
- data/ext/oj/buf.h +36 -68
- data/ext/oj/cache8.c +59 -62
- data/ext/oj/cache8.h +9 -36
- data/ext/oj/circarray.c +36 -42
- data/ext/oj/circarray.h +12 -13
- data/ext/oj/code.c +172 -179
- data/ext/oj/code.h +22 -24
- data/ext/oj/compat.c +168 -181
- data/ext/oj/custom.c +800 -864
- data/ext/oj/dump.c +774 -776
- data/ext/oj/dump.h +50 -55
- data/ext/oj/dump_compat.c +2 -4
- data/ext/oj/dump_leaf.c +118 -162
- data/ext/oj/dump_object.c +610 -632
- data/ext/oj/dump_strict.c +319 -331
- data/ext/oj/encode.h +4 -33
- data/ext/oj/err.c +40 -29
- data/ext/oj/err.h +25 -44
- data/ext/oj/extconf.rb +2 -1
- data/ext/oj/fast.c +1054 -1081
- data/ext/oj/hash.c +78 -95
- data/ext/oj/hash.h +10 -35
- data/ext/oj/hash_test.c +451 -472
- data/ext/oj/mimic_json.c +415 -402
- data/ext/oj/object.c +588 -532
- data/ext/oj/odd.c +124 -132
- data/ext/oj/odd.h +28 -29
- data/ext/oj/oj.c +1178 -905
- data/ext/oj/oj.h +289 -298
- data/ext/oj/parse.c +946 -870
- data/ext/oj/parse.h +81 -79
- data/ext/oj/rails.c +837 -842
- data/ext/oj/rails.h +8 -11
- data/ext/oj/reader.c +139 -147
- data/ext/oj/reader.h +68 -84
- data/ext/oj/resolve.c +44 -47
- data/ext/oj/resolve.h +4 -6
- data/ext/oj/rxclass.c +69 -73
- data/ext/oj/rxclass.h +13 -14
- data/ext/oj/saj.c +453 -484
- data/ext/oj/scp.c +88 -113
- data/ext/oj/sparse.c +783 -714
- data/ext/oj/stream_writer.c +123 -157
- data/ext/oj/strict.c +133 -106
- data/ext/oj/string_writer.c +199 -247
- data/ext/oj/trace.c +34 -41
- data/ext/oj/trace.h +15 -15
- data/ext/oj/util.c +104 -104
- data/ext/oj/util.h +4 -3
- data/ext/oj/val_stack.c +48 -76
- data/ext/oj/val_stack.h +80 -115
- data/ext/oj/wab.c +317 -328
- data/lib/oj.rb +0 -8
- data/lib/oj/bag.rb +1 -0
- data/lib/oj/easy_hash.rb +5 -4
- data/lib/oj/mimic.rb +45 -13
- data/lib/oj/version.rb +1 -1
- data/pages/Modes.md +1 -0
- data/pages/Options.md +23 -11
- data/test/activerecord/result_test.rb +7 -2
- data/test/foo.rb +8 -40
- data/test/helper.rb +10 -0
- data/test/json_gem/json_common_interface_test.rb +8 -3
- data/test/json_gem/json_generator_test.rb +15 -3
- data/test/json_gem/test_helper.rb +8 -0
- data/test/perf.rb +1 -1
- data/test/perf_scp.rb +11 -10
- data/test/perf_strict.rb +17 -23
- data/test/prec.rb +23 -0
- data/test/sample_json.rb +1 -1
- data/test/test_compat.rb +16 -3
- data/test/test_custom.rb +11 -0
- data/test/test_fast.rb +32 -2
- data/test/test_generate.rb +21 -0
- data/test/test_hash.rb +10 -0
- data/test/test_rails.rb +9 -0
- data/test/test_scp.rb +1 -1
- data/test/test_various.rb +4 -2
- metadata +89 -85
data/ext/oj/compat.c
CHANGED
@@ -1,298 +1,285 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
* All rights reserved.
|
4
|
-
*/
|
1
|
+
// Copyright (c) 2012 Peter Ohler. All rights reserved.
|
2
|
+
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
5
3
|
|
6
4
|
#include <stdio.h>
|
7
5
|
|
8
|
-
#include "
|
6
|
+
#include "encode.h"
|
9
7
|
#include "err.h"
|
8
|
+
#include "hash.h"
|
9
|
+
#include "oj.h"
|
10
10
|
#include "parse.h"
|
11
11
|
#include "resolve.h"
|
12
|
-
#include "hash.h"
|
13
|
-
#include "encode.h"
|
14
12
|
#include "trace.h"
|
15
13
|
|
16
|
-
static void
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
(int)pi->options.create_id_len == klen &&
|
28
|
-
0 == strncmp(pi->options.create_id, key, klen)) {
|
29
|
-
|
30
|
-
parent->classname = oj_strndup(str, len);
|
31
|
-
parent->clen = len;
|
14
|
+
static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
|
15
|
+
const char * key = kval->key;
|
16
|
+
int klen = kval->klen;
|
17
|
+
Val parent = stack_peek(&pi->stack);
|
18
|
+
volatile VALUE rkey = kval->key_val;
|
19
|
+
|
20
|
+
if (Qundef == rkey && Yes == pi->options.create_ok && NULL != pi->options.create_id &&
|
21
|
+
*pi->options.create_id == *key && (int)pi->options.create_id_len == klen &&
|
22
|
+
0 == strncmp(pi->options.create_id, key, klen)) {
|
23
|
+
parent->classname = oj_strndup(str, len);
|
24
|
+
parent->clen = len;
|
32
25
|
} else {
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
26
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
27
|
+
|
28
|
+
if (Qundef == rkey) {
|
29
|
+
VALUE *slot;
|
30
|
+
|
31
|
+
if (Yes == pi->options.sym_key) {
|
32
|
+
if (Qnil == (rkey = oj_sym_hash_get(key, klen, &slot))) {
|
33
|
+
rkey = rb_str_new(key, klen);
|
34
|
+
rkey = oj_encode(rkey);
|
35
|
+
rkey = rb_str_intern(rkey);
|
36
|
+
*slot = rkey;
|
37
|
+
rb_gc_register_address(slot);
|
38
|
+
}
|
39
|
+
} else {
|
40
|
+
if (Qnil == (rkey = oj_str_hash_get(key, klen, &slot))) {
|
41
|
+
rkey = rb_str_new(key, klen);
|
42
|
+
rkey = oj_encode(rkey);
|
43
|
+
*slot = rkey;
|
44
|
+
rb_gc_register_address(slot);
|
45
|
+
}
|
46
|
+
}
|
47
|
+
}
|
48
|
+
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
49
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
50
|
+
|
51
|
+
if (Qnil != clas) {
|
52
|
+
rstr = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
53
|
+
}
|
54
|
+
}
|
55
|
+
if (rb_cHash != rb_obj_class(parent->val)) {
|
56
|
+
// The rb_hash_set would still work but the unit tests for the
|
57
|
+
// json gem require the less efficient []= method be called to set
|
58
|
+
// values. Even using the store method to set the values will fail
|
59
|
+
// the unit tests.
|
60
|
+
rb_funcall(parent->val, rb_intern("[]="), 2, rkey, rstr);
|
61
|
+
} else {
|
62
|
+
rb_hash_aset(parent->val, rkey, rstr);
|
63
|
+
}
|
64
|
+
if (Yes == pi->options.trace) {
|
65
|
+
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
66
|
+
}
|
62
67
|
}
|
63
68
|
}
|
64
69
|
|
65
|
-
static VALUE
|
66
|
-
|
67
|
-
volatile VALUE h;
|
70
|
+
static VALUE start_hash(ParseInfo pi) {
|
71
|
+
volatile VALUE h;
|
68
72
|
|
69
73
|
if (Qnil != pi->options.hash_class) {
|
70
|
-
|
74
|
+
h = rb_class_new_instance(0, NULL, pi->options.hash_class);
|
71
75
|
} else {
|
72
|
-
|
76
|
+
h = rb_hash_new();
|
73
77
|
}
|
74
78
|
if (Yes == pi->options.trace) {
|
75
|
-
|
79
|
+
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
76
80
|
}
|
77
81
|
return h;
|
78
82
|
}
|
79
83
|
|
80
|
-
static void
|
81
|
-
|
82
|
-
Val parent = stack_peek(&pi->stack);
|
84
|
+
static void end_hash(struct _parseInfo *pi) {
|
85
|
+
Val parent = stack_peek(&pi->stack);
|
83
86
|
|
84
87
|
if (0 != parent->classname) {
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
88
|
+
volatile VALUE clas;
|
89
|
+
|
90
|
+
clas = oj_name2class(pi, parent->classname, parent->clen, 0, rb_eArgError);
|
91
|
+
if (Qundef != clas) { // else an error
|
92
|
+
ID creatable = rb_intern("json_creatable?");
|
93
|
+
|
94
|
+
if (!rb_respond_to(clas, creatable) || Qtrue == rb_funcall(clas, creatable, 0)) {
|
95
|
+
parent->val = rb_funcall(clas, oj_json_create_id, 1, parent->val);
|
96
|
+
}
|
97
|
+
}
|
98
|
+
if (0 != parent->classname) {
|
99
|
+
xfree((char *)parent->classname);
|
100
|
+
parent->classname = 0;
|
101
|
+
}
|
99
102
|
}
|
100
103
|
if (Yes == pi->options.trace) {
|
101
|
-
|
104
|
+
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
102
105
|
}
|
103
106
|
}
|
104
107
|
|
105
|
-
static
|
106
|
-
|
107
|
-
volatile VALUE rkey = parent->key_val;
|
108
|
+
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
109
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
108
110
|
|
109
|
-
if (Qundef == rkey) {
|
110
|
-
rkey = rb_str_new(parent->key, parent->klen);
|
111
|
-
}
|
112
|
-
rkey = oj_encode(rkey);
|
113
|
-
if (Yes == pi->options.sym_key) {
|
114
|
-
rkey = rb_str_intern(rkey);
|
115
|
-
}
|
116
|
-
return rkey;
|
117
|
-
}
|
118
|
-
|
119
|
-
static void
|
120
|
-
add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
121
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
122
|
-
|
123
|
-
rstr = oj_encode(rstr);
|
124
111
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
125
|
-
|
112
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
126
113
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
114
|
+
if (Qnil != clas) {
|
115
|
+
pi->stack.head->val = rb_funcall(clas, oj_json_create_id, 1, rstr);
|
116
|
+
return;
|
117
|
+
}
|
131
118
|
}
|
132
119
|
pi->stack.head->val = rstr;
|
133
120
|
if (Yes == pi->options.trace) {
|
134
|
-
|
121
|
+
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
135
122
|
}
|
136
123
|
}
|
137
124
|
|
138
|
-
static void
|
139
|
-
add_num(ParseInfo pi, NumInfo ni) {
|
125
|
+
static void add_num(ParseInfo pi, NumInfo ni) {
|
140
126
|
pi->stack.head->val = oj_num_as_value(ni);
|
141
127
|
if (Yes == pi->options.trace) {
|
142
|
-
|
128
|
+
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
143
129
|
}
|
144
130
|
}
|
145
131
|
|
146
|
-
static void
|
147
|
-
|
148
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
132
|
+
static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
|
133
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
149
134
|
|
150
135
|
if (!oj_use_hash_alt && rb_cHash != rb_obj_class(parent->val)) {
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
136
|
+
// The rb_hash_set would still work but the unit tests for the
|
137
|
+
// json gem require the less efficient []= method be called to set
|
138
|
+
// values. Even using the store method to set the values will fail
|
139
|
+
// the unit tests.
|
140
|
+
rb_funcall(stack_peek(&pi->stack)->val,
|
141
|
+
rb_intern("[]="),
|
142
|
+
2,
|
143
|
+
oj_calc_hash_key(pi, parent),
|
144
|
+
rval);
|
156
145
|
} else {
|
157
|
-
|
146
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
|
158
147
|
}
|
159
148
|
if (Yes == pi->options.trace) {
|
160
|
-
|
149
|
+
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
161
150
|
}
|
162
151
|
}
|
163
152
|
|
164
|
-
static void
|
165
|
-
hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
153
|
+
static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
166
154
|
if (rb_cHash != rb_obj_class(parent->val)) {
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
155
|
+
// The rb_hash_set would still work but the unit tests for the
|
156
|
+
// json gem require the less efficient []= method be called to set
|
157
|
+
// values. Even using the store method to set the values will fail
|
158
|
+
// the unit tests.
|
159
|
+
rb_funcall(stack_peek(&pi->stack)->val,
|
160
|
+
rb_intern("[]="),
|
161
|
+
2,
|
162
|
+
oj_calc_hash_key(pi, parent),
|
163
|
+
value);
|
172
164
|
} else {
|
173
|
-
|
165
|
+
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
|
174
166
|
}
|
175
167
|
if (Yes == pi->options.trace) {
|
176
|
-
|
168
|
+
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
177
169
|
}
|
178
170
|
}
|
179
171
|
|
180
|
-
static VALUE
|
181
|
-
start_array(ParseInfo pi) {
|
172
|
+
static VALUE start_array(ParseInfo pi) {
|
182
173
|
if (Qnil != pi->options.array_class) {
|
183
|
-
|
174
|
+
return rb_class_new_instance(0, NULL, pi->options.array_class);
|
184
175
|
}
|
185
176
|
if (Yes == pi->options.trace) {
|
186
|
-
|
177
|
+
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
187
178
|
}
|
188
179
|
return rb_ary_new();
|
189
180
|
}
|
190
181
|
|
191
|
-
static void
|
192
|
-
|
193
|
-
|
194
|
-
volatile VALUE rval = oj_num_as_value(ni);
|
182
|
+
static void array_append_num(ParseInfo pi, NumInfo ni) {
|
183
|
+
Val parent = stack_peek(&pi->stack);
|
184
|
+
volatile VALUE rval = oj_num_as_value(ni);
|
195
185
|
|
196
186
|
if (!oj_use_array_alt && rb_cArray != rb_obj_class(parent->val)) {
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
187
|
+
// The rb_ary_push would still work but the unit tests for the json
|
188
|
+
// gem require the less efficient << method be called to push the
|
189
|
+
// values.
|
190
|
+
rb_funcall(parent->val, rb_intern("<<"), 1, rval);
|
201
191
|
} else {
|
202
|
-
|
192
|
+
rb_ary_push(parent->val, rval);
|
203
193
|
}
|
204
194
|
if (Yes == pi->options.trace) {
|
205
|
-
|
195
|
+
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
206
196
|
}
|
207
197
|
}
|
208
198
|
|
209
|
-
static void
|
210
|
-
|
211
|
-
volatile VALUE rstr = rb_str_new(str, len);
|
199
|
+
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
200
|
+
volatile VALUE rstr = oj_cstr_to_value(str, len, (size_t)pi->options.cache_str);
|
212
201
|
|
213
|
-
rstr = oj_encode(rstr);
|
214
202
|
if (Yes == pi->options.create_ok && NULL != pi->options.str_rx.head) {
|
215
|
-
|
203
|
+
VALUE clas = oj_rxclass_match(&pi->options.str_rx, str, (int)len);
|
216
204
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
205
|
+
if (Qnil != clas) {
|
206
|
+
rb_ary_push(stack_peek(&pi->stack)->val, rb_funcall(clas, oj_json_create_id, 1, rstr));
|
207
|
+
return;
|
208
|
+
}
|
221
209
|
}
|
222
210
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
223
211
|
if (Yes == pi->options.trace) {
|
224
|
-
|
212
|
+
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
225
213
|
}
|
226
214
|
}
|
227
215
|
|
228
|
-
void
|
229
|
-
oj_set_compat_callbacks(ParseInfo pi) {
|
216
|
+
void oj_set_compat_callbacks(ParseInfo pi) {
|
230
217
|
oj_set_strict_callbacks(pi);
|
231
|
-
pi->start_hash
|
232
|
-
pi->end_hash
|
233
|
-
pi->hash_set_cstr
|
234
|
-
pi->hash_set_num
|
235
|
-
pi->hash_set_value
|
236
|
-
pi->add_num
|
237
|
-
pi->add_cstr
|
218
|
+
pi->start_hash = start_hash;
|
219
|
+
pi->end_hash = end_hash;
|
220
|
+
pi->hash_set_cstr = hash_set_cstr;
|
221
|
+
pi->hash_set_num = hash_set_num;
|
222
|
+
pi->hash_set_value = hash_set_value;
|
223
|
+
pi->add_num = add_num;
|
224
|
+
pi->add_cstr = add_cstr;
|
238
225
|
pi->array_append_cstr = array_append_cstr;
|
239
|
-
pi->start_array
|
240
|
-
pi->array_append_num
|
226
|
+
pi->start_array = start_array;
|
227
|
+
pi->array_append_num = array_append_num;
|
241
228
|
}
|
242
229
|
|
243
230
|
VALUE
|
244
231
|
oj_compat_parse(int argc, VALUE *argv, VALUE self) {
|
245
|
-
struct _parseInfo
|
232
|
+
struct _parseInfo pi;
|
246
233
|
|
247
234
|
parse_info_init(&pi);
|
248
|
-
pi.options
|
249
|
-
pi.handler
|
250
|
-
pi.err_class
|
251
|
-
pi.max_depth
|
252
|
-
pi.options.allow_nan
|
253
|
-
pi.options.nilnil
|
235
|
+
pi.options = oj_default_options;
|
236
|
+
pi.handler = Qnil;
|
237
|
+
pi.err_class = Qnil;
|
238
|
+
pi.max_depth = 0;
|
239
|
+
pi.options.allow_nan = Yes;
|
240
|
+
pi.options.nilnil = Yes;
|
254
241
|
pi.options.empty_string = No;
|
255
242
|
oj_set_compat_callbacks(&pi);
|
256
243
|
|
257
244
|
if (T_STRING == rb_type(*argv)) {
|
258
|
-
|
245
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
259
246
|
} else {
|
260
|
-
|
247
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
261
248
|
}
|
262
249
|
}
|
263
250
|
|
264
251
|
VALUE
|
265
252
|
oj_compat_load(int argc, VALUE *argv, VALUE self) {
|
266
|
-
struct _parseInfo
|
253
|
+
struct _parseInfo pi;
|
267
254
|
|
268
255
|
parse_info_init(&pi);
|
269
|
-
pi.options
|
270
|
-
pi.handler
|
271
|
-
pi.err_class
|
272
|
-
pi.max_depth
|
273
|
-
pi.options.allow_nan
|
274
|
-
pi.options.nilnil
|
256
|
+
pi.options = oj_default_options;
|
257
|
+
pi.handler = Qnil;
|
258
|
+
pi.err_class = Qnil;
|
259
|
+
pi.max_depth = 0;
|
260
|
+
pi.options.allow_nan = Yes;
|
261
|
+
pi.options.nilnil = Yes;
|
275
262
|
pi.options.empty_string = Yes;
|
276
263
|
oj_set_compat_callbacks(&pi);
|
277
264
|
|
278
265
|
if (T_STRING == rb_type(*argv)) {
|
279
|
-
|
266
|
+
return oj_pi_parse(argc, argv, &pi, 0, 0, false);
|
280
267
|
} else {
|
281
|
-
|
268
|
+
return oj_pi_sparse(argc, argv, &pi, 0);
|
282
269
|
}
|
283
270
|
}
|
284
271
|
|
285
272
|
VALUE
|
286
273
|
oj_compat_parse_cstr(int argc, VALUE *argv, char *json, size_t len) {
|
287
|
-
struct _parseInfo
|
274
|
+
struct _parseInfo pi;
|
288
275
|
|
289
276
|
parse_info_init(&pi);
|
290
|
-
pi.options
|
291
|
-
pi.handler
|
292
|
-
pi.err_class
|
293
|
-
pi.max_depth
|
277
|
+
pi.options = oj_default_options;
|
278
|
+
pi.handler = Qnil;
|
279
|
+
pi.err_class = Qnil;
|
280
|
+
pi.max_depth = 0;
|
294
281
|
pi.options.allow_nan = Yes;
|
295
|
-
pi.options.nilnil
|
282
|
+
pi.options.nilnil = Yes;
|
296
283
|
oj_set_compat_callbacks(&pi);
|
297
284
|
|
298
285
|
return oj_pi_parse(argc, argv, &pi, json, len, false);
|