oj 3.13.23 → 3.14.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +2 -1
- data/ext/oj/buf.h +6 -5
- data/ext/oj/cache.c +11 -10
- data/ext/oj/cache8.c +3 -2
- data/ext/oj/circarray.c +6 -5
- data/ext/oj/compat.c +12 -31
- data/ext/oj/custom.c +16 -31
- data/ext/oj/dump.c +10 -13
- data/ext/oj/dump_compat.c +9 -19
- data/ext/oj/dump_object.c +8 -13
- data/ext/oj/dump_strict.c +8 -18
- data/ext/oj/extconf.rb +10 -2
- data/ext/oj/fast.c +31 -47
- data/ext/oj/intern.c +7 -5
- data/ext/oj/mem.c +324 -0
- data/ext/oj/mem.h +53 -0
- data/ext/oj/mimic_json.c +3 -2
- data/ext/oj/object.c +9 -13
- data/ext/oj/odd.c +7 -6
- data/ext/oj/oj.c +12 -5
- data/ext/oj/oj.h +6 -0
- data/ext/oj/parse.c +18 -13
- data/ext/oj/parser.c +7 -7
- data/ext/oj/rails.c +19 -28
- data/ext/oj/reader.c +4 -3
- data/ext/oj/reader.h +3 -1
- data/ext/oj/rxclass.c +5 -4
- data/ext/oj/saj.c +6 -5
- data/ext/oj/saj2.c +10 -5
- data/ext/oj/sparse.c +5 -4
- data/ext/oj/stream_writer.c +5 -4
- data/ext/oj/strict.c +4 -12
- data/ext/oj/string_writer.c +7 -6
- data/ext/oj/trace.h +16 -0
- data/ext/oj/usual.c +28 -27
- data/ext/oj/val_stack.h +4 -3
- data/ext/oj/wab.c +9 -21
- data/lib/oj/version.rb +1 -1
- data/pages/InstallOptions.md +20 -0
- data/test/foo.rb +46 -65
- data/test/perf_parser.rb +1 -0
- data/test/test_compat.rb +9 -0
- metadata +7 -3
data/ext/oj/dump_object.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
// Copyright (c) 2012, 2017 Peter Ohler. All rights reserved.
|
2
2
|
// Licensed under the MIT License. See LICENSE file in the project root for license details.
|
3
3
|
|
4
|
+
#include "mem.h"
|
4
5
|
#include "dump.h"
|
5
6
|
#include "odd.h"
|
6
7
|
#include "trace.h"
|
@@ -30,7 +31,7 @@ static void dump_data(VALUE obj, int depth, Out out, bool as_ok) {
|
|
30
31
|
*out->cur = '\0';
|
31
32
|
} else {
|
32
33
|
if (oj_bigdecimal_class == clas) {
|
33
|
-
volatile VALUE rstr =
|
34
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
34
35
|
const char * str = RSTRING_PTR(rstr);
|
35
36
|
int len = (int)RSTRING_LEN(rstr);
|
36
37
|
|
@@ -59,7 +60,7 @@ static void dump_obj(VALUE obj, int depth, Out out, bool as_ok) {
|
|
59
60
|
VALUE clas = rb_obj_class(obj);
|
60
61
|
|
61
62
|
if (oj_bigdecimal_class == clas) {
|
62
|
-
volatile VALUE rstr =
|
63
|
+
volatile VALUE rstr = oj_safe_string_convert(obj);
|
63
64
|
const char * str = RSTRING_PTR(rstr);
|
64
65
|
int len = (int)RSTRING_LEN(rstr);
|
65
66
|
|
@@ -422,7 +423,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
422
423
|
ID i;
|
423
424
|
|
424
425
|
if (sizeof(nbuf) <= nlen) {
|
425
|
-
if (NULL == (n2 =
|
426
|
+
if (NULL == (n2 = OJ_STRDUP(name))) {
|
426
427
|
rb_raise(rb_eNoMemError, "for attribute name.");
|
427
428
|
}
|
428
429
|
} else {
|
@@ -439,7 +440,7 @@ static void dump_odd(VALUE obj, Odd odd, VALUE clas, int depth, Out out) {
|
|
439
440
|
i = rb_intern(n);
|
440
441
|
v = rb_funcall(v, i, 0);
|
441
442
|
if (nbuf != n2) {
|
442
|
-
|
443
|
+
OJ_FREE(n2);
|
443
444
|
}
|
444
445
|
}
|
445
446
|
fill_indent(out, d2);
|
@@ -682,9 +683,7 @@ static DumpFunc obj_funcs[] = {
|
|
682
683
|
void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
683
684
|
int type = rb_type(obj);
|
684
685
|
|
685
|
-
|
686
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
687
|
-
}
|
686
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceIn);
|
688
687
|
if (MAX_DEPTH < depth) {
|
689
688
|
rb_raise(rb_eNoMemError, "Too deeply nested.\n");
|
690
689
|
}
|
@@ -693,14 +692,10 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
693
692
|
|
694
693
|
if (NULL != f) {
|
695
694
|
f(obj, depth, out, false);
|
696
|
-
|
697
|
-
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
698
|
-
}
|
695
|
+
TRACE(out->opts->trace, "dump", obj, depth, TraceOut);
|
699
696
|
return;
|
700
697
|
}
|
701
698
|
}
|
702
699
|
oj_dump_nil(Qnil, depth, out, false);
|
703
|
-
|
704
|
-
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
705
|
-
}
|
700
|
+
TRACE(out->opts->trace, "dump", Qnil, depth, TraceOut);
|
706
701
|
}
|
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
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <stdlib.h>
|
12
12
|
#include <string.h>
|
13
13
|
|
14
|
+
#include "mem.h"
|
14
15
|
#include "encode.h"
|
15
16
|
#include "oj.h"
|
16
17
|
#include "dump.h"
|
@@ -74,7 +75,7 @@ static char *read_quoted_value(ParseInfo pi);
|
|
74
75
|
static void skip_comment(ParseInfo pi);
|
75
76
|
|
76
77
|
static VALUE protect_open_proc(VALUE x);
|
77
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
78
|
+
static VALUE parse_json(VALUE clas, char *json, bool given);
|
78
79
|
static void each_leaf(Doc doc, VALUE self);
|
79
80
|
static int move_step(Doc doc, const char *path, int loc);
|
80
81
|
static Leaf get_doc_leaf(Doc doc, const char *path);
|
@@ -160,7 +161,7 @@ inline static Leaf leaf_new(Doc doc, int type) {
|
|
160
161
|
Leaf leaf;
|
161
162
|
|
162
163
|
if (0 == doc->batches || BATCH_SIZE == doc->batches->next_avail) {
|
163
|
-
Batch b =
|
164
|
+
Batch b = OJ_R_ALLOC(struct _batch);
|
164
165
|
|
165
166
|
// Initializes all leaves with a NO_VAL value_type
|
166
167
|
memset(b, 0, sizeof(struct _batch));
|
@@ -648,10 +649,11 @@ static void doc_free(Doc doc) {
|
|
648
649
|
while (0 != (b = doc->batches)) {
|
649
650
|
doc->batches = doc->batches->next;
|
650
651
|
if (&doc->batch0 != b) {
|
651
|
-
|
652
|
+
OJ_R_FREE(b);
|
652
653
|
}
|
653
654
|
}
|
654
|
-
|
655
|
+
OJ_R_FREE(doc->json);
|
656
|
+
OJ_R_FREE(doc);
|
655
657
|
}
|
656
658
|
}
|
657
659
|
|
@@ -671,7 +673,6 @@ static void free_doc_cb(void *x) {
|
|
671
673
|
Doc doc = (Doc)x;
|
672
674
|
|
673
675
|
if (0 != doc) {
|
674
|
-
xfree(doc->json);
|
675
676
|
doc_free(doc);
|
676
677
|
}
|
677
678
|
}
|
@@ -749,20 +750,15 @@ static const rb_data_type_t oj_doc_type = {
|
|
749
750
|
0,
|
750
751
|
};
|
751
752
|
|
752
|
-
static VALUE parse_json(VALUE clas, char *json, bool given
|
753
|
+
static VALUE parse_json(VALUE clas, char *json, bool given) {
|
753
754
|
struct _parseInfo pi;
|
754
755
|
volatile VALUE result = Qnil;
|
755
756
|
Doc doc;
|
756
757
|
int ex = 0;
|
757
758
|
volatile VALUE self;
|
758
759
|
|
759
|
-
|
760
|
+
doc = OJ_R_ALLOC_N(struct _doc, 1);
|
760
761
|
|
761
|
-
if (given) {
|
762
|
-
doc = ALLOCA_N(struct _doc, 1);
|
763
|
-
} else {
|
764
|
-
doc = ALLOC(struct _doc);
|
765
|
-
}
|
766
762
|
// skip UTF-8 BOM if present
|
767
763
|
if (0xEF == (uint8_t)*json && 0xBB == (uint8_t)json[1] && 0xBF == (uint8_t)json[2]) {
|
768
764
|
pi.str = json + 3;
|
@@ -787,18 +783,20 @@ static VALUE parse_json(VALUE clas, char *json, bool given, bool allocated) {
|
|
787
783
|
}
|
788
784
|
}
|
789
785
|
#endif
|
786
|
+
doc->json = json;
|
790
787
|
self = TypedData_Wrap_Struct(clas, &oj_doc_type, doc);
|
791
788
|
doc->self = self;
|
792
|
-
doc->json = json;
|
793
789
|
DATA_PTR(doc->self) = doc;
|
794
790
|
result = rb_protect(protect_open_proc, (VALUE)&pi, &ex);
|
795
791
|
if (given || 0 != ex) {
|
796
792
|
DATA_PTR(doc->self) = NULL;
|
793
|
+
// TBD is this needed?
|
794
|
+
/*
|
797
795
|
doc_free(pi.doc);
|
798
|
-
if (
|
799
|
-
|
796
|
+
if (0 != ex) { // will jump so caller will not free
|
797
|
+
OJ_R_FREE(json);
|
800
798
|
}
|
801
|
-
|
799
|
+
*/
|
802
800
|
} else {
|
803
801
|
result = doc->self;
|
804
802
|
}
|
@@ -1092,27 +1090,19 @@ static VALUE doc_open(VALUE clas, VALUE str) {
|
|
1092
1090
|
size_t len;
|
1093
1091
|
volatile VALUE obj;
|
1094
1092
|
int given = rb_block_given_p();
|
1095
|
-
int allocate;
|
1096
1093
|
|
1097
1094
|
Check_Type(str, T_STRING);
|
1098
1095
|
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();
|
1096
|
+
json = OJ_R_ALLOC_N(char, len);
|
1097
|
+
|
1110
1098
|
memcpy(json, StringValuePtr(str), len);
|
1111
|
-
obj = parse_json(clas, json, given
|
1112
|
-
|
1113
|
-
|
1114
|
-
|
1099
|
+
obj = parse_json(clas, json, given);
|
1100
|
+
// TBD is this needed
|
1101
|
+
/*
|
1102
|
+
if (given) {
|
1103
|
+
OJ_R_FREE(json);
|
1115
1104
|
}
|
1105
|
+
*/
|
1116
1106
|
return obj;
|
1117
1107
|
}
|
1118
1108
|
|
@@ -1142,7 +1132,6 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1142
1132
|
size_t len;
|
1143
1133
|
volatile VALUE obj;
|
1144
1134
|
int given = rb_block_given_p();
|
1145
|
-
int allocate;
|
1146
1135
|
|
1147
1136
|
Check_Type(filename, T_STRING);
|
1148
1137
|
path = StringValuePtr(filename);
|
@@ -1151,12 +1140,8 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1151
1140
|
}
|
1152
1141
|
fseek(f, 0, SEEK_END);
|
1153
1142
|
len = ftell(f);
|
1154
|
-
|
1155
|
-
|
1156
|
-
json = ALLOC_N(char, len + 1);
|
1157
|
-
} else {
|
1158
|
-
json = ALLOCA_N(char, len + 1);
|
1159
|
-
}
|
1143
|
+
json = OJ_R_ALLOC_N(char, len + 1);
|
1144
|
+
|
1160
1145
|
fseek(f, 0, SEEK_SET);
|
1161
1146
|
if (len != fread(json, 1, len, f)) {
|
1162
1147
|
fclose(f);
|
@@ -1167,12 +1152,13 @@ static VALUE doc_open_file(VALUE clas, VALUE filename) {
|
|
1167
1152
|
}
|
1168
1153
|
fclose(f);
|
1169
1154
|
json[len] = '\0';
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
if (given
|
1174
|
-
|
1155
|
+
obj = parse_json(clas, json, given);
|
1156
|
+
// TBD is this needed
|
1157
|
+
/*
|
1158
|
+
if (given) {
|
1159
|
+
OJ_R_FREE(json);
|
1175
1160
|
}
|
1161
|
+
*/
|
1176
1162
|
return obj;
|
1177
1163
|
}
|
1178
1164
|
|
@@ -1656,11 +1642,9 @@ static VALUE doc_close(VALUE self) {
|
|
1656
1642
|
Doc doc = self_doc(self);
|
1657
1643
|
|
1658
1644
|
rb_gc_unregister_address(&doc->self);
|
1659
|
-
DATA_PTR(doc->self) =
|
1645
|
+
DATA_PTR(doc->self) = NULL;
|
1660
1646
|
if (0 != doc) {
|
1661
|
-
xfree(doc->json);
|
1662
1647
|
doc_free(doc);
|
1663
|
-
xfree(doc);
|
1664
1648
|
}
|
1665
1649
|
return Qnil;
|
1666
1650
|
}
|
data/ext/oj/intern.c
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
#if HAVE_PTHREAD_MUTEX_INIT
|
9
9
|
#include <pthread.h>
|
10
10
|
#endif
|
11
|
+
|
12
|
+
#include "mem.h"
|
11
13
|
#include "cache.h"
|
12
14
|
#include "parse.h"
|
13
15
|
|
@@ -55,7 +57,7 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
55
57
|
char buf[256];
|
56
58
|
|
57
59
|
if (sizeof(buf) - 2 <= len) {
|
58
|
-
char *b =
|
60
|
+
char *b = OJ_R_ALLOC_N(char, len + 2);
|
59
61
|
ID id;
|
60
62
|
|
61
63
|
if ('~' == *str) {
|
@@ -68,7 +70,7 @@ static VALUE form_attr(const char *str, size_t len) {
|
|
68
70
|
b[len + 1] = '\0';
|
69
71
|
}
|
70
72
|
id = rb_intern3(buf, len + 1, oj_utf8_encoding);
|
71
|
-
|
73
|
+
OJ_R_FREE(b);
|
72
74
|
return id;
|
73
75
|
}
|
74
76
|
if ('~' == *str) {
|
@@ -246,7 +248,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
246
248
|
}
|
247
249
|
bucket = b;
|
248
250
|
}
|
249
|
-
b =
|
251
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
250
252
|
b->next = NULL;
|
251
253
|
bucket->next = b;
|
252
254
|
bucket = b;
|
@@ -267,7 +269,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
267
269
|
}
|
268
270
|
bucket = b;
|
269
271
|
}
|
270
|
-
b =
|
272
|
+
b = OJ_R_ALLOC(struct _keyVal);
|
271
273
|
b->next = NULL;
|
272
274
|
bucket->next = b;
|
273
275
|
bucket = b;
|
@@ -281,7 +283,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
|
|
281
283
|
}
|
282
284
|
|
283
285
|
char *oj_strndup(const char *s, size_t len) {
|
284
|
-
char *d =
|
286
|
+
char *d = OJ_R_ALLOC_N(char, len + 1);
|
285
287
|
|
286
288
|
memcpy(d, s, len);
|
287
289
|
d[len] = '\0';
|