oj 3.13.23 → 3.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +2 -1
- data/ext/oj/compat.c +10 -30
- data/ext/oj/custom.c +13 -29
- data/ext/oj/dump.c +6 -10
- data/ext/oj/dump_compat.c +9 -19
- data/ext/oj/dump_object.c +5 -11
- data/ext/oj/dump_strict.c +8 -18
- data/ext/oj/extconf.rb +10 -2
- data/ext/oj/fast.c +25 -42
- data/ext/oj/object.c +2 -6
- data/ext/oj/oj.h +6 -0
- data/ext/oj/parse.c +4 -0
- data/ext/oj/parser.c +1 -1
- data/ext/oj/rails.c +10 -20
- data/ext/oj/reader.c +1 -1
- data/ext/oj/strict.c +4 -12
- data/ext/oj/trace.h +16 -0
- data/ext/oj/wab.c +9 -21
- data/lib/oj/version.rb +1 -1
- data/pages/InstallOptions.md +20 -0
- data/test/foo.rb +18 -66
- data/test/test_compat.rb +9 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5864f273679d1441d9731976eb4f4c3cdcccaa86c877fae2aeb719cd03f45167
|
4
|
+
data.tar.gz: 815abc1a8572ce907b280ca632fd010c766ad55e581c3a59d76c0f94ede24234
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3318017139004f712665ff2fda5dcfc761b33079bb96dd1d8f5baf59d146a45956e3c58f1e700044a714ca2643d5a54196e3b306566130c9bda7242d8c688b91
|
7
|
+
data.tar.gz: f8f6f637c883ca2b4fa8c76f349940f6be3c1af524d43f3cc0ed4df27a21896f480da520b2897e191d38e50ef939139bdd242c3e3f33aa0c0e3aa8bd3a008a6b
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# [![{}j](http://www.ohler.com/dev/images/oj_comet_64.svg)](http://www.ohler.com/oj) gem
|
2
2
|
|
3
|
-
[![
|
3
|
+
[![CI](https://github.com/ohler55/oj/actions/workflows/CI.yml/badge.svg)](https://github.com/ohler55/oj/actions/workflows/CI.yml)
|
4
4
|
![Gem](https://img.shields.io/gem/v/oj.svg)
|
5
5
|
![Gem](https://img.shields.io/gem/dt/oj.svg)
|
6
6
|
[![SemVer compatibility](https://api.dependabot.com/badges/compatibility_score?dependency-name=oj&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=oj&package-manager=bundler&version-scheme=semver)
|
@@ -70,6 +70,7 @@ links.
|
|
70
70
|
- [{file:Compatibility.md}](pages/Compatibility.md) lists current compatibility with Rubys and Rails.
|
71
71
|
- [{file:Advanced.md}](pages/Advanced.md) for fast parser and marshalling features.
|
72
72
|
- [{file:Security.md}](pages/Security.md) for security considerations.
|
73
|
+
- [{file:InstallOptions.md}](pages/InstallOptions.md) for install option.
|
73
74
|
|
74
75
|
## Releases
|
75
76
|
|
data/ext/oj/compat.c
CHANGED
@@ -54,9 +54,7 @@ static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, c
|
|
54
54
|
} else {
|
55
55
|
rb_hash_aset(parent->val, rkey, rstr);
|
56
56
|
}
|
57
|
-
|
58
|
-
oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rstr);
|
59
|
-
}
|
57
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_string", pi, rstr);
|
60
58
|
}
|
61
59
|
}
|
62
60
|
|
@@ -68,9 +66,7 @@ static VALUE start_hash(ParseInfo pi) {
|
|
68
66
|
} else {
|
69
67
|
h = rb_hash_new();
|
70
68
|
}
|
71
|
-
|
72
|
-
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
73
|
-
}
|
69
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
74
70
|
return h;
|
75
71
|
}
|
76
72
|
|
@@ -93,9 +89,7 @@ static void end_hash(struct _parseInfo *pi) {
|
|
93
89
|
parent->classname = 0;
|
94
90
|
}
|
95
91
|
}
|
96
|
-
|
97
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
98
|
-
}
|
92
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
99
93
|
}
|
100
94
|
|
101
95
|
static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
@@ -110,16 +104,12 @@ static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig
|
|
110
104
|
}
|
111
105
|
}
|
112
106
|
pi->stack.head->val = rstr;
|
113
|
-
|
114
|
-
oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, rstr);
|
115
|
-
}
|
107
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_string", pi, rstr);
|
116
108
|
}
|
117
109
|
|
118
110
|
static void add_num(ParseInfo pi, NumInfo ni) {
|
119
111
|
pi->stack.head->val = oj_num_as_value(ni);
|
120
|
-
|
121
|
-
oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, pi->stack.head->val);
|
122
|
-
}
|
112
|
+
TRACE_PARSE_CALL(pi->options.trace, "add_number", pi, pi->stack.head->val);
|
123
113
|
}
|
124
114
|
|
125
115
|
static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
|
@@ -138,9 +128,7 @@ static void hash_set_num(struct _parseInfo *pi, Val parent, NumInfo ni) {
|
|
138
128
|
} else {
|
139
129
|
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), rval);
|
140
130
|
}
|
141
|
-
|
142
|
-
oj_trace_parse_call("set_number", pi, __FILE__, __LINE__, rval);
|
143
|
-
}
|
131
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_number", pi, rval);
|
144
132
|
}
|
145
133
|
|
146
134
|
static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
@@ -157,18 +145,14 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
157
145
|
} else {
|
158
146
|
rb_hash_aset(stack_peek(&pi->stack)->val, oj_calc_hash_key(pi, parent), value);
|
159
147
|
}
|
160
|
-
|
161
|
-
oj_trace_parse_call("set_value", pi, __FILE__, __LINE__, value);
|
162
|
-
}
|
148
|
+
TRACE_PARSE_CALL(pi->options.trace, "set_value", pi, value);
|
163
149
|
}
|
164
150
|
|
165
151
|
static VALUE start_array(ParseInfo pi) {
|
166
152
|
if (Qnil != pi->options.array_class) {
|
167
153
|
return rb_class_new_instance(0, NULL, pi->options.array_class);
|
168
154
|
}
|
169
|
-
|
170
|
-
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
171
|
-
}
|
155
|
+
TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
|
172
156
|
return rb_ary_new();
|
173
157
|
}
|
174
158
|
|
@@ -184,9 +168,7 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
|
|
184
168
|
} else {
|
185
169
|
rb_ary_push(parent->val, rval);
|
186
170
|
}
|
187
|
-
|
188
|
-
oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
|
189
|
-
}
|
171
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_number", pi, rval);
|
190
172
|
}
|
191
173
|
|
192
174
|
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
@@ -201,9 +183,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
|
|
201
183
|
}
|
202
184
|
}
|
203
185
|
rb_ary_push(stack_peek(&pi->stack)->val, rstr);
|
204
|
-
|
205
|
-
oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rstr);
|
206
|
-
}
|
186
|
+
TRACE_PARSE_CALL(pi->options.trace, "append_string", pi, rstr);
|
207
187
|
}
|
208
188
|
|
209
189
|
void oj_set_compat_callbacks(ParseInfo pi) {
|
data/ext/oj/custom.c
CHANGED
@@ -24,20 +24,20 @@ static void dump_obj_str(VALUE obj, int depth, Out out) {
|
|
24
24
|
{"s", 1, Qnil},
|
25
25
|
{NULL, 0, Qnil},
|
26
26
|
};
|
27
|
-
attrs->value =
|
27
|
+
attrs->value = oj_safe_string_convert(obj);
|
28
28
|
|
29
29
|
oj_code_attrs(obj, attrs, depth, out, Yes == out->opts->create_ok);
|
30
30
|
}
|
31
31
|
|
32
32
|
static void dump_obj_as_str(VALUE obj, int depth, Out out) {
|
33
|
-
volatile VALUE rstr =
|
33
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
34
34
|
const char *str = RSTRING_PTR(rstr);
|
35
35
|
|
36
36
|
oj_dump_cstr(str, RSTRING_LEN(rstr), 0, 0, out);
|
37
37
|
}
|
38
38
|
|
39
39
|
static void bigdecimal_dump(VALUE obj, int depth, Out out) {
|
40
|
-
volatile VALUE rstr =
|
40
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
41
41
|
const char *str = RSTRING_PTR(rstr);
|
42
42
|
int len = (int)RSTRING_LEN(rstr);
|
43
43
|
|
@@ -305,7 +305,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
305
305
|
switch (rb_type(key)) {
|
306
306
|
case T_STRING: oj_dump_str(key, 0, out, false); break;
|
307
307
|
case T_SYMBOL: oj_dump_sym(key, 0, out, false); break;
|
308
|
-
default: oj_dump_str(
|
308
|
+
default: oj_dump_str(oj_safe_string_convert(key), 0, out, false); break;
|
309
309
|
}
|
310
310
|
if (!out->opts->dump_opts.use) {
|
311
311
|
*out->cur++ = ':';
|
@@ -479,17 +479,13 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
479
479
|
const char *s;
|
480
480
|
int len;
|
481
481
|
|
482
|
-
|
483
|
-
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
484
|
-
}
|
482
|
+
TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyIn);
|
485
483
|
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
486
484
|
rs = rb_funcall(obj, oj_to_json_id, 0);
|
487
485
|
} else {
|
488
486
|
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
489
487
|
}
|
490
|
-
|
491
|
-
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
492
|
-
}
|
488
|
+
TRACE(out->opts->trace, "to_json", obj, depth + 1, TraceRubyOut);
|
493
489
|
s = RSTRING_PTR(rs);
|
494
490
|
len = (int)RSTRING_LEN(rs);
|
495
491
|
|
@@ -499,9 +495,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
499
495
|
} else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
500
496
|
volatile VALUE aj;
|
501
497
|
|
502
|
-
|
503
|
-
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
504
|
-
}
|
498
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
|
505
499
|
// Some classes elect to not take an options argument so check the arity
|
506
500
|
// of as_json.
|
507
501
|
if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
|
@@ -509,12 +503,10 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
509
503
|
} else {
|
510
504
|
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
511
505
|
}
|
512
|
-
|
513
|
-
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
514
|
-
}
|
506
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
|
515
507
|
// Catch the obvious brain damaged recursive dumping.
|
516
508
|
if (aj == obj) {
|
517
|
-
volatile VALUE rstr =
|
509
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
518
510
|
|
519
511
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), false, false, out);
|
520
512
|
} else {
|
@@ -876,9 +868,7 @@ static DumpFunc custom_funcs[] = {
|
|
876
868
|
void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
877
869
|
int type = rb_type(obj);
|
878
870
|
|
879
|
-
|
880
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
881
|
-
}
|
871
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
882
872
|
if (MAX_DEPTH < depth) {
|
883
873
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
884
874
|
}
|
@@ -887,16 +877,12 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
887
877
|
|
888
878
|
if (NULL != f) {
|
889
879
|
f(obj, depth, out, true);
|
890
|
-
|
891
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
892
|
-
}
|
880
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
893
881
|
return;
|
894
882
|
}
|
895
883
|
}
|
896
884
|
oj_dump_nil(Qnil, depth, out, false);
|
897
|
-
|
898
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
899
|
-
}
|
885
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
900
886
|
}
|
901
887
|
|
902
888
|
///// load functions /////
|
@@ -969,9 +955,7 @@ static void end_hash(struct _parseInfo *pi) {
|
|
969
955
|
}
|
970
956
|
parent->clas = Qundef;
|
971
957
|
}
|
972
|
-
|
973
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
974
|
-
}
|
958
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
975
959
|
}
|
976
960
|
|
977
961
|
static void hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
data/ext/oj/dump.c
CHANGED
@@ -463,7 +463,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
463
463
|
}
|
464
464
|
|
465
465
|
void oj_dump_ruby_time(VALUE obj, Out out) {
|
466
|
-
volatile VALUE rstr =
|
466
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
467
467
|
|
468
468
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
469
469
|
}
|
@@ -736,13 +736,9 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
736
736
|
} else {
|
737
737
|
volatile VALUE jv;
|
738
738
|
|
739
|
-
|
740
|
-
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
741
|
-
}
|
739
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyIn);
|
742
740
|
jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
|
743
|
-
|
744
|
-
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
745
|
-
}
|
741
|
+
TRACE(out->opts->trace, "raw_json", obj, depth + 1, TraceRubyOut);
|
746
742
|
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
747
743
|
}
|
748
744
|
}
|
@@ -932,7 +928,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
932
928
|
}
|
933
929
|
|
934
930
|
void oj_dump_obj_to_s(VALUE obj, Out out) {
|
935
|
-
volatile VALUE rstr =
|
931
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
936
932
|
|
937
933
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
938
934
|
}
|
@@ -1173,7 +1169,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1173
1169
|
} else if (d == (double)(long long int)d) {
|
1174
1170
|
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
1175
1171
|
} else if (0 == out->opts->float_prec) {
|
1176
|
-
volatile VALUE rstr =
|
1172
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1177
1173
|
|
1178
1174
|
cnt = (int)RSTRING_LEN(rstr);
|
1179
1175
|
if ((int)sizeof(buf) <= cnt) {
|
@@ -1195,7 +1191,7 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
1195
1191
|
// Round off issues at 16 significant digits so check for obvious ones of
|
1196
1192
|
// 0001 and 9999.
|
1197
1193
|
if (17 <= cnt && (0 == strcmp("0001", buf + cnt - 4) || 0 == strcmp("9999", buf + cnt - 4))) {
|
1198
|
-
volatile VALUE rstr =
|
1194
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1199
1195
|
|
1200
1196
|
strcpy(buf, RSTRING_PTR(rstr));
|
1201
1197
|
cnt = (int)RSTRING_LEN(rstr);
|
data/ext/oj/dump_compat.c
CHANGED
@@ -109,17 +109,13 @@ dump_to_json(VALUE obj, Out out) {
|
|
109
109
|
const char *s;
|
110
110
|
int len;
|
111
111
|
|
112
|
-
|
113
|
-
oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
|
114
|
-
}
|
112
|
+
TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyIn);
|
115
113
|
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
116
114
|
rs = rb_funcall(obj, oj_to_json_id, 0);
|
117
115
|
} else {
|
118
116
|
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
119
117
|
}
|
120
|
-
|
121
|
-
oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
|
122
|
-
}
|
118
|
+
TRACE(out->opts->trace, "to_json", obj, 0, TraceRubyOut);
|
123
119
|
|
124
120
|
s = RSTRING_PTR(rs);
|
125
121
|
len = (int)RSTRING_LEN(rs);
|
@@ -299,7 +295,7 @@ datetime_alt(VALUE obj, int depth, Out out) {
|
|
299
295
|
attrs[3].value = rb_funcall(obj, hour_id, 0);
|
300
296
|
attrs[4].value = rb_funcall(obj, min_id, 0);
|
301
297
|
attrs[5].value = rb_funcall(obj, sec_id, 0);
|
302
|
-
attrs[6].value =
|
298
|
+
attrs[6].value = oj_safe_string_convert(rb_funcall(obj, offset_id, 0));
|
303
299
|
attrs[7].value = rb_funcall(obj, start_id, 0);
|
304
300
|
|
305
301
|
oj_code_attrs(obj, attrs, depth, out, true);
|
@@ -606,7 +602,7 @@ dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
606
602
|
} else if (oj_rails_float_opt) {
|
607
603
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
|
608
604
|
} else {
|
609
|
-
volatile VALUE rstr =
|
605
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
610
606
|
|
611
607
|
strcpy(buf, RSTRING_PTR(rstr));
|
612
608
|
cnt = (int)RSTRING_LEN(rstr);
|
@@ -648,7 +644,7 @@ hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
648
644
|
break;
|
649
645
|
default:
|
650
646
|
/*rb_raise(rb_eTypeError, "In :compat mode all Hash keys must be Strings or Symbols, not %s.\n", rb_class2name(rb_obj_class(key)));*/
|
651
|
-
oj_dump_str(
|
647
|
+
oj_dump_str(oj_safe_string_convert(key), 0, out, false);
|
652
648
|
break;
|
653
649
|
}
|
654
650
|
if (!out->opts->dump_opts.use) {
|
@@ -833,7 +829,7 @@ dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
833
829
|
if (use_bignum_alt) {
|
834
830
|
rs = rb_big2str(obj, 10);
|
835
831
|
} else {
|
836
|
-
rs =
|
832
|
+
rs = oj_safe_string_convert(obj);
|
837
833
|
}
|
838
834
|
rb_check_type(rs, T_STRING);
|
839
835
|
cnt = (int)RSTRING_LEN(rs);
|
@@ -893,9 +889,7 @@ void
|
|
893
889
|
oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
894
890
|
int type = rb_type(obj);
|
895
891
|
|
896
|
-
|
897
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
898
|
-
}
|
892
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
899
893
|
if (out->opts->dump_opts.max_depth <= depth) {
|
900
894
|
// When JSON.dump is called then an ArgumentError is expected and the
|
901
895
|
// limit is the depth inclusive. If JSON.generate is called then a
|
@@ -918,14 +912,10 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
918
912
|
|
919
913
|
if (NULL != f) {
|
920
914
|
f(obj, depth, out, as_ok);
|
921
|
-
|
922
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
923
|
-
}
|
915
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
924
916
|
return;
|
925
917
|
}
|
926
918
|
}
|
927
919
|
oj_dump_nil(Qnil, depth, out, false);
|
928
|
-
|
929
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
930
|
-
}
|
920
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
931
921
|
}
|
data/ext/oj/dump_object.c
CHANGED
@@ -30,7 +30,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
|
30
30
|
*out->cur = '\0';
|
31
31
|
} else {
|
32
32
|
if (oj_bigdecimal_class == clas) {
|
33
|
-
volatile VALUE rstr =
|
33
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
34
34
|
const char * str = RSTRING_PTR(rstr);
|
35
35
|
int len = (int)RSTRING_LEN(rstr);
|
36
36
|
|
@@ -59,7 +59,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
59
59
|
VALUE clas = rb_obj_class(obj);
|
60
60
|
|
61
61
|
if (oj_bigdecimal_class == clas) {
|
62
|
-
volatile VALUE rstr =
|
62
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
63
63
|
const char * str = RSTRING_PTR(rstr);
|
64
64
|
int len = (int)RSTRING_LEN(rstr);
|
65
65
|
|
@@ -682,9 +682,7 @@ static DumpFunc obj_funcs[] = {
|
|
682
682
|
void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
683
683
|
int type = rb_type(obj);
|
684
684
|
|
685
|
-
|
686
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
687
|
-
}
|
685
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
688
686
|
if (MAX_DEPTH < depth) {
|
689
687
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
690
688
|
}
|
@@ -693,14 +691,10 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
693
691
|
|
694
692
|
if (NULL != f) {
|
695
693
|
f(obj, depth, out, false);
|
696
|
-
|
697
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
698
|
-
}
|
694
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
699
695
|
return;
|
700
696
|
}
|
701
697
|
}
|
702
698
|
oj_dump_nil(Qnil, depth, out, false);
|
703
|
-
|
704
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
705
|
-
}
|
699
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
706
700
|
}
|
data/ext/oj/dump_strict.c
CHANGED
@@ -92,7 +92,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
92
92
|
} else if (d == (double)(long long int)d) {
|
93
93
|
cnt = snprintf(buf, sizeof(buf), "%.1f", d);
|
94
94
|
} else if (0 == out->opts->float_prec) {
|
95
|
-
volatile VALUE rstr =
|
95
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
96
96
|
|
97
97
|
cnt = (int)RSTRING_LEN(rstr);
|
98
98
|
if ((int)sizeof(buf) <= cnt) {
|
@@ -290,7 +290,7 @@ static void dump_data_strict(VALUE obj, int depth, Out out, bool as_ok) {
|
|
290
290
|
VALUE clas = rb_obj_class(obj);
|
291
291
|
|
292
292
|
if (oj_bigdecimal_class == clas) {
|
293
|
-
volatile VALUE rstr =
|
293
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
294
294
|
|
295
295
|
oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
|
296
296
|
} else {
|
@@ -302,7 +302,7 @@ static void dump_data_null(VALUE obj, int depth, Out out, bool as_ok) {
|
|
302
302
|
VALUE clas = rb_obj_class(obj);
|
303
303
|
|
304
304
|
if (oj_bigdecimal_class == clas) {
|
305
|
-
volatile VALUE rstr =
|
305
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
306
306
|
|
307
307
|
oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
|
308
308
|
} else {
|
@@ -338,9 +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
|
-
|
342
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
343
|
-
}
|
341
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
344
342
|
if (MAX_DEPTH < depth) {
|
345
343
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
346
344
|
}
|
@@ -349,9 +347,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
|
349
347
|
|
350
348
|
if (NULL != f) {
|
351
349
|
f(obj, depth, out, false);
|
352
|
-
|
353
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
354
|
-
}
|
350
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
355
351
|
return;
|
356
352
|
}
|
357
353
|
}
|
@@ -386,9 +382,7 @@ static DumpFunc null_funcs[] = {
|
|
386
382
|
void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
387
383
|
int type = rb_type(obj);
|
388
384
|
|
389
|
-
|
390
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
391
|
-
}
|
385
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
392
386
|
if (MAX_DEPTH < depth) {
|
393
387
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
394
388
|
}
|
@@ -397,14 +391,10 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
|
397
391
|
|
398
392
|
if (NULL != f) {
|
399
393
|
f(obj, depth, out, false);
|
400
|
-
|
401
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
402
|
-
}
|
394
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
403
395
|
return;
|
404
396
|
}
|
405
397
|
}
|
406
398
|
oj_dump_nil(Qnil, depth, out, false);
|
407
|
-
|
408
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
409
|
-
}
|
399
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
410
400
|
}
|
data/ext/oj/extconf.rb
CHANGED
@@ -35,8 +35,16 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
|
|
35
35
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
36
36
|
|
37
37
|
if with_config('--with-sse42')
|
38
|
-
|
39
|
-
|
38
|
+
if try_cflags('-msse4.2')
|
39
|
+
$CPPFLAGS += ' -msse4.2'
|
40
|
+
dflags['OJ_USE_SSE4_2'] = 1
|
41
|
+
else
|
42
|
+
warn 'SSE 4.2 is not supported on this platform.'
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
if enable_config('trace-log', false)
|
47
|
+
dflags['OJ_ENABLE_TRACE_LOG'] = 1
|
40
48
|
end
|
41
49
|
|
42
50
|
dflags.each do |k,v|
|
data/ext/oj/fast.c
CHANGED
@@ -74,7 +74,7 @@ static char *read_quoted_value(ParseInfo pi);
|
|
74
74
|
static void skip_comment(ParseInfo pi);
|
75
75
|
|
76
76
|
static VALUE protect_open_proc(VALUE x);
|
77
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
77
|
+
static VALUE parse_json(VALUE clas, char *json, bool given);
|
78
78
|
static void each_leaf(Doc doc, VALUE self);
|
79
79
|
static int move_step(Doc doc, const char *path, int loc);
|
80
80
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
@@ -651,7 +651,8 @@ static void doc_free(Doc doc) {
|
|
651
651
|
xfree(b);
|
652
652
|
}
|
653
653
|
}
|
654
|
-
|
654
|
+
xfree(doc->json);
|
655
|
+
xfree(doc);
|
655
656
|
}
|
656
657
|
}
|
657
658
|
|
@@ -671,7 +672,6 @@ static void free_doc_cb(void *x) {
|
|
671
672
|
Doc doc = (Doc)x;
|
672
673
|
|
673
674
|
if (0 != doc) {
|
674
|
-
xfree(doc->json);
|
675
675
|
doc_free(doc);
|
676
676
|
}
|
677
677
|
}
|
@@ -749,20 +749,15 @@ static const rb_data_type_t oj_doc_type = {
|
|
749
749
|
0,
|
750
750
|
};
|
751
751
|
|
752
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
752
|
+
static VALUE parse_json(VALUE clas, char *json, bool given) {
|
753
753
|
struct _parseInfo pi;
|
754
754
|
volatile VALUE result = Qnil;
|
755
755
|
Doc doc;
|
756
756
|
int ex = 0;
|
757
757
|
volatile VALUE self;
|
758
758
|
|
759
|
-
|
759
|
+
doc = RB_ALLOC_N(struct _doc, 1);
|
760
760
|
|
761
|
-
if (given) {
|
762
|
-
doc = ALLOCA_N(struct _doc, 1);
|
763
|
-
} else {
|
764
|
-
doc = ALLOC(struct _doc);
|
765
|
-
}
|
766
761
|
// skip UTF-8 BOM if present
|
767
762
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
768
763
|
pi.str = json + 3;
|
@@ -787,18 +782,20 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
787
782
|
}
|
788
783
|
}
|
789
784
|
#endif
|
785
|
+
doc->json = json;
|
790
786
|
self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
|
791
787
|
doc->self = self;
|
792
|
-
doc->json = json;
|
793
788
|
DATA_PTR(doc->self) = doc;
|
794
789
|
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
795
790
|
if (given || 0 != ex) {
|
796
791
|
DATA_PTR(doc->self) = NULL;
|
792
|
+
// TBD is this needed?
|
793
|
+
/*
|
797
794
|
doc_free(pi.doc);
|
798
|
-
if (
|
795
|
+
if (0 != ex) { // will jump so caller will not free
|
799
796
|
xfree(json);
|
800
797
|
}
|
801
|
-
|
798
|
+
*/
|
802
799
|
} else {
|
803
800
|
result = doc->self;
|
804
801
|
}
|
@@ -1092,27 +1089,19 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
1092
1089
|
size_t len;
|
1093
1090
|
volatile VALUE obj;
|
1094
1091
|
int given = rb_block_given_p();
|
1095
|
-
int allocate;
|
1096
1092
|
|
1097
1093
|
Check_Type(str, T_STRING);
|
1098
1094
|
len = (int)RSTRING_LEN(str) + 1;
|
1099
|
-
|
1100
|
-
|
1101
|
-
json = ALLOC_N(char, len);
|
1102
|
-
} else {
|
1103
|
-
json = ALLOCA_N(char, len);
|
1104
|
-
}
|
1105
|
-
// It should not be necessaary to stop GC but if it is not stopped and a
|
1106
|
-
// large string is parsed that string is corrupted or freed during
|
1107
|
-
// parsing. I'm not sure what is going on exactly but disabling GC avoids
|
1108
|
-
// the issue.
|
1109
|
-
rb_gc_disable();
|
1095
|
+
json = RB_ALLOC_N(char, len);
|
1096
|
+
|
1110
1097
|
memcpy(json, StringValuePtr(str), len);
|
1111
|
-
obj = parse_json(clas, json, given
|
1112
|
-
|
1113
|
-
|
1098
|
+
obj = parse_json(clas, json, given);
|
1099
|
+
// TBD is this needed
|
1100
|
+
/*
|
1101
|
+
if (given) {
|
1114
1102
|
xfree(json);
|
1115
1103
|
}
|
1104
|
+
*/
|
1116
1105
|
return obj;
|
1117
1106
|
}
|
1118
1107
|
|
@@ -1142,7 +1131,6 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1142
1131
|
size_t len;
|
1143
1132
|
volatile VALUE obj;
|
1144
1133
|
int given = rb_block_given_p();
|
1145
|
-
int allocate;
|
1146
1134
|
|
1147
1135
|
Check_Type(filename, T_STRING);
|
1148
1136
|
path = StringValuePtr(filename);
|
@@ -1151,12 +1139,8 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1151
1139
|
}
|
1152
1140
|
fseek(f, 0, SEEK_END);
|
1153
1141
|
len = ftell(f);
|
1154
|
-
|
1155
|
-
|
1156
|
-
json = ALLOC_N(char, len + 1);
|
1157
|
-
} else {
|
1158
|
-
json = ALLOCA_N(char, len + 1);
|
1159
|
-
}
|
1142
|
+
json = RB_ALLOC_N(char, len + 1);
|
1143
|
+
|
1160
1144
|
fseek(f, 0, SEEK_SET);
|
1161
1145
|
if (len != fread(json, 1, len, f)) {
|
1162
1146
|
fclose(f);
|
@@ -1167,12 +1151,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1167
1151
|
}
|
1168
1152
|
fclose(f);
|
1169
1153
|
json[len] = '\0';
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
if (given
|
1154
|
+
obj = parse_json(clas, json, given);
|
1155
|
+
// TBD is this needed
|
1156
|
+
/*
|
1157
|
+
if (given) {
|
1174
1158
|
xfree(json);
|
1175
1159
|
}
|
1160
|
+
*/
|
1176
1161
|
return obj;
|
1177
1162
|
}
|
1178
1163
|
|
@@ -1656,11 +1641,9 @@ static VALUE doc_close(VALUE self) {
|
|
1656
1641
|
Doc doc = self_doc(self);
|
1657
1642
|
|
1658
1643
|
rb_gc_unregister_address(&doc->self);
|
1659
|
-
DATA_PTR(doc->self) =
|
1644
|
+
DATA_PTR(doc->self) = NULL;
|
1660
1645
|
if (0 != doc) {
|
1661
|
-
xfree(doc->json);
|
1662
1646
|
doc_free(doc);
|
1663
|
-
xfree(doc);
|
1664
1647
|
}
|
1665
1648
|
return Qnil;
|
1666
1649
|
}
|
data/ext/oj/object.c
CHANGED
@@ -609,9 +609,7 @@ WHICH_TYPE:
|
|
609
609
|
}
|
610
610
|
|
611
611
|
static VALUE start_hash(ParseInfo pi) {
|
612
|
-
|
613
|
-
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
614
|
-
}
|
612
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
615
613
|
return Qnil;
|
616
614
|
}
|
617
615
|
|
@@ -627,9 +625,7 @@ static void end_hash(ParseInfo pi) {
|
|
627
625
|
oj_odd_free(oa);
|
628
626
|
parent->odd_args = NULL;
|
629
627
|
}
|
630
|
-
|
631
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
632
|
-
}
|
628
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
633
629
|
}
|
634
630
|
|
635
631
|
static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
|
data/ext/oj/oj.h
CHANGED
@@ -379,6 +379,12 @@ extern bool oj_use_hash_alt;
|
|
379
379
|
extern bool oj_use_array_alt;
|
380
380
|
extern bool string_writer_optimized;
|
381
381
|
|
382
|
+
static inline VALUE oj_safe_string_convert(VALUE obj) {
|
383
|
+
VALUE rstr = rb_funcall(obj, oj_to_s_id, 0);
|
384
|
+
StringValue(rstr);
|
385
|
+
return rstr;
|
386
|
+
}
|
387
|
+
|
382
388
|
#define APPEND_CHARS(buffer, chars, size) \
|
383
389
|
{ \
|
384
390
|
memcpy(buffer, chars, size); \
|
data/ext/oj/parse.c
CHANGED
data/ext/oj/parser.c
CHANGED
@@ -1263,7 +1263,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1263
1263
|
// from this function. A delegate must be added before the parser can be
|
1264
1264
|
// used. Optionally oj_parser_set_options can be called if the options are not
|
1265
1265
|
// set directly.
|
1266
|
-
VALUE oj_parser_new() {
|
1266
|
+
VALUE oj_parser_new(void) {
|
1267
1267
|
ojParser p = ALLOC(struct _ojParser);
|
1268
1268
|
|
1269
1269
|
#if HAVE_RB_EXT_RACTOR_SAFE
|
data/ext/oj/rails.c
CHANGED
@@ -198,7 +198,7 @@ static void dump_enumerable(VALUE obj, int depth, Out out, bool as_ok) {
|
|
198
198
|
}
|
199
199
|
|
200
200
|
static void dump_bigdecimal(VALUE obj, int depth, Out out, bool as_ok) {
|
201
|
-
volatile VALUE rstr =
|
201
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
202
202
|
const char * str = RSTRING_PTR(rstr);
|
203
203
|
|
204
204
|
if ('I' == *str || 'N' == *str || ('-' == *str && 'I' == str[1])) {
|
@@ -345,7 +345,7 @@ static void dump_timewithzone(VALUE obj, int depth, Out out, bool as_ok) {
|
|
345
345
|
}
|
346
346
|
|
347
347
|
static void dump_to_s(VALUE obj, int depth, Out out, bool as_ok) {
|
348
|
-
volatile VALUE rstr =
|
348
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
349
349
|
|
350
350
|
oj_dump_cstr(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), 0, 0, out);
|
351
351
|
}
|
@@ -377,7 +377,7 @@ static StrLen columns_array(VALUE rcols, int *ccnt) {
|
|
377
377
|
for (i = 0, cp = cols; i < cnt; i++, cp++) {
|
378
378
|
v = RARRAY_AREF(rcols, i);
|
379
379
|
if (T_STRING != rb_type(v)) {
|
380
|
-
v =
|
380
|
+
v = oj_safe_string_convert(v);
|
381
381
|
}
|
382
382
|
cp->str = StringValuePtr(v);
|
383
383
|
cp->len = (int)RSTRING_LEN(v);
|
@@ -517,9 +517,7 @@ static void dump_as_string(VALUE obj, int depth, Out out, bool as_ok) {
|
|
517
517
|
static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
|
518
518
|
volatile VALUE ja;
|
519
519
|
|
520
|
-
|
521
|
-
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
522
|
-
}
|
520
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyIn);
|
523
521
|
// Some classes elect to not take an options argument so check the arity
|
524
522
|
// of as_json.
|
525
523
|
if (0 == rb_obj_method_arity(obj, oj_as_json_id)) {
|
@@ -527,9 +525,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
|
|
527
525
|
} else {
|
528
526
|
ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
529
527
|
}
|
530
|
-
|
531
|
-
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
532
|
-
}
|
528
|
+
TRACE(out->opts->trace, "as_json", obj, depth + 1, TraceRubyOut);
|
533
529
|
|
534
530
|
out->argc = 0;
|
535
531
|
if (ja == obj || !as_ok) {
|
@@ -1208,7 +1204,7 @@ static void dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1208
1204
|
} else if (oj_rails_float_opt) {
|
1209
1205
|
cnt = oj_dump_float_printf(buf, sizeof(buf), obj, d, "%0.16g");
|
1210
1206
|
} else {
|
1211
|
-
volatile VALUE rstr =
|
1207
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
1212
1208
|
|
1213
1209
|
strcpy(buf, RSTRING_PTR(rstr));
|
1214
1210
|
cnt = (int)RSTRING_LEN(rstr);
|
@@ -1301,7 +1297,7 @@ static int hash_cb(VALUE key, VALUE value, VALUE ov) {
|
|
1301
1297
|
return ST_CONTINUE;
|
1302
1298
|
}
|
1303
1299
|
if (rtype != T_STRING && rtype != T_SYMBOL) {
|
1304
|
-
key =
|
1300
|
+
key = oj_safe_string_convert(key);
|
1305
1301
|
rtype = rb_type(key);
|
1306
1302
|
}
|
1307
1303
|
if (!out->opts->dump_opts.use) {
|
@@ -1464,9 +1460,7 @@ static DumpFunc rails_funcs[] = {
|
|
1464
1460
|
static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
1465
1461
|
int type = rb_type(obj);
|
1466
1462
|
|
1467
|
-
|
1468
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
1469
|
-
}
|
1463
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
1470
1464
|
if (MAX_DEPTH < depth) {
|
1471
1465
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
1472
1466
|
}
|
@@ -1475,16 +1469,12 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1475
1469
|
|
1476
1470
|
if (NULL != f) {
|
1477
1471
|
f(obj, depth, out, as_ok);
|
1478
|
-
|
1479
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
1480
|
-
}
|
1472
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
1481
1473
|
return;
|
1482
1474
|
}
|
1483
1475
|
}
|
1484
1476
|
oj_dump_nil(Qnil, depth, out, false);
|
1485
|
-
|
1486
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
1487
|
-
}
|
1477
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
1488
1478
|
}
|
1489
1479
|
|
1490
1480
|
void oj_dump_rails_val(VALUE obj, int depth, Out out) {
|
data/ext/oj/reader.c
CHANGED
@@ -75,7 +75,7 @@ void oj_reader_init(Reader reader, VALUE io, int fd, bool to_s) {
|
|
75
75
|
reader->read_func = read_from_io;
|
76
76
|
reader->io = io;
|
77
77
|
} else if (to_s) {
|
78
|
-
volatile VALUE rstr =
|
78
|
+
volatile VALUE rstr = oj_safe_string_convert(io);
|
79
79
|
|
80
80
|
reader->read_func = 0;
|
81
81
|
reader->in_str = StringValuePtr(rstr);
|
data/ext/oj/strict.c
CHANGED
@@ -50,15 +50,11 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
|
|
50
50
|
}
|
51
51
|
|
52
52
|
static void hash_end(ParseInfo pi) {
|
53
|
-
|
54
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
55
|
-
}
|
53
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
56
54
|
}
|
57
55
|
|
58
56
|
static void array_end(ParseInfo pi) {
|
59
|
-
|
60
|
-
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
61
|
-
}
|
57
|
+
TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
|
62
58
|
}
|
63
59
|
|
64
60
|
static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
@@ -95,9 +91,7 @@ static VALUE start_hash(ParseInfo pi) {
|
|
95
91
|
if (Qnil != pi->options.hash_class) {
|
96
92
|
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
97
93
|
}
|
98
|
-
|
99
|
-
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
100
|
-
}
|
94
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
101
95
|
return rb_hash_new();
|
102
96
|
}
|
103
97
|
|
@@ -137,9 +131,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
137
131
|
}
|
138
132
|
|
139
133
|
static VALUE start_array(ParseInfo pi) {
|
140
|
-
|
141
|
-
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
142
|
-
}
|
134
|
+
TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
|
143
135
|
return rb_ary_new();
|
144
136
|
}
|
145
137
|
|
data/ext/oj/trace.h
CHANGED
@@ -25,4 +25,20 @@ extern void
|
|
25
25
|
extern void oj_trace_parse_hash_end(struct _parseInfo *pi, const char *file, int line);
|
26
26
|
extern void oj_trace_parse_array_end(struct _parseInfo *pi, const char *file, int line);
|
27
27
|
|
28
|
+
|
29
|
+
#ifdef OJ_ENABLE_TRACE_LOG
|
30
|
+
#define TRACE(option, func, obj, depth, where) if (RB_UNLIKELY(Yes == option)) { oj_trace(func, obj, __FILE__, __LINE__, depth, where); }
|
31
|
+
#define TRACE_PARSE_IN(option, func, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_in(func, pi, __FILE__, __LINE__); }
|
32
|
+
#define TRACE_PARSE_CALL(option, func, pi, obj) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_call(func, pi, __FILE__, __LINE__, obj); }
|
33
|
+
#define TRACE_PARSE_HASH_END(option, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_hash_end(pi, __FILE__, __LINE__); }
|
34
|
+
#define TRACE_PARSE_ARRAY_END(option, pi) if (RB_UNLIKELY(Yes == option)) { oj_trace_parse_array_end(pi, __FILE__, __LINE__); }
|
35
|
+
#else
|
36
|
+
#define TRACE(option, func, obj, depth, where)
|
37
|
+
#define TRACE_PARSE_IN(option, func, pi)
|
38
|
+
#define TRACE_PARSE_CALL(option, func, pi, obj)
|
39
|
+
#define TRACE_PARSE_HASH_END(option, pi)
|
40
|
+
#define TRACE_PARSE_ARRAY_END(option, pi)
|
41
|
+
#endif
|
42
|
+
|
43
|
+
|
28
44
|
#endif /* OJ_TRACE_H */
|
data/ext/oj/wab.c
CHANGED
@@ -226,13 +226,13 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
226
226
|
if (rb_cTime == clas) {
|
227
227
|
dump_time(obj, out);
|
228
228
|
} else if (oj_bigdecimal_class == clas) {
|
229
|
-
volatile VALUE rstr =
|
229
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
230
230
|
|
231
231
|
oj_dump_raw(RSTRING_PTR(rstr), (int)RSTRING_LEN(rstr), out);
|
232
232
|
} else if (resolve_wab_uuid_class() == clas) {
|
233
|
-
oj_dump_str(
|
233
|
+
oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
|
234
234
|
} else if (resolve_uri_http_class() == clas) {
|
235
|
-
oj_dump_str(
|
235
|
+
oj_dump_str(oj_safe_string_convert(obj), depth, out, false);
|
236
236
|
} else {
|
237
237
|
raise_wab(obj);
|
238
238
|
}
|
@@ -266,9 +266,7 @@ static DumpFunc wab_funcs[] = {
|
|
266
266
|
void oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
267
267
|
int type = rb_type(obj);
|
268
268
|
|
269
|
-
|
270
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
271
|
-
}
|
269
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
272
270
|
if (MAX_DEPTH < depth) {
|
273
271
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
274
272
|
}
|
@@ -277,9 +275,7 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
277
275
|
|
278
276
|
if (NULL != f) {
|
279
277
|
f(obj, depth, out, false);
|
280
|
-
|
281
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
282
|
-
}
|
278
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
283
279
|
return;
|
284
280
|
}
|
285
281
|
}
|
@@ -312,15 +308,11 @@ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
|
|
312
308
|
}
|
313
309
|
|
314
310
|
static void hash_end(ParseInfo pi) {
|
315
|
-
|
316
|
-
oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
|
317
|
-
}
|
311
|
+
TRACE_PARSE_HASH_END(pi->options.trace, pi);
|
318
312
|
}
|
319
313
|
|
320
314
|
static void array_end(ParseInfo pi) {
|
321
|
-
|
322
|
-
oj_trace_parse_array_end(pi, __FILE__, __LINE__);
|
323
|
-
}
|
315
|
+
TRACE_PARSE_ARRAY_END(pi->options.trace, pi);
|
324
316
|
}
|
325
317
|
|
326
318
|
static VALUE noop_hash_key(ParseInfo pi, const char *key, size_t klen) {
|
@@ -494,9 +486,7 @@ static void add_num(ParseInfo pi, NumInfo ni) {
|
|
494
486
|
}
|
495
487
|
|
496
488
|
static VALUE start_hash(ParseInfo pi) {
|
497
|
-
|
498
|
-
oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
|
499
|
-
}
|
489
|
+
TRACE_PARSE_IN(pi->options.trace, "start_hash", pi);
|
500
490
|
if (Qnil != pi->options.hash_class) {
|
501
491
|
return rb_class_new_instance(0, NULL, pi->options.hash_class);
|
502
492
|
}
|
@@ -533,9 +523,7 @@ static void hash_set_value(ParseInfo pi, Val parent, VALUE value) {
|
|
533
523
|
}
|
534
524
|
|
535
525
|
static VALUE start_array(ParseInfo pi) {
|
536
|
-
|
537
|
-
oj_trace_parse_in("start_array", pi, __FILE__, __LINE__);
|
538
|
-
}
|
526
|
+
TRACE_PARSE_IN(pi->options.trace, "start_array", pi);
|
539
527
|
return rb_ary_new();
|
540
528
|
}
|
541
529
|
|
data/lib/oj/version.rb
CHANGED
@@ -0,0 +1,20 @@
|
|
1
|
+
# Oj Install Options
|
2
|
+
|
3
|
+
### Enable trace log
|
4
|
+
|
5
|
+
```
|
6
|
+
$ gem install oj -- --enable-trace-log
|
7
|
+
```
|
8
|
+
|
9
|
+
To enable Oj trace feature, it uses `--enable-trace-log` option when installing the gem.
|
10
|
+
Then, the trace logs will be displayed when `:trace` option is set to `true`.
|
11
|
+
|
12
|
+
|
13
|
+
### Enable SIMD instructions
|
14
|
+
|
15
|
+
```
|
16
|
+
$ gem install oj -- --with-sse42
|
17
|
+
```
|
18
|
+
|
19
|
+
To enable the use of SIMD instructions in Oj, it uses the `--with-sse42` option when installing the gem.
|
20
|
+
This will enable the use of the SSE4.2 instructions in the internal.
|
data/test/foo.rb
CHANGED
@@ -5,73 +5,25 @@ $: << File.join(File.dirname(__FILE__), "../lib")
|
|
5
5
|
$: << File.join(File.dirname(__FILE__), "../ext")
|
6
6
|
|
7
7
|
require "oj"
|
8
|
-
require "socket"
|
9
|
-
require 'io/nonblock'
|
10
8
|
|
11
|
-
#pid = spawn("nc -d 0.1 -l 5000", out: "/dev/null")
|
12
|
-
pid = spawn("nc -i 1 -l 7777", out: "/dev/null")
|
13
|
-
at_exit { Process.kill 9, pid }
|
14
|
-
sleep 0.2
|
15
|
-
s = Socket.tcp("localhost", 7777)
|
16
|
-
s.nonblock = false
|
17
|
-
1_000_000.times do |x|
|
18
|
-
Oj.to_stream(s, { x: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]})
|
19
|
-
end
|
20
9
|
|
21
|
-
=
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
w.close
|
38
|
-
sleep(0.1)
|
39
|
-
r.each_line { |b|
|
40
|
-
#print b
|
41
|
-
}
|
42
|
-
r.close
|
43
|
-
Process.exit(0)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
=end
|
10
|
+
p = Oj::Parser.new(:saj)
|
11
|
+
|
12
|
+
json = %|{
|
13
|
+
"array": [
|
14
|
+
{
|
15
|
+
"num" : 3,
|
16
|
+
"string": "message",
|
17
|
+
"hash" : {
|
18
|
+
"h2" : {
|
19
|
+
"a" : [ 1, 2, 3 ]
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
23
|
+
],
|
24
|
+
"boolean" : true
|
25
|
+
}|
|
47
26
|
|
48
|
-
|
49
|
-
|
50
|
-
if fork
|
51
|
-
r.close
|
52
|
-
#w.nonblock = false
|
53
|
-
a = []
|
54
|
-
10_000.times do |i|
|
55
|
-
a << i
|
56
|
-
end
|
57
|
-
begin
|
58
|
-
Oj.to_stream(w, a, indent: 2)
|
59
|
-
rescue IOError => e
|
60
|
-
puts "*** raised #{e.class}: #{e}"
|
61
|
-
puts "*** fileno: #{w.fileno}"
|
62
|
-
puts "*** is an IO?: #{w.kind_of?(IO)}"
|
63
|
-
IO.select(nil, [w])
|
64
|
-
retry
|
65
|
-
end
|
66
|
-
w.puts
|
67
|
-
else
|
68
|
-
w.close
|
69
|
-
sleep(0.5)
|
70
|
-
r.each_line { |b|
|
71
|
-
#print b
|
72
|
-
}
|
73
|
-
r.close
|
74
|
-
Process.exit(0)
|
75
|
-
end
|
27
|
+
1_000_000.times do
|
28
|
+
e = Oj.load(json)
|
76
29
|
end
|
77
|
-
=end
|
data/test/test_compat.rb
CHANGED
@@ -513,6 +513,15 @@ class CompatJuice < Minitest::Test
|
|
513
513
|
assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
|
514
514
|
end
|
515
515
|
|
516
|
+
def test_invalid_to_s
|
517
|
+
obj = Object.new
|
518
|
+
def obj.to_s
|
519
|
+
nil
|
520
|
+
end
|
521
|
+
|
522
|
+
assert_raises(TypeError) { Oj.dump(obj, mode: :compat) }
|
523
|
+
end
|
524
|
+
|
516
525
|
def dump_and_load(obj, trace=false)
|
517
526
|
json = Oj.dump(obj)
|
518
527
|
puts json if trace
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.14.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|
@@ -72,6 +72,7 @@ extra_rdoc_files:
|
|
72
72
|
- pages/Compatibility.md
|
73
73
|
- pages/Custom.md
|
74
74
|
- pages/Encoding.md
|
75
|
+
- pages/InstallOptions.md
|
75
76
|
- pages/JsonGem.md
|
76
77
|
- pages/Modes.md
|
77
78
|
- pages/Options.md
|
@@ -161,6 +162,7 @@ files:
|
|
161
162
|
- pages/Compatibility.md
|
162
163
|
- pages/Custom.md
|
163
164
|
- pages/Encoding.md
|
165
|
+
- pages/InstallOptions.md
|
164
166
|
- pages/JsonGem.md
|
165
167
|
- pages/Modes.md
|
166
168
|
- pages/Options.md
|