oj 3.13.16 → 3.13.19
Sign up to get free protection for your applications and to get access to all the features.
- 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
|