oj 3.13.16 → 3.13.19
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 +12 -0
- data/ext/oj/buf.h +4 -0
- data/ext/oj/custom.c +7 -7
- data/ext/oj/dump.c +2 -2
- data/ext/oj/dump_compat.c +5 -5
- data/ext/oj/dump_object.c +3 -3
- data/ext/oj/dump_strict.c +5 -5
- data/ext/oj/extconf.rb +14 -2
- data/ext/oj/oj.c +1 -0
- data/ext/oj/parse.c +116 -80
- data/ext/oj/parse.h +2 -0
- data/ext/oj/parser.c +29 -26
- data/ext/oj/rails.c +5 -5
- data/ext/oj/saj2.c +3 -3
- data/ext/oj/validate.c +21 -26
- data/ext/oj/wab.c +2 -2
- data/lib/oj/version.rb +1 -1
- data/test/bar.rb +3 -8
- data/test/helper.rb +8 -2
- data/test/json_gem/test_helper.rb +7 -3
- data/test/test_compat.rb +9 -0
- data/test/test_object.rb +1 -1
- data/test/test_parser_saj.rb +11 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfbe0dd2157d1aba97ad11d82eee1870fbb64f4f197ae75b17a2e781c64144f7
|
4
|
+
data.tar.gz: 907ff02298adc4555834ca1c1c6078a3586abfde85f790b4dcba284c5be60248
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c56828991af620bb1436db19b5660ec588fce4858b455bd2b6c7f11f2bccaf3a7afca8fe98b62ad868a1a18ab584d38220e1b5c4c1243d3a8c1201c3b0c51a54
|
7
|
+
data.tar.gz: f687f4bd9a0a64ecd75cee755722cc2f4f80fc356fe884fd34bf5cf68066d2e648050de7a49c93c121740e790afbcc168b1a8efc5f8280f64ca9bf3d23bc736b
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.13.19 - 2022-07-29
|
4
|
+
|
5
|
+
- TruffleRuby issues resolved.
|
6
|
+
|
7
|
+
## 3.13.18 - 2022-07-25
|
8
|
+
|
9
|
+
- Fixed SSE detection at run time.
|
10
|
+
|
11
|
+
## 3.13.17 - 2022-07-15
|
12
|
+
|
13
|
+
- Fixed Oj::Parser to detect unterminated arrays and objects.
|
14
|
+
|
3
15
|
## 3.13.16 - 2022-07-06
|
4
16
|
|
5
17
|
- Added line and column as optional arguments to the Oj::Parser.saj parser.
|
data/ext/oj/buf.h
CHANGED
@@ -39,6 +39,10 @@ inline static const char *buf_str(Buf buf) {
|
|
39
39
|
}
|
40
40
|
|
41
41
|
inline static void buf_append_string(Buf buf, const char *s, size_t slen) {
|
42
|
+
if (0 == slen) {
|
43
|
+
return;
|
44
|
+
}
|
45
|
+
|
42
46
|
if (buf->end <= buf->tail + slen) {
|
43
47
|
size_t len = buf->end - buf->head;
|
44
48
|
size_t toff = buf->tail - buf->head;
|
data/ext/oj/custom.c
CHANGED
@@ -484,7 +484,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
484
484
|
const char * s;
|
485
485
|
int len;
|
486
486
|
|
487
|
-
if (Yes == out->opts->trace) {
|
487
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
488
488
|
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
489
489
|
}
|
490
490
|
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
@@ -492,7 +492,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
492
492
|
} else {
|
493
493
|
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
494
494
|
}
|
495
|
-
if (Yes == out->opts->trace) {
|
495
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
496
496
|
oj_trace("to_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
497
497
|
}
|
498
498
|
s = RSTRING_PTR(rs);
|
@@ -504,7 +504,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
504
504
|
} else if (Yes == out->opts->as_json && rb_respond_to(obj, oj_as_json_id)) {
|
505
505
|
volatile VALUE aj;
|
506
506
|
|
507
|
-
if (Yes == out->opts->trace) {
|
507
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
508
508
|
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
509
509
|
}
|
510
510
|
// Some classes elect to not take an options argument so check the arity
|
@@ -514,7 +514,7 @@ static VALUE dump_common(VALUE obj, int depth, Out out) {
|
|
514
514
|
} else {
|
515
515
|
aj = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
516
516
|
}
|
517
|
-
if (Yes == out->opts->trace) {
|
517
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
518
518
|
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
519
519
|
}
|
520
520
|
// Catch the obvious brain damaged recursive dumping.
|
@@ -885,7 +885,7 @@ static DumpFunc custom_funcs[] = {
|
|
885
885
|
void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
886
886
|
int type = rb_type(obj);
|
887
887
|
|
888
|
-
if (Yes == out->opts->trace) {
|
888
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
889
889
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
890
890
|
}
|
891
891
|
if (MAX_DEPTH < depth) {
|
@@ -896,14 +896,14 @@ void oj_dump_custom_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
896
896
|
|
897
897
|
if (NULL != f) {
|
898
898
|
f(obj, depth, out, true);
|
899
|
-
if (Yes == out->opts->trace) {
|
899
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
900
900
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
901
901
|
}
|
902
902
|
return;
|
903
903
|
}
|
904
904
|
}
|
905
905
|
oj_dump_nil(Qnil, depth, out, false);
|
906
|
-
if (Yes == out->opts->trace) {
|
906
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
907
907
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
908
908
|
}
|
909
909
|
}
|
data/ext/oj/dump.c
CHANGED
@@ -736,11 +736,11 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
736
736
|
} else {
|
737
737
|
volatile VALUE jv;
|
738
738
|
|
739
|
-
if (Yes == out->opts->trace) {
|
739
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
740
740
|
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
741
741
|
}
|
742
742
|
jv = rb_funcall(obj, oj_raw_json_id, 2, RB_INT2NUM(depth), RB_INT2NUM(out->indent));
|
743
|
-
if (Yes == out->opts->trace) {
|
743
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
744
744
|
oj_trace("raw_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
745
745
|
}
|
746
746
|
oj_dump_raw(RSTRING_PTR(jv), (size_t)RSTRING_LEN(jv), out);
|
data/ext/oj/dump_compat.c
CHANGED
@@ -109,7 +109,7 @@ dump_to_json(VALUE obj, Out out) {
|
|
109
109
|
const char *s;
|
110
110
|
int len;
|
111
111
|
|
112
|
-
if (Yes == out->opts->trace) {
|
112
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
113
113
|
oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyIn);
|
114
114
|
}
|
115
115
|
if (0 == rb_obj_method_arity(obj, oj_to_json_id)) {
|
@@ -117,7 +117,7 @@ dump_to_json(VALUE obj, Out out) {
|
|
117
117
|
} else {
|
118
118
|
rs = rb_funcall2(obj, oj_to_json_id, out->argc, out->argv);
|
119
119
|
}
|
120
|
-
if (Yes == out->opts->trace) {
|
120
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
121
121
|
oj_trace("to_json", obj, __FILE__, __LINE__, 0, TraceRubyOut);
|
122
122
|
}
|
123
123
|
|
@@ -893,7 +893,7 @@ void
|
|
893
893
|
oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
894
894
|
int type = rb_type(obj);
|
895
895
|
|
896
|
-
if (Yes == out->opts->trace) {
|
896
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
897
897
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
898
898
|
}
|
899
899
|
if (out->opts->dump_opts.max_depth <= depth) {
|
@@ -918,14 +918,14 @@ oj_dump_compat_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
918
918
|
|
919
919
|
if (NULL != f) {
|
920
920
|
f(obj, depth, out, as_ok);
|
921
|
-
if (Yes == out->opts->trace) {
|
921
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
922
922
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
923
923
|
}
|
924
924
|
return;
|
925
925
|
}
|
926
926
|
}
|
927
927
|
oj_dump_nil(Qnil, depth, out, false);
|
928
|
-
if (Yes == out->opts->trace) {
|
928
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
929
929
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
930
930
|
}
|
931
931
|
}
|
data/ext/oj/dump_object.c
CHANGED
@@ -682,7 +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
|
-
if (Yes == out->opts->trace) {
|
685
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
686
686
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
687
687
|
}
|
688
688
|
if (MAX_DEPTH < depth) {
|
@@ -693,14 +693,14 @@ void oj_dump_obj_val(VALUE obj, int depth, Out out) {
|
|
693
693
|
|
694
694
|
if (NULL != f) {
|
695
695
|
f(obj, depth, out, false);
|
696
|
-
if (Yes == out->opts->trace) {
|
696
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
697
697
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
698
698
|
}
|
699
699
|
return;
|
700
700
|
}
|
701
701
|
}
|
702
702
|
oj_dump_nil(Qnil, depth, out, false);
|
703
|
-
if (Yes == out->opts->trace) {
|
703
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
704
704
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
705
705
|
}
|
706
706
|
}
|
data/ext/oj/dump_strict.c
CHANGED
@@ -338,7 +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
|
-
if (Yes == out->opts->trace) {
|
341
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
342
342
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
343
343
|
}
|
344
344
|
if (MAX_DEPTH < depth) {
|
@@ -349,7 +349,7 @@ void oj_dump_strict_val(VALUE obj, int depth, Out out) {
|
|
349
349
|
|
350
350
|
if (NULL != f) {
|
351
351
|
f(obj, depth, out, false);
|
352
|
-
if (Yes == out->opts->trace) {
|
352
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
353
353
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
354
354
|
}
|
355
355
|
return;
|
@@ -386,7 +386,7 @@ static DumpFunc null_funcs[] = {
|
|
386
386
|
void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
387
387
|
int type = rb_type(obj);
|
388
388
|
|
389
|
-
if (Yes == out->opts->trace) {
|
389
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
390
390
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
391
391
|
}
|
392
392
|
if (MAX_DEPTH < depth) {
|
@@ -397,14 +397,14 @@ void oj_dump_null_val(VALUE obj, int depth, Out out) {
|
|
397
397
|
|
398
398
|
if (NULL != f) {
|
399
399
|
f(obj, depth, out, false);
|
400
|
-
if (Yes == out->opts->trace) {
|
400
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
401
401
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
402
402
|
}
|
403
403
|
return;
|
404
404
|
}
|
405
405
|
}
|
406
406
|
oj_dump_nil(Qnil, depth, out, false);
|
407
|
-
if (Yes == out->opts->trace) {
|
407
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
408
408
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
409
409
|
}
|
410
410
|
}
|
data/ext/oj/extconf.rb
CHANGED
@@ -34,9 +34,21 @@ have_func('rb_hash_bulk_insert', 'ruby.h') unless '2' == version[0] && '6' == ve
|
|
34
34
|
|
35
35
|
dflags['OJ_DEBUG'] = true unless ENV['OJ_DEBUG'].nil?
|
36
36
|
|
37
|
-
|
37
|
+
src =<<~SRC
|
38
|
+
#include <string.h>
|
39
|
+
#include <nmmintrin.h>
|
40
|
+
int main(int argc, char **argv) {
|
41
|
+
const char *str = "hello ";
|
42
|
+
const char chars[16] = "\x00\\\"";
|
43
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
44
|
+
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
45
|
+
int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
46
|
+
return r == 16 ? 0 : 1;
|
47
|
+
}
|
48
|
+
SRC
|
49
|
+
|
50
|
+
if try_run(src, '-msse4.2')
|
38
51
|
$CPPFLAGS += ' -msse4.2'
|
39
|
-
dflags['OJ_USE_SSE4_2'] = 1
|
40
52
|
end
|
41
53
|
|
42
54
|
dflags.each do |k,v|
|
data/ext/oj/oj.c
CHANGED
data/ext/oj/parse.c
CHANGED
@@ -183,6 +183,78 @@ static void unicode_to_chars(ParseInfo pi, Buf buf, uint32_t code) {
|
|
183
183
|
}
|
184
184
|
}
|
185
185
|
|
186
|
+
static inline const char *scan_string_noSIMD(const char *str, const char *end) {
|
187
|
+
for (; '"' != *str; str++) {
|
188
|
+
if (end <= str || '\0' == *str || '\\' == *str) {
|
189
|
+
break;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
return str;
|
193
|
+
}
|
194
|
+
|
195
|
+
// Taken from Tensorflow:
|
196
|
+
// https://github.com/tensorflow/tensorflow/blob/5dcfc51118817f27fad5246812d83e5dccdc5f72/tensorflow/core/lib/hash/crc32c_accelerate.cc#L21-L38
|
197
|
+
#ifdef __SSE4_2__
|
198
|
+
#if defined(__x86_64__) && defined(__GNUC__) && \
|
199
|
+
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8))
|
200
|
+
#define USE_SSE_DETECT 1
|
201
|
+
#elif defined(__x86_64__) && defined(__clang__)
|
202
|
+
#if __has_builtin(__builtin_cpu_supports)
|
203
|
+
#define USE_SSE_DETECT 1
|
204
|
+
#endif
|
205
|
+
#endif
|
206
|
+
#endif /* __SSE4_2__ */
|
207
|
+
|
208
|
+
// This version of Apple clang has a bug:
|
209
|
+
// https://llvm.org/bugs/show_bug.cgi?id=25510
|
210
|
+
#if defined(__APPLE__) && (__clang_major__ <= 8)
|
211
|
+
#undef USE_SSE_DETECT
|
212
|
+
#endif
|
213
|
+
|
214
|
+
#if defined(TRUFFLERUBY)
|
215
|
+
#undef USE_SSE_DETECT
|
216
|
+
#endif
|
217
|
+
|
218
|
+
#ifdef USE_SSE_DETECT
|
219
|
+
#include <nmmintrin.h>
|
220
|
+
|
221
|
+
static inline const char *scan_string_SIMD(const char *str, const char *end) {
|
222
|
+
static const char chars[16] = "\x00\\\"";
|
223
|
+
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
224
|
+
const char *_end = (const char *)(end - 16);
|
225
|
+
|
226
|
+
for (; str <= _end; str += 16) {
|
227
|
+
const __m128i string = _mm_loadu_si128((const __m128i *)str);
|
228
|
+
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
229
|
+
if (r != 16) {
|
230
|
+
str = (char*)(str + r);
|
231
|
+
return str;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
return scan_string_noSIMD(str, end);
|
236
|
+
}
|
237
|
+
#endif
|
238
|
+
|
239
|
+
static bool cpu_supports_sse42(void) {
|
240
|
+
#if USE_SSE_DETECT
|
241
|
+
__builtin_cpu_init();
|
242
|
+
return (__builtin_cpu_supports("sse4.2"));
|
243
|
+
#else
|
244
|
+
return false;
|
245
|
+
#endif
|
246
|
+
}
|
247
|
+
|
248
|
+
static const char *(*scan_func) (const char *str, const char *end) = scan_string_noSIMD;
|
249
|
+
|
250
|
+
void oj_scanner_init(void) {
|
251
|
+
if (cpu_supports_sse42()) {
|
252
|
+
#if USE_SSE_DETECT
|
253
|
+
scan_func = scan_string_SIMD;
|
254
|
+
#endif
|
255
|
+
}
|
256
|
+
}
|
257
|
+
|
186
258
|
// entered at /
|
187
259
|
static void read_escaped_str(ParseInfo pi, const char *start) {
|
188
260
|
struct _buf buf;
|
@@ -192,11 +264,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
192
264
|
Val parent = stack_peek(&pi->stack);
|
193
265
|
|
194
266
|
buf_init(&buf);
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
if (
|
267
|
+
buf_append_string(&buf, start, cnt);
|
268
|
+
|
269
|
+
for (s = pi->cur; '"' != *s;) {
|
270
|
+
const char *scanned = scan_func(s, pi->end);
|
271
|
+
if (scanned >= pi->end) {
|
200
272
|
oj_set_error_at(pi,
|
201
273
|
oj_parse_error_class,
|
202
274
|
__FILE__,
|
@@ -204,7 +276,12 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
204
276
|
"quoted string not terminated");
|
205
277
|
buf_cleanup(&buf);
|
206
278
|
return;
|
207
|
-
}
|
279
|
+
}
|
280
|
+
|
281
|
+
buf_append_string(&buf, s, (size_t)(scanned - s));
|
282
|
+
s = scanned;
|
283
|
+
|
284
|
+
if ('\\' == *s) {
|
208
285
|
s++;
|
209
286
|
switch (*s) {
|
210
287
|
case 'n': buf_append(&buf, '\n'); break;
|
@@ -273,8 +350,7 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
273
350
|
buf_cleanup(&buf);
|
274
351
|
return;
|
275
352
|
}
|
276
|
-
|
277
|
-
buf_append(&buf, *s);
|
353
|
+
s++;
|
278
354
|
}
|
279
355
|
}
|
280
356
|
if (0 == parent) {
|
@@ -327,44 +403,11 @@ static void read_escaped_str(ParseInfo pi, const char *start) {
|
|
327
403
|
buf_cleanup(&buf);
|
328
404
|
}
|
329
405
|
|
330
|
-
static inline void scan_string_noSIMD(ParseInfo pi) {
|
331
|
-
for (; '"' != *pi->cur; pi->cur++) {
|
332
|
-
if (pi->end <= pi->cur || '\0' == *pi->cur || '\\' == *pi->cur) {
|
333
|
-
return;
|
334
|
-
}
|
335
|
-
}
|
336
|
-
}
|
337
|
-
|
338
|
-
#if defined(OJ_USE_SSE4_2)
|
339
|
-
#include <nmmintrin.h>
|
340
|
-
|
341
|
-
static inline void scan_string_SIMD(ParseInfo pi) {
|
342
|
-
static const char chars[16] = "\x00\\\"";
|
343
|
-
const __m128i terminate = _mm_loadu_si128((const __m128i *)&chars[0]);
|
344
|
-
const char *end = (const char *)(pi->end - 16);
|
345
|
-
|
346
|
-
for (; pi->cur <= end; pi->cur += 16) {
|
347
|
-
const __m128i string = _mm_loadu_si128((const __m128i *)pi->cur);
|
348
|
-
const int r = _mm_cmpestri(terminate, 3, string, 16, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT);
|
349
|
-
if (r != 16) {
|
350
|
-
pi->cur = (const char*)(pi->cur + r);
|
351
|
-
return;
|
352
|
-
}
|
353
|
-
}
|
354
|
-
|
355
|
-
scan_string_noSIMD(pi);
|
356
|
-
}
|
357
|
-
#endif
|
358
|
-
|
359
406
|
static void read_str(ParseInfo pi) {
|
360
407
|
const char *str = pi->cur;
|
361
408
|
Val parent = stack_peek(&pi->stack);
|
362
409
|
|
363
|
-
|
364
|
-
scan_string_SIMD(pi);
|
365
|
-
#else
|
366
|
-
scan_string_noSIMD(pi);
|
367
|
-
#endif
|
410
|
+
pi->cur = scan_func(pi->cur, pi->end);
|
368
411
|
if (RB_UNLIKELY(pi->end <= pi->cur)) {
|
369
412
|
oj_set_error_at(pi,
|
370
413
|
oj_parse_error_class,
|
@@ -494,33 +537,31 @@ static void read_num(ParseInfo pi) {
|
|
494
537
|
int dec_cnt = 0;
|
495
538
|
bool zero1 = false;
|
496
539
|
|
540
|
+
// Skip leading zeros.
|
541
|
+
for (; '0' == *pi->cur; pi->cur++) {
|
542
|
+
zero1 = true;
|
543
|
+
}
|
544
|
+
|
497
545
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
498
|
-
|
499
|
-
zero1 = true;
|
500
|
-
}
|
501
|
-
if (0 < ni.i) {
|
502
|
-
dec_cnt++;
|
503
|
-
}
|
504
|
-
if (!ni.big) {
|
505
|
-
int d = (*pi->cur - '0');
|
546
|
+
int d = (*pi->cur - '0');
|
506
547
|
|
507
|
-
|
508
|
-
|
509
|
-
oj_set_error_at(pi,
|
510
|
-
oj_parse_error_class,
|
511
|
-
__FILE__,
|
512
|
-
__LINE__,
|
513
|
-
"not a number");
|
514
|
-
return;
|
515
|
-
}
|
516
|
-
zero1 = false;
|
517
|
-
}
|
518
|
-
ni.i = ni.i * 10 + d;
|
519
|
-
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
520
|
-
ni.big = 1;
|
521
|
-
}
|
548
|
+
if (RB_LIKELY(0 != ni.i)) {
|
549
|
+
dec_cnt++;
|
522
550
|
}
|
551
|
+
ni.i = ni.i * 10 + d;
|
523
552
|
}
|
553
|
+
if (RB_UNLIKELY(0 != ni.i && zero1 && CompatMode == pi->options.mode)) {
|
554
|
+
oj_set_error_at(pi,
|
555
|
+
oj_parse_error_class,
|
556
|
+
__FILE__,
|
557
|
+
__LINE__,
|
558
|
+
"not a number");
|
559
|
+
return;
|
560
|
+
}
|
561
|
+
if (INT64_MAX <= ni.i || DEC_MAX < dec_cnt) {
|
562
|
+
ni.big = true;
|
563
|
+
}
|
564
|
+
|
524
565
|
if ('.' == *pi->cur) {
|
525
566
|
pi->cur++;
|
526
567
|
// A trailing . is not a valid decimal but if encountered allow it
|
@@ -540,25 +581,20 @@ static void read_num(ParseInfo pi) {
|
|
540
581
|
for (; '0' <= *pi->cur && *pi->cur <= '9'; pi->cur++) {
|
541
582
|
int d = (*pi->cur - '0');
|
542
583
|
|
543
|
-
if (0
|
584
|
+
if (RB_LIKELY(0 != ni.num || 0 != ni.i)) {
|
544
585
|
dec_cnt++;
|
545
586
|
}
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
}
|
550
|
-
} else {
|
551
|
-
ni.num = ni.num * 10 + d;
|
552
|
-
ni.div *= 10;
|
553
|
-
ni.di++;
|
554
|
-
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
555
|
-
if (!ni.no_big) {
|
556
|
-
ni.big = true;
|
557
|
-
}
|
558
|
-
}
|
559
|
-
}
|
587
|
+
ni.num = ni.num * 10 + d;
|
588
|
+
ni.div *= 10;
|
589
|
+
ni.di++;
|
560
590
|
}
|
561
591
|
}
|
592
|
+
if (INT64_MAX <= ni.div || DEC_MAX < dec_cnt) {
|
593
|
+
if (!ni.no_big) {
|
594
|
+
ni.big = true;
|
595
|
+
}
|
596
|
+
}
|
597
|
+
|
562
598
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
563
599
|
int eneg = 0;
|
564
600
|
|
data/ext/oj/parse.h
CHANGED
data/ext/oj/parser.c
CHANGED
@@ -600,7 +600,7 @@ static void parse(ojParser p, const byte *json) {
|
|
600
600
|
int i;
|
601
601
|
|
602
602
|
p->line = 1;
|
603
|
-
p->col
|
603
|
+
p->col = -1;
|
604
604
|
#if DEBUG
|
605
605
|
printf("*** parse - mode: %c %s\n", p->map[256], (const char *)json);
|
606
606
|
#endif
|
@@ -655,7 +655,7 @@ static void parse(ojParser p, const byte *json) {
|
|
655
655
|
}
|
656
656
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
657
657
|
if ('"' == *b) {
|
658
|
-
|
658
|
+
p->cur = b - json;
|
659
659
|
p->funcs[p->stack[p->depth]].add_str(p);
|
660
660
|
p->map = (0 == p->depth) ? value_map : after_map;
|
661
661
|
break;
|
@@ -665,14 +665,14 @@ static void parse(ojParser p, const byte *json) {
|
|
665
665
|
p->next_map = (0 == p->depth) ? value_map : after_map;
|
666
666
|
break;
|
667
667
|
case OPEN_OBJECT:
|
668
|
-
|
668
|
+
p->cur = b - json;
|
669
669
|
p->funcs[p->stack[p->depth]].open_object(p);
|
670
670
|
p->depth++;
|
671
671
|
p->stack[p->depth] = OBJECT_FUN;
|
672
672
|
p->map = key1_map;
|
673
673
|
break;
|
674
674
|
case NUM_CLOSE_OBJECT:
|
675
|
-
|
675
|
+
p->cur = b - json;
|
676
676
|
calc_num(p);
|
677
677
|
// flow through
|
678
678
|
case CLOSE_OBJECT:
|
@@ -683,18 +683,18 @@ static void parse(ojParser p, const byte *json) {
|
|
683
683
|
return;
|
684
684
|
}
|
685
685
|
p->depth--;
|
686
|
-
|
686
|
+
p->cur = b - json;
|
687
687
|
p->funcs[p->stack[p->depth]].close_object(p);
|
688
688
|
break;
|
689
689
|
case OPEN_ARRAY:
|
690
|
-
|
690
|
+
p->cur = b - json;
|
691
691
|
p->funcs[p->stack[p->depth]].open_array(p);
|
692
692
|
p->depth++;
|
693
693
|
p->stack[p->depth] = ARRAY_FUN;
|
694
694
|
p->map = value_map;
|
695
695
|
break;
|
696
696
|
case NUM_CLOSE_ARRAY:
|
697
|
-
|
697
|
+
p->cur = b - json;
|
698
698
|
calc_num(p);
|
699
699
|
// flow through
|
700
700
|
case CLOSE_ARRAY:
|
@@ -705,11 +705,11 @@ static void parse(ojParser p, const byte *json) {
|
|
705
705
|
return;
|
706
706
|
}
|
707
707
|
p->depth--;
|
708
|
-
|
708
|
+
p->cur = b - json;
|
709
709
|
p->funcs[p->stack[p->depth]].close_array(p);
|
710
710
|
break;
|
711
711
|
case NUM_COMMA:
|
712
|
-
|
712
|
+
p->cur = b - json;
|
713
713
|
calc_num(p);
|
714
714
|
if (0 < p->depth && OBJECT_FUN == p->stack[p->depth]) {
|
715
715
|
p->map = key_map;
|
@@ -872,13 +872,13 @@ static void parse(ojParser p, const byte *json) {
|
|
872
872
|
p->map = big_exp_map;
|
873
873
|
break;
|
874
874
|
case NUM_SPC:
|
875
|
-
|
876
|
-
|
877
|
-
|
875
|
+
p->cur = b - json;
|
876
|
+
calc_num(p);
|
877
|
+
break;
|
878
878
|
case NUM_NEWLINE:
|
879
|
-
|
880
|
-
|
881
|
-
|
879
|
+
p->cur = b - json;
|
880
|
+
calc_num(p);
|
881
|
+
b++;
|
882
882
|
#ifdef SPACE_JUMP
|
883
883
|
// for (uint32_t *sj = (uint32_t*)b; 0x20202020 == *sj; sj++) { b += 4; }
|
884
884
|
for (uint16_t *sj = (uint16_t *)b; 0x2020 == *sj; sj++) {
|
@@ -899,7 +899,7 @@ static void parse(ojParser p, const byte *json) {
|
|
899
899
|
buf_append_string(&p->buf, (const char *)start, b - start);
|
900
900
|
}
|
901
901
|
if ('"' == *b) {
|
902
|
-
|
902
|
+
p->cur = b - json;
|
903
903
|
p->funcs[p->stack[p->depth]].add_str(p);
|
904
904
|
p->map = p->next_map;
|
905
905
|
break;
|
@@ -908,7 +908,7 @@ static void parse(ojParser p, const byte *json) {
|
|
908
908
|
break;
|
909
909
|
case STR_SLASH: p->map = esc_map; break;
|
910
910
|
case STR_QUOTE:
|
911
|
-
|
911
|
+
p->cur = b - json;
|
912
912
|
p->funcs[p->stack[p->depth]].add_str(p);
|
913
913
|
p->map = p->next_map;
|
914
914
|
break;
|
@@ -986,7 +986,7 @@ static void parse(ojParser p, const byte *json) {
|
|
986
986
|
case VAL_NULL:
|
987
987
|
if ('u' == b[1] && 'l' == b[2] && 'l' == b[3]) {
|
988
988
|
b += 3;
|
989
|
-
|
989
|
+
p->cur = b - json;
|
990
990
|
p->funcs[p->stack[p->depth]].add_null(p);
|
991
991
|
p->map = (0 == p->depth) ? value_map : after_map;
|
992
992
|
break;
|
@@ -1012,7 +1012,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1012
1012
|
case VAL_TRUE:
|
1013
1013
|
if ('r' == b[1] && 'u' == b[2] && 'e' == b[3]) {
|
1014
1014
|
b += 3;
|
1015
|
-
|
1015
|
+
p->cur = b - json;
|
1016
1016
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1017
1017
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1018
1018
|
break;
|
@@ -1038,7 +1038,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1038
1038
|
case VAL_FALSE:
|
1039
1039
|
if ('a' == b[1] && 'l' == b[2] && 's' == b[3] && 'e' == b[4]) {
|
1040
1040
|
b += 4;
|
1041
|
-
|
1041
|
+
p->cur = b - json;
|
1042
1042
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1043
1043
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1044
1044
|
break;
|
@@ -1072,7 +1072,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1072
1072
|
parse_error(p, "expected null");
|
1073
1073
|
return;
|
1074
1074
|
}
|
1075
|
-
|
1075
|
+
p->cur = b - json;
|
1076
1076
|
p->funcs[p->stack[p->depth]].add_null(p);
|
1077
1077
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1078
1078
|
}
|
@@ -1084,7 +1084,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1084
1084
|
parse_error(p, "expected false");
|
1085
1085
|
return;
|
1086
1086
|
}
|
1087
|
-
|
1087
|
+
p->cur = b - json;
|
1088
1088
|
p->funcs[p->stack[p->depth]].add_false(p);
|
1089
1089
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1090
1090
|
}
|
@@ -1096,7 +1096,7 @@ static void parse(ojParser p, const byte *json) {
|
|
1096
1096
|
parse_error(p, "expected true");
|
1097
1097
|
return;
|
1098
1098
|
}
|
1099
|
-
|
1099
|
+
p->cur = b - json;
|
1100
1100
|
p->funcs[p->stack[p->depth]].add_true(p);
|
1101
1101
|
p->map = (0 == p->depth) ? value_map : after_map;
|
1102
1102
|
}
|
@@ -1114,6 +1114,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1114
1114
|
p->map = trail_map;
|
1115
1115
|
}
|
1116
1116
|
}
|
1117
|
+
if (0 < p->depth) {
|
1118
|
+
parse_error(p, "parse error, not closed");
|
1119
|
+
}
|
1117
1120
|
if (0 == p->depth) {
|
1118
1121
|
switch (p->map[256]) {
|
1119
1122
|
case '0':
|
@@ -1125,9 +1128,9 @@ static void parse(ojParser p, const byte *json) {
|
|
1125
1128
|
case 'g':
|
1126
1129
|
case 'B':
|
1127
1130
|
case 'Y':
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
+
p->cur = b - json;
|
1132
|
+
calc_num(p);
|
1133
|
+
break;
|
1131
1134
|
}
|
1132
1135
|
}
|
1133
1136
|
return;
|
data/ext/oj/rails.c
CHANGED
@@ -517,7 +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
|
-
if (Yes == out->opts->trace) {
|
520
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
521
521
|
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyIn);
|
522
522
|
}
|
523
523
|
// Some classes elect to not take an options argument so check the arity
|
@@ -527,7 +527,7 @@ static void dump_as_json(VALUE obj, int depth, Out out, bool as_ok) {
|
|
527
527
|
} else {
|
528
528
|
ja = rb_funcall2(obj, oj_as_json_id, out->argc, out->argv);
|
529
529
|
}
|
530
|
-
if (Yes == out->opts->trace) {
|
530
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
531
531
|
oj_trace("as_json", obj, __FILE__, __LINE__, depth + 1, TraceRubyOut);
|
532
532
|
}
|
533
533
|
|
@@ -1464,7 +1464,7 @@ static DumpFunc rails_funcs[] = {
|
|
1464
1464
|
static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
1465
1465
|
int type = rb_type(obj);
|
1466
1466
|
|
1467
|
-
if (Yes == out->opts->trace) {
|
1467
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
1468
1468
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
1469
1469
|
}
|
1470
1470
|
if (MAX_DEPTH < depth) {
|
@@ -1475,14 +1475,14 @@ static void dump_rails_val(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1475
1475
|
|
1476
1476
|
if (NULL != f) {
|
1477
1477
|
f(obj, depth, out, as_ok);
|
1478
|
-
if (Yes == out->opts->trace) {
|
1478
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
1479
1479
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
1480
1480
|
}
|
1481
1481
|
return;
|
1482
1482
|
}
|
1483
1483
|
}
|
1484
1484
|
oj_dump_nil(Qnil, depth, out, false);
|
1485
|
-
if (Yes == out->opts->trace) {
|
1485
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
1486
1486
|
oj_trace("dump", Qnil, __FILE__, __LINE__, depth, TraceOut);
|
1487
1487
|
}
|
1488
1488
|
}
|
data/ext/oj/saj2.c
CHANGED
@@ -289,7 +289,7 @@ static void add_float_key_loc(ojParser p) {
|
|
289
289
|
}
|
290
290
|
|
291
291
|
static void add_big(ojParser p) {
|
292
|
-
rb_funcall((
|
292
|
+
rb_funcall(((Delegate)p->ctx)->handler,
|
293
293
|
oj_add_value_id,
|
294
294
|
2,
|
295
295
|
rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
|
@@ -297,7 +297,7 @@ static void add_big(ojParser p) {
|
|
297
297
|
}
|
298
298
|
|
299
299
|
static void add_big_loc(ojParser p) {
|
300
|
-
rb_funcall((
|
300
|
+
rb_funcall(((Delegate)p->ctx)->handler,
|
301
301
|
oj_add_value_id,
|
302
302
|
4,
|
303
303
|
rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
|
@@ -307,7 +307,7 @@ static void add_big_loc(ojParser p) {
|
|
307
307
|
}
|
308
308
|
|
309
309
|
static void add_big_key(ojParser p) {
|
310
|
-
rb_funcall((
|
310
|
+
rb_funcall(((Delegate)p->ctx)->handler,
|
311
311
|
oj_add_value_id,
|
312
312
|
2,
|
313
313
|
rb_funcall(rb_cObject, oj_bigdecimal_id, 1, rb_str_new(buf_str(&p->buf), buf_len(&p->buf))),
|
data/ext/oj/validate.c
CHANGED
@@ -2,50 +2,45 @@
|
|
2
2
|
|
3
3
|
#include "parser.h"
|
4
4
|
|
5
|
-
static void
|
6
|
-
noop(ojParser p) {
|
5
|
+
static void noop(ojParser p) {
|
7
6
|
}
|
8
7
|
|
9
|
-
static VALUE
|
10
|
-
option(ojParser p, const char *key, VALUE value) {
|
8
|
+
static VALUE option(ojParser p, const char *key, VALUE value) {
|
11
9
|
rb_raise(rb_eArgError, "%s is not an option for the validate delegate", key);
|
12
10
|
return Qnil;
|
13
11
|
}
|
14
12
|
|
15
|
-
static VALUE
|
16
|
-
result(ojParser p) {
|
13
|
+
static VALUE result(ojParser p) {
|
17
14
|
return Qnil;
|
18
15
|
}
|
19
16
|
|
20
|
-
static void
|
21
|
-
dfree(ojParser p) {
|
17
|
+
static void dfree(ojParser p) {
|
22
18
|
}
|
23
19
|
|
24
|
-
static void
|
25
|
-
mark(ojParser p) {
|
20
|
+
static void mark(ojParser p) {
|
26
21
|
}
|
27
22
|
|
28
23
|
void oj_set_parser_validator(ojParser p) {
|
29
|
-
p->
|
30
|
-
Funcs end = p->funcs + 3;
|
24
|
+
Funcs end = p->funcs + 3;
|
31
25
|
Funcs f;
|
26
|
+
p->ctx = NULL;
|
32
27
|
|
33
28
|
for (f = p->funcs; f < end; f++) {
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
29
|
+
f->add_null = noop;
|
30
|
+
f->add_true = noop;
|
31
|
+
f->add_false = noop;
|
32
|
+
f->add_int = noop;
|
33
|
+
f->add_float = noop;
|
34
|
+
f->add_big = noop;
|
35
|
+
f->add_str = noop;
|
36
|
+
f->open_array = noop;
|
37
|
+
f->close_array = noop;
|
38
|
+
f->open_object = noop;
|
39
|
+
f->close_object = noop;
|
45
40
|
}
|
46
41
|
p->option = option;
|
47
42
|
p->result = result;
|
48
|
-
p->free
|
49
|
-
p->mark
|
50
|
-
p->start
|
43
|
+
p->free = dfree;
|
44
|
+
p->mark = mark;
|
45
|
+
p->start = noop;
|
51
46
|
}
|
data/ext/oj/wab.c
CHANGED
@@ -266,7 +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
|
-
if (Yes == out->opts->trace) {
|
269
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
270
270
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceIn);
|
271
271
|
}
|
272
272
|
if (MAX_DEPTH < depth) {
|
@@ -277,7 +277,7 @@ void oj_dump_wab_val(VALUE obj, int depth, Out out) {
|
|
277
277
|
|
278
278
|
if (NULL != f) {
|
279
279
|
f(obj, depth, out, false);
|
280
|
-
if (Yes == out->opts->trace) {
|
280
|
+
if (RB_UNLIKELY(Yes == out->opts->trace)) {
|
281
281
|
oj_trace("dump", obj, __FILE__, __LINE__, depth, TraceOut);
|
282
282
|
}
|
283
283
|
return;
|
data/lib/oj/version.rb
CHANGED
data/test/bar.rb
CHANGED
@@ -6,11 +6,6 @@ $: << File.join(File.dirname(__FILE__), "../ext")
|
|
6
6
|
|
7
7
|
require 'oj'
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
"inf_test" => Float::INFINITY,
|
13
|
-
"minus_inf_test" => -Float::INFINITY,
|
14
|
-
"min_test" => Float::MIN,
|
15
|
-
"max_test" => Float::MAX,
|
16
|
-
}, mode: :object) # => {"float_test":0.25,"nan_test":3.3e14159265358979323846
|
9
|
+
p = Oj::Parser.validate
|
10
|
+
# p = Oj::Parser.new(:debug)
|
11
|
+
p.parse(%|{|)
|
data/test/helper.rb
CHANGED
@@ -19,10 +19,16 @@ require 'pp'
|
|
19
19
|
require 'oj'
|
20
20
|
|
21
21
|
|
22
|
-
|
22
|
+
def verify_gc_compaction
|
23
23
|
# This method was added in Ruby 3.0.0. Calling it this way asks the GC to
|
24
24
|
# move objects around, helping to find object movement bugs.
|
25
|
-
GC.verify_compaction_references(
|
25
|
+
if defined?(GC.verify_compaction_references) == 'method' && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
|
26
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
|
27
|
+
GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
28
|
+
else
|
29
|
+
GC.verify_compaction_references(double_heap: true, toward: :empty)
|
30
|
+
end
|
31
|
+
end
|
26
32
|
end
|
27
33
|
|
28
34
|
|
@@ -15,10 +15,14 @@ else
|
|
15
15
|
require 'oj'
|
16
16
|
Oj.mimic_JSON
|
17
17
|
|
18
|
+
# This method was added in Ruby 3.0.0. Calling it this way asks the GC to
|
19
|
+
# move objects around, helping to find object movement bugs.
|
18
20
|
if defined?(GC.verify_compaction_references) == 'method'
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.2.0")
|
22
|
+
GC.verify_compaction_references(expand_heap: true, toward: :empty)
|
23
|
+
else
|
24
|
+
GC.verify_compaction_references(double_heap: true, toward: :empty)
|
25
|
+
end
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
data/test/test_compat.rb
CHANGED
@@ -504,6 +504,15 @@ class CompatJuice < Minitest::Test
|
|
504
504
|
assert_equal("ぴーたー", Oj.load(json)['a'])
|
505
505
|
end
|
506
506
|
|
507
|
+
def test_parse_large_escaped_string
|
508
|
+
invalid_json = %|{"a":\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc }|
|
509
|
+
error = assert_raises() { Oj.load(invalid_json) }
|
510
|
+
assert(error.message.include?('quoted string not terminated'))
|
511
|
+
|
512
|
+
json = "\"aaaa\\nbbbb\\rcccc\\tddd\\feee\\bf\/\\\\\\u3074\\u30fc\\u305f\\u30fc \""
|
513
|
+
assert_equal("aaaa\nbbbb\rcccc\tddd\feee\bf/\\ぴーたー ", Oj.load(json))
|
514
|
+
end
|
515
|
+
|
507
516
|
def dump_and_load(obj, trace=false)
|
508
517
|
json = Oj.dump(obj)
|
509
518
|
puts json if trace
|
data/test/test_object.rb
CHANGED
@@ -224,7 +224,7 @@ class ObjectJuice < Minitest::Test
|
|
224
224
|
#=begin
|
225
225
|
if '3.1.0' <= RUBY_VERSION && !(RbConfig::CONFIG['host_os'] =~ /(mingw|mswin)/)
|
226
226
|
#Oj::debug_odd("teardown before GC.verify_compaction_references")
|
227
|
-
|
227
|
+
verify_gc_compaction
|
228
228
|
#Oj::debug_odd("teardown after GC.verify_compaction_references")
|
229
229
|
end
|
230
230
|
#=end
|
data/test/test_parser_saj.rb
CHANGED
@@ -149,6 +149,17 @@ class SajTest < Minitest::Test
|
|
149
149
|
assert_equal((12345.6789e7 * 10000).to_i, (handler.calls[0][1] * 10000).to_i)
|
150
150
|
end
|
151
151
|
|
152
|
+
def test_bignum
|
153
|
+
handler = AllSaj.new()
|
154
|
+
json = %{-11.899999999999999}
|
155
|
+
p = Oj::Parser.new(:saj)
|
156
|
+
p.handler = handler
|
157
|
+
p.parse(json)
|
158
|
+
assert_equal(1, handler.calls.size)
|
159
|
+
assert_equal(:add_value, handler.calls[0][0])
|
160
|
+
assert_equal(-118999, (handler.calls[0][1] * 10000).to_i)
|
161
|
+
end
|
162
|
+
|
152
163
|
def test_array_empty
|
153
164
|
handler = AllSaj.new()
|
154
165
|
json = %{[]}
|
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.13.
|
4
|
+
version: 3.13.19
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-07-
|
11
|
+
date: 2022-07-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake-compiler
|