oj 3.13.22 → 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 +10 -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.c +2 -2
- data/ext/oj/oj.h +6 -0
- data/ext/oj/parse.c +4 -0
- data/ext/oj/parser.c +7 -3
- 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/pages/Options.md +6 -0
- data/test/foo.rb +18 -66
- data/test/test_compat.rb +9 -0
- metadata +4 -3
- data/ext/oj/introspect.c +0 -96
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.c
CHANGED
@@ -243,7 +243,7 @@ struct _options oj_default_options = {
|
|
243
243
|
*references
|
244
244
|
* - *:auto_define* [_Boolean_|_nil_] automatically define classes if they do not exist
|
245
245
|
* - *:symbol_keys* [_Boolean_|_nil_] use symbols instead of strings for hash keys
|
246
|
-
* - *:escape_mode* [_:newline_|_:json_|_:xss_safe_|_:ascii_|
|
246
|
+
* - *:escape_mode* [_:newline_|_:json_|_:slash_|_:xss_safe_|_:ascii_|_:unicode_xss_|_nil_] determines the
|
247
247
|
*characters to escape
|
248
248
|
* - *:class_cache* [_Boolean_|_nil_] cache classes for faster parsing (if dynamically modifying
|
249
249
|
*classes or reloading classes then don't use this)
|
@@ -251,7 +251,7 @@ struct _options oj_default_options = {
|
|
251
251
|
*to use for JSON
|
252
252
|
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
253
253
|
* - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
|
254
|
-
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead
|
254
|
+
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_|_:ruby_] load decimals as BigDecimal instead
|
255
255
|
*of as a Float. :auto pick the most precise for the number of digits. :float should be the same as
|
256
256
|
*ruby. :fast may require rounding but is must faster.
|
257
257
|
* - *:compat_bigdecimal* [_true_|_false_] load decimals as BigDecimal instead of as a Float when in
|
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
@@ -1145,7 +1145,9 @@ static void parser_free(void *ptr) {
|
|
1145
1145
|
p = (ojParser)ptr;
|
1146
1146
|
buf_cleanup(&p->key);
|
1147
1147
|
buf_cleanup(&p->buf);
|
1148
|
-
p->free
|
1148
|
+
if (NULL != p->free) {
|
1149
|
+
p->free(p);
|
1150
|
+
}
|
1149
1151
|
xfree(ptr);
|
1150
1152
|
}
|
1151
1153
|
|
@@ -1156,7 +1158,9 @@ static void parser_mark(void *ptr) {
|
|
1156
1158
|
if (0 != p->reader) {
|
1157
1159
|
rb_gc_mark(p->reader);
|
1158
1160
|
}
|
1159
|
-
p->mark
|
1161
|
+
if (NULL != p->mark) {
|
1162
|
+
p->mark(p);
|
1163
|
+
}
|
1160
1164
|
}
|
1161
1165
|
}
|
1162
1166
|
|
@@ -1259,7 +1263,7 @@ static VALUE parser_new(int argc, VALUE *argv, VALUE self) {
|
|
1259
1263
|
// from this function. A delegate must be added before the parser can be
|
1260
1264
|
// used. Optionally oj_parser_set_options can be called if the options are not
|
1261
1265
|
// set directly.
|
1262
|
-
VALUE oj_parser_new() {
|
1266
|
+
VALUE oj_parser_new(void) {
|
1263
1267
|
ojParser p = ALLOC(struct _ojParser);
|
1264
1268
|
|
1265
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/pages/Options.md
CHANGED
@@ -66,6 +66,10 @@ Determines how to load decimals.
|
|
66
66
|
|
67
67
|
- `:auto` the most precise for the number of digits is used.
|
68
68
|
|
69
|
+
- `:fast` faster conversion to Float.
|
70
|
+
|
71
|
+
- `:ruby` convert to Float using the Ruby `to_f` conversion.
|
72
|
+
|
69
73
|
This can also be set with `:decimal_class` when used as a load or
|
70
74
|
parse option to match the JSON gem. In that case either `Float`,
|
71
75
|
`BigDecimal`, or `nil` can be provided.
|
@@ -154,6 +158,8 @@ Determines the characters to escape when dumping. Only the :ascii and
|
|
154
158
|
|
155
159
|
- `:json` follows the JSON specification. This is the default mode.
|
156
160
|
|
161
|
+
- `:slash` escapes `/` characters.
|
162
|
+
|
157
163
|
- `:xss_safe` escapes HTML and XML characters such as `&` and `<`.
|
158
164
|
|
159
165
|
- `:ascii` escapes all non-ascii or characters with the hi-bit set.
|
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
|