oj 3.16.0 → 3.17.3
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 +107 -0
- data/README.md +0 -16
- data/ext/oj/cache.c +4 -2
- data/ext/oj/cache.h +3 -2
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +624 -90
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +15 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +32 -17
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +11 -9
- data/ext/oj/fast.c +50 -32
- data/ext/oj/intern.c +24 -7
- data/ext/oj/mimic_json.c +17 -11
- data/ext/oj/object.c +21 -13
- data/ext/oj/oj.c +387 -140
- data/ext/oj/oj.h +59 -55
- data/ext/oj/parse.c +248 -47
- data/ext/oj/parser.c +179 -89
- data/ext/oj/parser.h +4 -2
- data/ext/oj/rails.c +64 -42
- data/ext/oj/reader.c +1 -1
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +15 -10
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +6 -3
- data/ext/oj/stream_writer.c +38 -28
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +54 -22
- data/ext/oj/usual.c +57 -35
- data/ext/oj/usual.h +1 -0
- data/ext/oj/val_stack.c +13 -2
- data/ext/oj/wab.c +5 -4
- data/lib/oj/mimic.rb +1 -5
- data/lib/oj/schandler.rb +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +36 -100
- data/test/_test_active.rb +0 -75
- data/test/_test_active_mimic.rb +0 -95
- data/test/_test_mimic_rails.rb +0 -123
- data/test/activerecord/result_test.rb +0 -31
- data/test/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -507
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -49
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -486
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -14
- data/test/helper.rb +0 -39
- data/test/isolated/shared.rb +0 -309
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -155
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -21
- data/test/json_gem/json_fixtures_test.rb +0 -36
- data/test/json_gem/json_generator_test.rb +0 -407
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -34
- data/test/perf.rb +0 -102
- data/test/perf_compat.rb +0 -128
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -162
- data/test/perf_file.rb +0 -62
- data/test/perf_object.rb +0 -134
- data/test/perf_once.rb +0 -59
- data/test/perf_parser.rb +0 -183
- data/test/perf_saj.rb +0 -101
- data/test/perf_scp.rb +0 -140
- data/test/perf_simple.rb +0 -289
- data/test/perf_strict.rb +0 -137
- data/test/perf_wab.rb +0 -129
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -13
- data/test/sample/dir.rb +0 -18
- data/test/sample/doc.rb +0 -35
- data/test/sample/file.rb +0 -47
- data/test/sample/group.rb +0 -15
- data/test/sample/hasprops.rb +0 -15
- data/test/sample/layer.rb +0 -11
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -9
- data/test/sample/shape.rb +0 -34
- data/test/sample/text.rb +0 -19
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -567
- data/test/test_custom.rb +0 -554
- data/test/test_debian.rb +0 -50
- data/test/test_fast.rb +0 -526
- data/test/test_file.rb +0 -250
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1016
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -337
- data/test/test_parser_usual.rb +0 -217
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -188
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -431
- data/test/test_various.rb +0 -801
- data/test/test_wab.rb +0 -311
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/dump.h
CHANGED
|
@@ -7,12 +7,17 @@
|
|
|
7
7
|
#include <ruby.h>
|
|
8
8
|
|
|
9
9
|
#include "oj.h"
|
|
10
|
+
#include "simd.h"
|
|
10
11
|
|
|
11
12
|
#define MAX_DEPTH 1000
|
|
12
13
|
|
|
13
14
|
// Extra padding at end of buffer.
|
|
14
15
|
#define BUFFER_EXTRA 64
|
|
15
16
|
|
|
17
|
+
#ifdef HAVE_SIMD_NEON
|
|
18
|
+
extern void initialize_neon(void);
|
|
19
|
+
#endif /* HAVE_SIMD_NEON */
|
|
20
|
+
|
|
16
21
|
extern void oj_dump_nil(VALUE obj, int depth, Out out, bool as_ok);
|
|
17
22
|
extern void oj_dump_true(VALUE obj, int depth, Out out, bool as_ok);
|
|
18
23
|
extern void oj_dump_false(VALUE obj, int depth, Out out, bool as_ok);
|
|
@@ -30,7 +35,7 @@ extern void oj_dump_xml_time(VALUE obj, Out out);
|
|
|
30
35
|
extern void oj_dump_time(VALUE obj, Out out, int withZone);
|
|
31
36
|
extern void oj_dump_obj_to_s(VALUE obj, Out out);
|
|
32
37
|
|
|
33
|
-
extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus,
|
|
38
|
+
extern const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, size_t *lenp);
|
|
34
39
|
|
|
35
40
|
// initialize an out buffer with the provided stack allocated memory
|
|
36
41
|
extern void oj_out_init(Out out);
|
|
@@ -53,10 +58,12 @@ extern void oj_dump_raw_json(VALUE obj, int depth, Out out);
|
|
|
53
58
|
extern VALUE oj_add_to_json(int argc, VALUE *argv, VALUE self);
|
|
54
59
|
extern VALUE oj_remove_to_json(int argc, VALUE *argv, VALUE self);
|
|
55
60
|
|
|
56
|
-
extern
|
|
61
|
+
extern size_t oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format);
|
|
57
62
|
|
|
58
63
|
extern time_t oj_sec_from_time_hard_way(VALUE obj);
|
|
59
64
|
|
|
65
|
+
extern bool oj_key_skip(VALUE key, const char *only, const char *except);
|
|
66
|
+
|
|
60
67
|
inline static void assure_size(Out out, size_t len) {
|
|
61
68
|
if (out->end - out->cur <= (long)len) {
|
|
62
69
|
oj_grow_out(out, len);
|
data/ext/oj/dump_compat.c
CHANGED
|
@@ -103,7 +103,7 @@ static void dump_values_array(VALUE *values, int depth, Out out) {
|
|
|
103
103
|
static void dump_to_json(VALUE obj, Out out) {
|
|
104
104
|
volatile VALUE rs;
|
|
105
105
|
const char *s;
|
|
106
|
-
|
|
106
|
+
size_t len;
|
|
107
107
|
|
|
108
108
|
TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyIn);
|
|
109
109
|
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
|
@@ -115,7 +115,7 @@ static void dump_to_json(VALUE obj, Out out) {
|
|
|
115
115
|
|
|
116
116
|
StringValue(rs);
|
|
117
117
|
s = RSTRING_PTR(rs);
|
|
118
|
-
len =
|
|
118
|
+
len = RSTRING_LEN(rs);
|
|
119
119
|
|
|
120
120
|
assure_size(out, len + 1);
|
|
121
121
|
APPEND_CHARS(out->cur, s, len);
|
|
@@ -124,7 +124,8 @@ static void dump_to_json(VALUE obj, Out out) {
|
|
|
124
124
|
|
|
125
125
|
static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
126
126
|
size_t size;
|
|
127
|
-
|
|
127
|
+
size_t i;
|
|
128
|
+
size_t cnt;
|
|
128
129
|
int d2 = depth + 1;
|
|
129
130
|
long id = oj_check_circular(a, out);
|
|
130
131
|
|
|
@@ -136,7 +137,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
|
136
137
|
dump_to_json(a, out);
|
|
137
138
|
return;
|
|
138
139
|
}
|
|
139
|
-
cnt =
|
|
140
|
+
cnt = RARRAY_LEN(a);
|
|
140
141
|
*out->cur++ = '[';
|
|
141
142
|
assure_size(out, 2);
|
|
142
143
|
if (0 == cnt) {
|
|
@@ -147,10 +148,10 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
|
147
148
|
} else {
|
|
148
149
|
size = d2 * out->indent + 2;
|
|
149
150
|
}
|
|
150
|
-
assure_size(out, size * cnt);
|
|
151
151
|
cnt--;
|
|
152
152
|
for (i = 0; i <= cnt; i++) {
|
|
153
153
|
if (out->opts->dump_opts.use) {
|
|
154
|
+
assure_size(out, size);
|
|
154
155
|
if (0 < out->opts->dump_opts.array_size) {
|
|
155
156
|
APPEND_CHARS(out->cur, out->opts->dump_opts.array_nl, out->opts->dump_opts.array_size);
|
|
156
157
|
}
|
|
@@ -552,7 +553,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
552
553
|
char buf[64];
|
|
553
554
|
char *b;
|
|
554
555
|
double d = rb_num2dbl(obj);
|
|
555
|
-
|
|
556
|
+
size_t cnt = 0;
|
|
556
557
|
|
|
557
558
|
if (0.0 == d) {
|
|
558
559
|
b = buf;
|
|
@@ -590,7 +591,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
590
591
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
591
592
|
|
|
592
593
|
strcpy(buf, RSTRING_PTR(rstr));
|
|
593
|
-
cnt =
|
|
594
|
+
cnt = RSTRING_LEN(rstr);
|
|
594
595
|
}
|
|
595
596
|
assure_size(out, cnt);
|
|
596
597
|
APPEND_CHARS(out->cur, buf, cnt);
|
|
@@ -604,6 +605,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
604
605
|
if (out->omit_nil && Qnil == value) {
|
|
605
606
|
return ST_CONTINUE;
|
|
606
607
|
}
|
|
608
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
609
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
610
|
+
return ST_CONTINUE;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
607
613
|
if (!out->opts->dump_opts.use) {
|
|
608
614
|
assure_size(out, depth * out->indent + 1);
|
|
609
615
|
fill_indent(out, depth);
|
|
@@ -800,7 +806,7 @@ static void dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
800
806
|
// rb_big2str can not so unless overridden by using add_to_json(Integer)
|
|
801
807
|
// this must use to_s to pass the json gem unit tests.
|
|
802
808
|
volatile VALUE rs;
|
|
803
|
-
|
|
809
|
+
size_t cnt;
|
|
804
810
|
bool dump_as_string = false;
|
|
805
811
|
|
|
806
812
|
if (use_bignum_alt) {
|
|
@@ -809,7 +815,7 @@ static void dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
809
815
|
rs = oj_safe_string_convert(obj);
|
|
810
816
|
}
|
|
811
817
|
rb_check_type(rs, T_STRING);
|
|
812
|
-
cnt =
|
|
818
|
+
cnt = RSTRING_LEN(rs);
|
|
813
819
|
|
|
814
820
|
if (out->opts->int_range_min != 0 || out->opts->int_range_max != 0) {
|
|
815
821
|
dump_as_string = true; // Bignum cannot be inside of Fixnum range
|
data/ext/oj/dump_leaf.c
CHANGED
|
@@ -17,7 +17,7 @@ inline static void dump_chars(const char *s, size_t size, Out out) {
|
|
|
17
17
|
static void dump_leaf_str(Leaf leaf, Out out) {
|
|
18
18
|
switch (leaf->value_type) {
|
|
19
19
|
case STR_VAL: oj_dump_cstr(leaf->str, strlen(leaf->str), 0, 0, out); break;
|
|
20
|
-
case RUBY_VAL: oj_dump_cstr(StringValueCStr(leaf->value),
|
|
20
|
+
case RUBY_VAL: oj_dump_cstr(StringValueCStr(leaf->value), RSTRING_LEN(leaf->value), 0, 0, out); break;
|
|
21
21
|
case COL_VAL:
|
|
22
22
|
default: rb_raise(rb_eTypeError, "Unexpected value type %02x.\n", leaf->value_type); break;
|
|
23
23
|
}
|
data/ext/oj/dump_object.c
CHANGED
|
@@ -33,7 +33,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
33
33
|
if (oj_bigdecimal_class == clas) {
|
|
34
34
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
35
35
|
const char *str = RSTRING_PTR(rstr);
|
|
36
|
-
|
|
36
|
+
size_t len = RSTRING_LEN(rstr);
|
|
37
37
|
|
|
38
38
|
if (No != out->opts->bigdec_as_num) {
|
|
39
39
|
oj_dump_raw(str, len, out);
|
|
@@ -62,7 +62,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
62
62
|
if (oj_bigdecimal_class == clas) {
|
|
63
63
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
64
64
|
const char *str = RSTRING_PTR(rstr);
|
|
65
|
-
|
|
65
|
+
size_t len = RSTRING_LEN(rstr);
|
|
66
66
|
|
|
67
67
|
if (0 == strcasecmp("Infinity", str)) {
|
|
68
68
|
str = oj_nan_str(obj, out->opts->dump_opts.nan_dump, out->opts->mode, true, &len);
|
|
@@ -95,7 +95,8 @@ static void dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
95
95
|
|
|
96
96
|
static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
|
|
97
97
|
size_t size;
|
|
98
|
-
|
|
98
|
+
size_t i;
|
|
99
|
+
size_t cnt;
|
|
99
100
|
int d2 = depth + 1;
|
|
100
101
|
long id = oj_check_circular(a, out);
|
|
101
102
|
|
|
@@ -106,7 +107,7 @@ static void dump_array_class(VALUE a, VALUE clas, int depth, Out out) {
|
|
|
106
107
|
dump_obj_attrs(a, clas, 0, depth, out);
|
|
107
108
|
return;
|
|
108
109
|
}
|
|
109
|
-
cnt =
|
|
110
|
+
cnt = RARRAY_LEN(a);
|
|
110
111
|
*out->cur++ = '[';
|
|
111
112
|
if (0 < id) {
|
|
112
113
|
assure_size(out, d2 * out->indent + 16);
|
|
@@ -181,7 +182,7 @@ static void dump_str_class(VALUE obj, VALUE clas, int depth, Out out) {
|
|
|
181
182
|
dump_obj_attrs(obj, clas, 0, depth, out);
|
|
182
183
|
} else {
|
|
183
184
|
const char *s = RSTRING_PTR(obj);
|
|
184
|
-
size_t len =
|
|
185
|
+
size_t len = RSTRING_LEN(obj);
|
|
185
186
|
char s1 = s[1];
|
|
186
187
|
|
|
187
188
|
oj_dump_cstr(s, len, 0, (':' == *s || ('^' == *s && ('r' == s1 || 'i' == s1))), out);
|
|
@@ -195,7 +196,7 @@ static void dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
195
196
|
static void dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
196
197
|
volatile VALUE s = rb_sym2str(obj);
|
|
197
198
|
|
|
198
|
-
oj_dump_cstr(RSTRING_PTR(s),
|
|
199
|
+
oj_dump_cstr(RSTRING_PTR(s), RSTRING_LEN(s), 1, 0, out);
|
|
199
200
|
}
|
|
200
201
|
|
|
201
202
|
static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
@@ -209,6 +210,11 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
209
210
|
if (out->omit_nil && Qnil == value) {
|
|
210
211
|
return ST_CONTINUE;
|
|
211
212
|
}
|
|
213
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
214
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
215
|
+
return ST_CONTINUE;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
212
218
|
assure_size(out, size);
|
|
213
219
|
fill_indent(out, depth);
|
|
214
220
|
switch (rb_type(key)) {
|
|
@@ -389,7 +395,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
|
389
395
|
rb_raise(rb_eEncodingError, "Invalid type for raw JSON.");
|
|
390
396
|
} else {
|
|
391
397
|
const char *s = RSTRING_PTR(v);
|
|
392
|
-
|
|
398
|
+
size_t len = RSTRING_LEN(v);
|
|
393
399
|
const char *name = rb_id2name(*odd->attrs);
|
|
394
400
|
size_t nlen = strlen(name);
|
|
395
401
|
|
|
@@ -489,7 +495,7 @@ static void dump_obj_attrs(VALUE obj, VALUE clas, slot_t id, int depth, Out out)
|
|
|
489
495
|
*out->cur++ = ',';
|
|
490
496
|
fill_indent(out, d2);
|
|
491
497
|
APPEND_CHARS(out->cur, "\"self\":", 7);
|
|
492
|
-
oj_dump_cstr(RSTRING_PTR(obj),
|
|
498
|
+
oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
|
|
493
499
|
break;
|
|
494
500
|
case T_ARRAY:
|
|
495
501
|
assure_size(out, d2 * out->indent + 14);
|
|
@@ -564,11 +570,12 @@ static void dump_regexp(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
564
570
|
static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
565
571
|
VALUE clas = rb_obj_class(obj);
|
|
566
572
|
const char *class_name = rb_class2name(clas);
|
|
567
|
-
|
|
568
|
-
int d2
|
|
569
|
-
int d3
|
|
570
|
-
size_t len
|
|
571
|
-
size_t size
|
|
573
|
+
size_t i;
|
|
574
|
+
int d2 = depth + 1;
|
|
575
|
+
int d3 = d2 + 1;
|
|
576
|
+
size_t len = strlen(class_name);
|
|
577
|
+
size_t size = d2 * out->indent + d3 * out->indent + 10 + len;
|
|
578
|
+
char circular = out->opts->circular;
|
|
572
579
|
|
|
573
580
|
assure_size(out, size);
|
|
574
581
|
*out->cur++ = '{';
|
|
@@ -577,14 +584,14 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
577
584
|
if ('#' == *class_name) {
|
|
578
585
|
VALUE ma = rb_struct_s_members(clas);
|
|
579
586
|
const char *name;
|
|
580
|
-
|
|
587
|
+
size_t cnt = RARRAY_LEN(ma);
|
|
581
588
|
|
|
582
589
|
*out->cur++ = '[';
|
|
583
590
|
for (i = 0; i < cnt; i++) {
|
|
584
591
|
volatile VALUE s = rb_sym2str(RARRAY_AREF(ma, i));
|
|
585
592
|
|
|
586
593
|
name = RSTRING_PTR(s);
|
|
587
|
-
len =
|
|
594
|
+
len = RSTRING_LEN(s);
|
|
588
595
|
size = len + 3;
|
|
589
596
|
assure_size(out, size);
|
|
590
597
|
if (0 < i) {
|
|
@@ -607,14 +614,18 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
607
614
|
{
|
|
608
615
|
VALUE v;
|
|
609
616
|
int cnt;
|
|
617
|
+
|
|
610
618
|
#if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
611
619
|
cnt = (int)NUM2LONG(RSTRUCT_LEN(obj));
|
|
612
620
|
#else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
613
621
|
cnt = (int)RSTRUCT_LEN(obj);
|
|
614
622
|
#endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
|
|
615
623
|
|
|
616
|
-
|
|
617
|
-
|
|
624
|
+
if (0 == strcmp(class_name, "Range")) {
|
|
625
|
+
out->opts->circular = 'n';
|
|
626
|
+
}
|
|
627
|
+
for (i = 0; i < (size_t)cnt; i++) {
|
|
628
|
+
v = RSTRUCT_GET(obj, (int)i);
|
|
618
629
|
if (dump_ignore(out->opts, v)) {
|
|
619
630
|
v = Qnil;
|
|
620
631
|
}
|
|
@@ -630,6 +641,9 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
630
641
|
// class in interpreted Ruby so length() may not be defined.
|
|
631
642
|
int slen = FIX2INT(rb_funcall2(obj, oj_length_id, 0, 0));
|
|
632
643
|
|
|
644
|
+
if (0 == strcmp(class_name, "Range")) {
|
|
645
|
+
out->opts->circular = 'n';
|
|
646
|
+
}
|
|
633
647
|
for (i = 0; i < slen; i++) {
|
|
634
648
|
assure_size(out, size);
|
|
635
649
|
fill_indent(out, d3);
|
|
@@ -641,6 +655,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
641
655
|
}
|
|
642
656
|
}
|
|
643
657
|
#endif
|
|
658
|
+
out->opts->circular = circular;
|
|
644
659
|
out->cur--;
|
|
645
660
|
APPEND_CHARS(out->cur, "]}", 2);
|
|
646
661
|
*out->cur = '\0';
|
data/ext/oj/dump_strict.c
CHANGED
|
@@ -30,7 +30,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
30
30
|
char buf[64];
|
|
31
31
|
char* b;
|
|
32
32
|
double d = rb_num2dbl(obj);
|
|
33
|
-
|
|
33
|
+
size_t cnt = 0;
|
|
34
34
|
|
|
35
35
|
if (0.0 == d) {
|
|
36
36
|
b = buf;
|
|
@@ -92,7 +92,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
92
92
|
} else if (0 == out->opts->float_prec) {
|
|
93
93
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
94
94
|
|
|
95
|
-
cnt =
|
|
95
|
+
cnt = RSTRING_LEN(rstr);
|
|
96
96
|
if ((int)sizeof(buf) <= cnt) {
|
|
97
97
|
cnt = sizeof(buf) - 1;
|
|
98
98
|
}
|
|
@@ -109,7 +109,8 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
109
109
|
|
|
110
110
|
static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
111
111
|
size_t size;
|
|
112
|
-
|
|
112
|
+
size_t i;
|
|
113
|
+
size_t cnt;
|
|
113
114
|
int d2 = depth + 1;
|
|
114
115
|
|
|
115
116
|
if (Yes == out->opts->circular) {
|
|
@@ -118,7 +119,7 @@ static void dump_array(VALUE a, int depth, Out out, bool as_ok) {
|
|
|
118
119
|
return;
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
|
-
cnt =
|
|
122
|
+
cnt = RARRAY_LEN(a);
|
|
122
123
|
*out->cur++ = '[';
|
|
123
124
|
size = 2;
|
|
124
125
|
assure_size(out, size);
|
|
@@ -192,14 +193,19 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
192
193
|
if (out->omit_nil && Qnil == value) {
|
|
193
194
|
return ST_CONTINUE;
|
|
194
195
|
}
|
|
196
|
+
if (NULL != out->opts->dump_opts.only || NULL != out->opts->dump_opts.except) {
|
|
197
|
+
if (oj_key_skip(key, out->opts->dump_opts.only, out->opts->dump_opts.except)) {
|
|
198
|
+
return ST_CONTINUE;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
195
201
|
if (!out->opts->dump_opts.use) {
|
|
196
202
|
size = depth * out->indent + 1;
|
|
197
203
|
assure_size(out, size);
|
|
198
204
|
fill_indent(out, depth);
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
switch (rtype) {
|
|
206
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
207
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
208
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
203
209
|
}
|
|
204
210
|
*out->cur++ = ':';
|
|
205
211
|
} else {
|
|
@@ -214,10 +220,10 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
|
214
220
|
APPEND_CHARS(out->cur, out->opts->dump_opts.indent_str, out->opts->dump_opts.indent_size);
|
|
215
221
|
}
|
|
216
222
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
223
|
+
switch (rtype) {
|
|
224
|
+
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
|
225
|
+
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
|
226
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
|
221
227
|
}
|
|
222
228
|
size = out->opts->dump_opts.before_size + out->opts->dump_opts.after_size + 2;
|
|
223
229
|
assure_size(out, size);
|
|
@@ -290,7 +296,7 @@ static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
290
296
|
if (oj_bigdecimal_class == clas) {
|
|
291
297
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
292
298
|
|
|
293
|
-
oj_dump_raw(RSTRING_PTR(rstr),
|
|
299
|
+
oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
|
|
294
300
|
} else {
|
|
295
301
|
raise_strict(obj);
|
|
296
302
|
}
|
|
@@ -302,7 +308,7 @@ static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
302
308
|
if (oj_bigdecimal_class == clas) {
|
|
303
309
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
304
310
|
|
|
305
|
-
oj_dump_raw(RSTRING_PTR(rstr),
|
|
311
|
+
oj_dump_raw(RSTRING_PTR(rstr), RSTRING_LEN(rstr), out);
|
|
306
312
|
} else {
|
|
307
313
|
oj_dump_nil(Qnil, depth, out, false);
|
|
308
314
|
}
|
data/ext/oj/extconf.rb
CHANGED
|
@@ -29,20 +29,22 @@ dflags = {
|
|
|
29
29
|
have_func('rb_gc_mark_movable')
|
|
30
30
|
have_func('stpcpy')
|
|
31
31
|
have_func('pthread_mutex_init')
|
|
32
|
+
have_func('getrlimit', 'sys/resource.h')
|
|
32
33
|
have_func('rb_enc_interned_str')
|
|
33
34
|
have_func('rb_ext_ractor_safe', 'ruby.h')
|
|
34
|
-
# rb_hash_bulk_insert is deep down in a header not included in normal build and that seems to fool have_func.
|
|
35
|
-
have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == version[1]
|
|
36
35
|
|
|
37
36
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
# SIMD optimizations use runtime CPU detection and function-level target attributes
|
|
39
|
+
# We do NOT add global -msse4.2/-msse2 flags here because:
|
|
40
|
+
# 1. It would cause illegal instruction errors on CPUs without SSE4.2
|
|
41
|
+
# 2. The code uses __attribute__((target("sse4.2"))) for SSE4.2 functions
|
|
42
|
+
# 3. Runtime detection in oj_get_simd_implementation() selects the right path
|
|
43
|
+
#
|
|
44
|
+
# We only add -msse2 if available, since SSE2 is baseline for all x86_64 CPUs
|
|
45
|
+
# and needed for compiling the SSE2 fallback code on 32-bit x86
|
|
46
|
+
if try_cflags('-msse2')
|
|
47
|
+
$CPPFLAGS += ' -msse2'
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
if enable_config('trace-log', false)
|
data/ext/oj/fast.c
CHANGED
|
@@ -40,7 +40,7 @@ typedef struct _doc {
|
|
|
40
40
|
Leaf *where; // points to current location
|
|
41
41
|
Leaf where_path[MAX_STACK]; // points to head of path
|
|
42
42
|
char *json;
|
|
43
|
-
unsigned long size;
|
|
43
|
+
unsigned long size; // number of leaves/branches in the doc
|
|
44
44
|
VALUE self;
|
|
45
45
|
Batch batches;
|
|
46
46
|
struct _batch batch0;
|
|
@@ -80,21 +80,10 @@ static void each_leaf(Doc doc, VALUE self);
|
|
|
80
80
|
static int move_step(Doc doc, const char *path, int loc);
|
|
81
81
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
|
82
82
|
static Leaf get_leaf(Leaf *stack, Leaf *lp, const char *path);
|
|
83
|
-
static void each_value(Doc doc, Leaf leaf);
|
|
83
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self);
|
|
84
84
|
|
|
85
85
|
VALUE oj_doc_class = Qundef;
|
|
86
86
|
|
|
87
|
-
// This is only for CentOS 5.4 with Ruby 1.9.3-p0.
|
|
88
|
-
#ifndef HAVE_STPCPY
|
|
89
|
-
char *stpcpy(char *dest, const char *src) {
|
|
90
|
-
size_t cnt = strlen(src);
|
|
91
|
-
|
|
92
|
-
strcpy(dest, src);
|
|
93
|
-
|
|
94
|
-
return dest + cnt;
|
|
95
|
-
}
|
|
96
|
-
#endif
|
|
97
|
-
|
|
98
87
|
inline static void next_non_white(ParseInfo pi) {
|
|
99
88
|
for (; 1; pi->s++) {
|
|
100
89
|
switch (*pi->s) {
|
|
@@ -193,8 +182,7 @@ static VALUE leaf_value(Doc doc, Leaf leaf) {
|
|
|
193
182
|
case T_FIXNUM: leaf_fixnum_value(leaf); break;
|
|
194
183
|
case T_FLOAT: leaf_float_value(leaf); break;
|
|
195
184
|
case T_STRING:
|
|
196
|
-
leaf->value =
|
|
197
|
-
leaf->value = oj_encode(leaf->value);
|
|
185
|
+
leaf->value = rb_utf8_str_new_cstr(leaf->str);
|
|
198
186
|
leaf->value_type = RUBY_VAL;
|
|
199
187
|
break;
|
|
200
188
|
case T_ARRAY: return leaf_array_value(doc, leaf); break;
|
|
@@ -247,6 +235,19 @@ static void skip_comment(ParseInfo pi) {
|
|
|
247
235
|
#define NUM_MAX (FIXNUM_MAX >> 8)
|
|
248
236
|
#endif
|
|
249
237
|
|
|
238
|
+
static void validate_integer_size(size_t limit, char *head, char *tail) {
|
|
239
|
+
size_t total = (size_t)(tail - head);
|
|
240
|
+
bool has_sign = (head[0] == '-' || head[0] == '+');
|
|
241
|
+
size_t digit_count = total - (has_sign ? 1 : 0);
|
|
242
|
+
|
|
243
|
+
if (digit_count > limit) {
|
|
244
|
+
rb_raise(oj_parse_error_class,
|
|
245
|
+
"integer exceeds :max_integer_digits (%lu > %lu)",
|
|
246
|
+
(unsigned long)digit_count,
|
|
247
|
+
(unsigned long)limit);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
250
251
|
static void leaf_fixnum_value(Leaf leaf) {
|
|
251
252
|
char *s = leaf->str;
|
|
252
253
|
int64_t n = 0;
|
|
@@ -266,7 +267,12 @@ static void leaf_fixnum_value(Leaf leaf) {
|
|
|
266
267
|
}
|
|
267
268
|
}
|
|
268
269
|
if (big) {
|
|
269
|
-
|
|
270
|
+
size_t limit = oj_default_options.max_integer_digits;
|
|
271
|
+
char c = *s;
|
|
272
|
+
|
|
273
|
+
if (0 < limit) {
|
|
274
|
+
validate_integer_size(limit, leaf->str, s);
|
|
275
|
+
}
|
|
270
276
|
|
|
271
277
|
*s = '\0';
|
|
272
278
|
leaf->value = rb_cstr_to_inum(leaf->str, 10, 0);
|
|
@@ -309,8 +315,7 @@ static VALUE leaf_hash_value(Doc doc, Leaf leaf) {
|
|
|
309
315
|
volatile VALUE key;
|
|
310
316
|
|
|
311
317
|
do {
|
|
312
|
-
key =
|
|
313
|
-
key = oj_encode(key);
|
|
318
|
+
key = rb_utf8_str_new_cstr(e->key);
|
|
314
319
|
rb_hash_aset(h, key, leaf_value(doc, e));
|
|
315
320
|
e = e->next;
|
|
316
321
|
} while (e != first);
|
|
@@ -573,7 +578,7 @@ static char *read_quoted_value(ParseInfo pi) {
|
|
|
573
578
|
char *h = pi->s; // head
|
|
574
579
|
char *t = h; // tail
|
|
575
580
|
|
|
576
|
-
h++;
|
|
581
|
+
h++; // skip quote character
|
|
577
582
|
t++;
|
|
578
583
|
value = h;
|
|
579
584
|
for (; '"' != *h; h++, t++) {
|
|
@@ -765,7 +770,7 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
|
765
770
|
pi.s = pi.str;
|
|
766
771
|
doc_init(doc);
|
|
767
772
|
pi.doc = doc;
|
|
768
|
-
#if IS_WINDOWS
|
|
773
|
+
#if IS_WINDOWS || !defined(HAVE_GETRLIMIT)
|
|
769
774
|
// assume a 1M stack and give half to ruby
|
|
770
775
|
pi.stack_min = (void *)((char *)&pi - (512L * 1024L));
|
|
771
776
|
#else
|
|
@@ -780,11 +785,10 @@ static VALUE parse_json(VALUE clas, char *json, bool given) {
|
|
|
780
785
|
}
|
|
781
786
|
}
|
|
782
787
|
#endif
|
|
783
|
-
doc->json
|
|
784
|
-
self
|
|
785
|
-
doc->self
|
|
786
|
-
|
|
787
|
-
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
|
788
|
+
doc->json = json;
|
|
789
|
+
self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
|
|
790
|
+
doc->self = self;
|
|
791
|
+
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
|
788
792
|
if (given || 0 != ex) {
|
|
789
793
|
DATA_PTR(doc->self) = NULL;
|
|
790
794
|
// TBD is this needed?
|
|
@@ -953,6 +957,9 @@ static void each_leaf(Doc doc, VALUE self) {
|
|
|
953
957
|
}
|
|
954
958
|
} else {
|
|
955
959
|
rb_yield(self);
|
|
960
|
+
if (NULL == DATA_PTR(self)) {
|
|
961
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
962
|
+
}
|
|
956
963
|
}
|
|
957
964
|
}
|
|
958
965
|
|
|
@@ -1046,19 +1053,22 @@ static int move_step(Doc doc, const char *path, int loc) {
|
|
|
1046
1053
|
return loc;
|
|
1047
1054
|
}
|
|
1048
1055
|
|
|
1049
|
-
static void each_value(Doc doc, Leaf leaf) {
|
|
1056
|
+
static void each_value(Doc doc, Leaf leaf, VALUE self) {
|
|
1050
1057
|
if (COL_VAL == leaf->value_type) {
|
|
1051
1058
|
if (0 != leaf->elements) {
|
|
1052
1059
|
Leaf first = leaf->elements->next;
|
|
1053
1060
|
Leaf e = first;
|
|
1054
1061
|
|
|
1055
1062
|
do {
|
|
1056
|
-
each_value(doc, e);
|
|
1063
|
+
each_value(doc, e, self);
|
|
1057
1064
|
e = e->next;
|
|
1058
1065
|
} while (e != first);
|
|
1059
1066
|
}
|
|
1060
1067
|
} else {
|
|
1061
1068
|
rb_yield(leaf_value(doc, leaf));
|
|
1069
|
+
if (NULL == DATA_PTR(self)) {
|
|
1070
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1071
|
+
}
|
|
1062
1072
|
}
|
|
1063
1073
|
}
|
|
1064
1074
|
|
|
@@ -1089,7 +1099,7 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
|
1089
1099
|
int given = rb_block_given_p();
|
|
1090
1100
|
|
|
1091
1101
|
Check_Type(str, T_STRING);
|
|
1092
|
-
len =
|
|
1102
|
+
len = RSTRING_LEN(str) + 1;
|
|
1093
1103
|
json = OJ_R_ALLOC_N(char, len);
|
|
1094
1104
|
|
|
1095
1105
|
memcpy(json, StringValuePtr(str), len);
|
|
@@ -1258,8 +1268,7 @@ static VALUE doc_local_key(VALUE self) {
|
|
|
1258
1268
|
volatile VALUE key = Qnil;
|
|
1259
1269
|
|
|
1260
1270
|
if (T_HASH == leaf->parent_type) {
|
|
1261
|
-
key =
|
|
1262
|
-
key = oj_encode(key);
|
|
1271
|
+
key = rb_utf8_str_new_cstr(leaf->key);
|
|
1263
1272
|
} else if (T_ARRAY == leaf->parent_type) {
|
|
1264
1273
|
key = LONG2NUM(leaf->index);
|
|
1265
1274
|
}
|
|
@@ -1495,12 +1504,19 @@ static VALUE doc_each_child(int argc, VALUE *argv, VALUE self) {
|
|
|
1495
1504
|
Leaf first = (*doc->where)->elements->next;
|
|
1496
1505
|
Leaf e = first;
|
|
1497
1506
|
|
|
1507
|
+
if (MAX_STACK <= (doc->where + 1) - doc->where_path) {
|
|
1508
|
+
rb_raise(rb_const_get_at(Oj, rb_intern("DepthError")), "Path too deep. Limit is %d levels.", MAX_STACK);
|
|
1509
|
+
}
|
|
1498
1510
|
doc->where++;
|
|
1499
1511
|
do {
|
|
1500
1512
|
*doc->where = e;
|
|
1501
1513
|
rb_yield(self);
|
|
1514
|
+
if (NULL == DATA_PTR(self)) {
|
|
1515
|
+
rb_raise(rb_eIOError, "Document closed.");
|
|
1516
|
+
}
|
|
1502
1517
|
e = e->next;
|
|
1503
1518
|
} while (e != first);
|
|
1519
|
+
doc->where--;
|
|
1504
1520
|
}
|
|
1505
1521
|
if (0 < wlen) {
|
|
1506
1522
|
memcpy(doc->where_path, save_path, sizeof(Leaf) * (wlen + 1));
|
|
@@ -1544,7 +1560,7 @@ static VALUE doc_each_value(int argc, VALUE *argv, VALUE self) {
|
|
|
1544
1560
|
path = StringValuePtr(*argv);
|
|
1545
1561
|
}
|
|
1546
1562
|
if (0 != (leaf = get_doc_leaf(doc, path))) {
|
|
1547
|
-
each_value(doc, leaf);
|
|
1563
|
+
each_value(doc, leaf, self);
|
|
1548
1564
|
}
|
|
1549
1565
|
}
|
|
1550
1566
|
return Qnil;
|
|
@@ -1609,7 +1625,9 @@ static VALUE doc_dump(int argc, VALUE *argv, VALUE self) {
|
|
|
1609
1625
|
* Oj::Doc.open('[1,2,3]') { |doc| doc.size() } #=> 4
|
|
1610
1626
|
*/
|
|
1611
1627
|
static VALUE doc_size(VALUE self) {
|
|
1612
|
-
|
|
1628
|
+
Doc d;
|
|
1629
|
+
TypedData_Get_Struct(self, struct _doc, &oj_doc_type, d);
|
|
1630
|
+
return ULONG2NUM(d->size);
|
|
1613
1631
|
}
|
|
1614
1632
|
|
|
1615
1633
|
/* @overload close() => nil
|