oj 3.13.23 → 3.14.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/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
|
# [](http://www.ohler.com/oj) gem
|
2
2
|
|
3
|
-
[](https://github.com/ohler55/oj/actions/workflows/CI.yml)
|
4
4
|

|
5
5
|

|
6
6
|
[](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
|