oj 3.10.7 → 3.10.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ext/oj/custom.c +1 -1
- data/ext/oj/mimic_json.c +4 -3
- data/ext/oj/object.c +1 -1
- data/ext/oj/oj.c +6 -1
- data/ext/oj/oj.h +3 -1
- data/ext/oj/parse.c +83 -43
- data/ext/oj/parse.h +2 -1
- data/ext/oj/sparse.c +8 -5
- data/lib/oj/version.rb +1 -1
- data/test/json_gem/json_common_interface_test.rb +6 -0
- data/test/sample_json.rb +1 -1
- data/test/test_custom.rb +6 -0
- metadata +23 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6fa2380f622d5ca9441eb9b2588179a077d851833c8c0985a99d5be562b033b3
|
4
|
+
data.tar.gz: 56f3d28b1a711efed58a4ef43a0518b44f127e1ad68a68fbe9afecbee9d6b395
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1603e46da846347272f245183555480e944368eb1c0394bd8ab4e6cc0a916353e66ba94b14c6a45c687a80a033bf792161c64acb24a32d81f6d749f35dd1bf31
|
7
|
+
data.tar.gz: f2d40d5bb00fb5cfd0bbbc0eb55d15be1d90dd2da8657b07ce4156ab8fe3d91731bb536231be4d12d0f2f5e9979fd95dec77a800cfc8e11e96ce4856067d3788
|
data/ext/oj/custom.c
CHANGED
@@ -1089,7 +1089,7 @@ hash_set_num(struct _parseInfo *pi, Val kval, NumInfo ni) {
|
|
1089
1089
|
// offset and then a conversion to UTC keeps makes the time
|
1090
1090
|
// match the expected value.
|
1091
1091
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
1092
|
-
} else if (ni->
|
1092
|
+
} else if (ni->has_exp) {
|
1093
1093
|
int64_t t = (int64_t)(ni->i + ni->exp);
|
1094
1094
|
struct _timeInfo ti;
|
1095
1095
|
VALUE args[8];
|
data/ext/oj/mimic_json.c
CHANGED
@@ -513,7 +513,8 @@ mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
|
|
513
513
|
pi.options.create_ok = No;
|
514
514
|
pi.options.allow_nan = (bang ? Yes : No);
|
515
515
|
pi.options.nilnil = No;
|
516
|
-
pi.options.bigdec_load = FloatDec;
|
516
|
+
//pi.options.bigdec_load = FloatDec;
|
517
|
+
pi.options.bigdec_load = RubyDec;
|
517
518
|
pi.options.mode = CompatMode;
|
518
519
|
pi.max_depth = 100;
|
519
520
|
|
@@ -686,7 +687,7 @@ static struct _options mimic_object_to_json_options = {
|
|
686
687
|
No, // class_cache
|
687
688
|
RubyTime, // time_format
|
688
689
|
No, // bigdec_as_num
|
689
|
-
|
690
|
+
RubyDec, // bigdec_load
|
690
691
|
No, // to_hash
|
691
692
|
No, // to_json
|
692
693
|
No, // as_json
|
@@ -707,7 +708,7 @@ static struct _options mimic_object_to_json_options = {
|
|
707
708
|
oj_json_class,// create_id
|
708
709
|
10, // create_id_len
|
709
710
|
3, // sec_prec
|
710
|
-
|
711
|
+
0, // float_prec
|
711
712
|
"%0.16g", // float_fmt
|
712
713
|
Qnil, // hash_class
|
713
714
|
Qnil, // array_class
|
data/ext/oj/object.c
CHANGED
@@ -295,7 +295,7 @@ hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
|
|
295
295
|
// offset and then a conversion to UTC keeps makes the time
|
296
296
|
// match the expected value.
|
297
297
|
parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
|
298
|
-
} else if (ni->
|
298
|
+
} else if (ni->has_exp) {
|
299
299
|
int64_t t = (int64_t)(ni->i + ni->exp);
|
300
300
|
struct _timeInfo ti;
|
301
301
|
VALUE args[8];
|
data/ext/oj/oj.c
CHANGED
@@ -115,6 +115,7 @@ static VALUE custom_sym;
|
|
115
115
|
static VALUE empty_string_sym;
|
116
116
|
static VALUE escape_mode_sym;
|
117
117
|
static VALUE integer_range_sym;
|
118
|
+
static VALUE fast_sym;
|
118
119
|
static VALUE float_prec_sym;
|
119
120
|
static VALUE float_sym;
|
120
121
|
static VALUE huge_sym;
|
@@ -230,7 +231,7 @@ struct _options oj_default_options = {
|
|
230
231
|
* - *:mode* [_:object_|_:strict_|_:compat_|_:null_|_:custom_|_:rails_|_:wab_] load and dump modes to use for JSON
|
231
232
|
* - *:time_format* [_:unix_|_:unix_zone_|_:xmlschema_|_:ruby_] time format when dumping
|
232
233
|
* - *:bigdecimal_as_decimal* [_Boolean_|_nil_] dump BigDecimal as a decimal number or as a String
|
233
|
-
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits.
|
234
|
+
* - *:bigdecimal_load* [_:bigdecimal_|_:float_|_:auto_|_:fast_] load decimals as BigDecimal instead of as a Float. :auto pick the most precise for the number of digits. :float should be the same as ruby. :fast may require rounding but is must faster.
|
234
235
|
* - *:create_id* [_String_|_nil_] create id for json compatible object encoding, default is 'json_class'
|
235
236
|
* - *:create_additions* [_Boolean_|_nil_] if true allow creation of instances using create_id on load.
|
236
237
|
* - *:second_precision* [_Fixnum_|_nil_] number of digits after the decimal when dumping the seconds portion of time
|
@@ -331,6 +332,7 @@ get_def_opts(VALUE self) {
|
|
331
332
|
switch (oj_default_options.bigdec_load) {
|
332
333
|
case BigDec: rb_hash_aset(opts, bigdecimal_load_sym, bigdecimal_sym);break;
|
333
334
|
case FloatDec: rb_hash_aset(opts, bigdecimal_load_sym, float_sym); break;
|
335
|
+
case FastDec: rb_hash_aset(opts, bigdecimal_load_sym, fast_sym); break;
|
334
336
|
case AutoDec:
|
335
337
|
default: rb_hash_aset(opts, bigdecimal_load_sym, auto_sym); break;
|
336
338
|
}
|
@@ -574,6 +576,8 @@ oj_parse_options(VALUE ropts, Options copts) {
|
|
574
576
|
copts->bigdec_load = BigDec;
|
575
577
|
} else if (float_sym == v) {
|
576
578
|
copts->bigdec_load = FloatDec;
|
579
|
+
} else if (fast_sym == v) {
|
580
|
+
copts->bigdec_load = FastDec;
|
577
581
|
} else if (auto_sym == v || Qfalse == v) {
|
578
582
|
copts->bigdec_load = AutoDec;
|
579
583
|
} else {
|
@@ -1654,6 +1658,7 @@ Init_oj() {
|
|
1654
1658
|
empty_string_sym = ID2SYM(rb_intern("empty_string")); rb_gc_register_address(&empty_string_sym);
|
1655
1659
|
escape_mode_sym = ID2SYM(rb_intern("escape_mode")); rb_gc_register_address(&escape_mode_sym);
|
1656
1660
|
integer_range_sym = ID2SYM(rb_intern("integer_range")); rb_gc_register_address(&integer_range_sym);
|
1661
|
+
fast_sym = ID2SYM(rb_intern("fast")); rb_gc_register_address(&fast_sym);
|
1657
1662
|
float_prec_sym = ID2SYM(rb_intern("float_precision")); rb_gc_register_address(&float_prec_sym);
|
1658
1663
|
float_sym = ID2SYM(rb_intern("float")); rb_gc_register_address(&float_sym);
|
1659
1664
|
huge_sym = ID2SYM(rb_intern("huge")); rb_gc_register_address(&huge_sym);
|
data/ext/oj/oj.h
CHANGED
data/ext/oj/parse.c
CHANGED
@@ -393,8 +393,9 @@ read_num(ParseInfo pi) {
|
|
393
393
|
ni.infinity = 0;
|
394
394
|
ni.nan = 0;
|
395
395
|
ni.neg = 0;
|
396
|
-
ni.
|
397
|
-
ni.no_big = (FloatDec == pi->options.bigdec_load);
|
396
|
+
ni.has_exp = 0;
|
397
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
|
398
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
398
399
|
|
399
400
|
if ('-' == *pi->cur) {
|
400
401
|
pi->cur++;
|
@@ -488,7 +489,7 @@ read_num(ParseInfo pi) {
|
|
488
489
|
if ('e' == *pi->cur || 'E' == *pi->cur) {
|
489
490
|
int eneg = 0;
|
490
491
|
|
491
|
-
ni.
|
492
|
+
ni.has_exp = 1;
|
492
493
|
pi->cur++;
|
493
494
|
if ('-' == *pi->cur) {
|
494
495
|
pi->cur++;
|
@@ -759,6 +760,59 @@ parse_big_decimal(VALUE str) {
|
|
759
760
|
return rb_funcall(rb_cObject, oj_bigdecimal_id, 1, str);
|
760
761
|
}
|
761
762
|
|
763
|
+
static long double exp_plus[] = {
|
764
|
+
1.0,
|
765
|
+
1.0e1,
|
766
|
+
1.0e2,
|
767
|
+
1.0e3,
|
768
|
+
1.0e4,
|
769
|
+
1.0e5,
|
770
|
+
1.0e6,
|
771
|
+
1.0e7,
|
772
|
+
1.0e8,
|
773
|
+
1.0e9,
|
774
|
+
1.0e10,
|
775
|
+
1.0e11,
|
776
|
+
1.0e12,
|
777
|
+
1.0e13,
|
778
|
+
1.0e14,
|
779
|
+
1.0e15,
|
780
|
+
1.0e16,
|
781
|
+
1.0e17,
|
782
|
+
1.0e18,
|
783
|
+
1.0e19,
|
784
|
+
1.0e20,
|
785
|
+
1.0e21,
|
786
|
+
1.0e22,
|
787
|
+
1.0e23,
|
788
|
+
1.0e24,
|
789
|
+
1.0e25,
|
790
|
+
1.0e26,
|
791
|
+
1.0e27,
|
792
|
+
1.0e28,
|
793
|
+
1.0e29,
|
794
|
+
1.0e30,
|
795
|
+
1.0e31,
|
796
|
+
1.0e32,
|
797
|
+
1.0e33,
|
798
|
+
1.0e34,
|
799
|
+
1.0e35,
|
800
|
+
1.0e36,
|
801
|
+
1.0e37,
|
802
|
+
1.0e38,
|
803
|
+
1.0e39,
|
804
|
+
1.0e40,
|
805
|
+
1.0e41,
|
806
|
+
1.0e42,
|
807
|
+
1.0e43,
|
808
|
+
1.0e44,
|
809
|
+
1.0e45,
|
810
|
+
1.0e46,
|
811
|
+
1.0e47,
|
812
|
+
1.0e48,
|
813
|
+
1.0e49,
|
814
|
+
};
|
815
|
+
|
762
816
|
VALUE
|
763
817
|
oj_num_as_value(NumInfo ni) {
|
764
818
|
volatile VALUE rnum = Qnil;
|
@@ -771,7 +825,7 @@ oj_num_as_value(NumInfo ni) {
|
|
771
825
|
}
|
772
826
|
} else if (ni->nan) {
|
773
827
|
rnum = rb_float_new(0.0/0.0);
|
774
|
-
} else if (1 == ni->div && 0 == ni->exp) { // fixnum
|
828
|
+
} else if (1 == ni->div && 0 == ni->exp && !ni->has_exp) { // fixnum
|
775
829
|
if (ni->big) {
|
776
830
|
if (256 > ni->len) {
|
777
831
|
char buf[256];
|
@@ -802,53 +856,39 @@ oj_num_as_value(NumInfo ni) {
|
|
802
856
|
if (ni->no_big) {
|
803
857
|
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
804
858
|
}
|
805
|
-
} else {
|
806
|
-
// All these machinations are to get rounding to work better.
|
859
|
+
} else if (FastDec == ni->bigdec_load) {
|
807
860
|
long double ld = (long double)ni->i * (long double)ni->div + (long double)ni->num;
|
808
861
|
int x = (int)((int64_t)ni->exp - ni->di);
|
809
862
|
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
if ((long double)INT64_MAX > ld && (int64_t)ld != (ni->i * ni->div + ni->num)) {
|
814
|
-
volatile VALUE bd = rb_str_new(ni->str, ni->len);
|
815
|
-
|
816
|
-
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
817
|
-
if (ni->no_big) {
|
818
|
-
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
819
|
-
}
|
820
|
-
} else {
|
821
|
-
double d;
|
822
|
-
double d2;
|
823
|
-
|
824
|
-
ld = roundl(ld);
|
825
|
-
// You would expect that staying with a long double would be
|
826
|
-
// more accurate but it fails to match what Ruby generates so
|
827
|
-
// drop down to a double.
|
828
|
-
if (0 < x) {
|
829
|
-
d = (double)(ld * powl(10.0, x));
|
830
|
-
d2 = (double)ld * pow(10.0, x);
|
831
|
-
} else if (0 > x) {
|
832
|
-
d = (double)(ld / powl(10.0, -x));
|
833
|
-
d2 = (double)ld / pow(10.0, -x);
|
863
|
+
if (0 < x) {
|
864
|
+
if (x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
865
|
+
ld *= exp_plus[x];
|
834
866
|
} else {
|
835
|
-
|
836
|
-
d2 = d;
|
867
|
+
ld *= powl(10.0, x);
|
837
868
|
}
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
rnum = rb_rescue2(parse_big_decimal, bd, rescue_big_decimal, bd, rb_eException, 0);
|
842
|
-
if (ni->no_big) {
|
843
|
-
rnum = rb_funcall(rnum, rb_intern("to_f"), 0);
|
844
|
-
}
|
869
|
+
} else if (x < 0) {
|
870
|
+
if (-x < (int)(sizeof(exp_plus) / sizeof(*exp_plus))) {
|
871
|
+
ld /= exp_plus[-x];
|
845
872
|
} else {
|
846
|
-
|
847
|
-
d = -d;
|
848
|
-
}
|
849
|
-
rnum = rb_float_new(d);
|
873
|
+
ld /= powl(10.0, -x);
|
850
874
|
}
|
851
875
|
}
|
876
|
+
if (ni->neg) {
|
877
|
+
ld = -ld;
|
878
|
+
}
|
879
|
+
rnum = rb_float_new((double)ld);
|
880
|
+
} else if (RubyDec == ni->bigdec_load) {
|
881
|
+
volatile VALUE sv = rb_str_new(ni->str, ni->len);
|
882
|
+
|
883
|
+
rnum = rb_funcall(sv, rb_intern("to_f"), 0);
|
884
|
+
} else {
|
885
|
+
char *end;
|
886
|
+
double d = strtod(ni->str, &end);
|
887
|
+
|
888
|
+
if ((long)ni->len != (long)(end - ni->str)) {
|
889
|
+
rb_raise(oj_parse_error_class, "Invalid float");
|
890
|
+
}
|
891
|
+
rnum = rb_float_new(d);
|
852
892
|
}
|
853
893
|
}
|
854
894
|
return rnum;
|
data/ext/oj/parse.h
CHANGED
data/ext/oj/sparse.c
CHANGED
@@ -407,8 +407,9 @@ read_num(ParseInfo pi) {
|
|
407
407
|
ni.infinity = 0;
|
408
408
|
ni.nan = 0;
|
409
409
|
ni.neg = 0;
|
410
|
-
ni.
|
411
|
-
ni.no_big = (FloatDec == pi->options.bigdec_load);
|
410
|
+
ni.has_exp = 0;
|
411
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
|
412
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
412
413
|
|
413
414
|
c = reader_get(&pi->rd);
|
414
415
|
if ('-' == c) {
|
@@ -489,7 +490,7 @@ read_num(ParseInfo pi) {
|
|
489
490
|
if ('e' == c || 'E' == c) {
|
490
491
|
int eneg = 0;
|
491
492
|
|
492
|
-
ni.
|
493
|
+
ni.has_exp = 1;
|
493
494
|
c = reader_get(&pi->rd);
|
494
495
|
if ('-' == c) {
|
495
496
|
c = reader_get(&pi->rd);
|
@@ -548,7 +549,8 @@ read_nan(ParseInfo pi) {
|
|
548
549
|
ni.infinity = 0;
|
549
550
|
ni.nan = 1;
|
550
551
|
ni.neg = 0;
|
551
|
-
ni.no_big = (FloatDec == pi->options.bigdec_load);
|
552
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load);
|
553
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
552
554
|
|
553
555
|
if ('a' != reader_get(&pi->rd) ||
|
554
556
|
('N' != (c = reader_get(&pi->rd)) && 'n' != c)) {
|
@@ -745,7 +747,8 @@ oj_sparse2(ParseInfo pi) {
|
|
745
747
|
ni.infinity = 0;
|
746
748
|
ni.nan = 1;
|
747
749
|
ni.neg = 0;
|
748
|
-
ni.no_big = (FloatDec == pi->options.bigdec_load);
|
750
|
+
ni.no_big = (FloatDec == pi->options.bigdec_load || RubyDec == pi->options.bigdec_load || FastDec == pi->options.bigdec_load);
|
751
|
+
ni.bigdec_load = pi->options.bigdec_load;
|
749
752
|
add_num_value(pi, &ni);
|
750
753
|
} else {
|
751
754
|
oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "invalid token");
|
data/lib/oj/version.rb
CHANGED
@@ -23,8 +23,14 @@ class JSONCommonInterfaceTest < Test::Unit::TestCase
|
|
23
23
|
'h' => 1000.0,
|
24
24
|
'i' => 0.001
|
25
25
|
}
|
26
|
+
# Tired of chasing floating point rounding and precision. Oj not uses the
|
27
|
+
# Ruby float parser in compat mode yet on i386 machines there are issues
|
28
|
+
# with this test when the float is included.
|
29
|
+
|
26
30
|
@json = '{"a":2,"b":5.23683071,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},'\
|
27
31
|
'"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
|
32
|
+
#@json = '{"a":2,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},'\
|
33
|
+
#p '"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
|
28
34
|
end
|
29
35
|
|
30
36
|
def test_index
|
data/test/sample_json.rb
CHANGED
data/test/test_custom.rb
CHANGED
@@ -123,6 +123,12 @@ class CustomJuice < Minitest::Test
|
|
123
123
|
assert_equal(Float, f.class)
|
124
124
|
end
|
125
125
|
|
126
|
+
def test_float_parse_fast
|
127
|
+
f = Oj.load("12.123456789012345678", mode: :custom, bigdecimal_load: :fast);
|
128
|
+
assert_equal(Float, f.class)
|
129
|
+
assert_equal('12.12345678901235', "%0.14f" % [f]) # only care about 16 digits
|
130
|
+
end
|
131
|
+
|
126
132
|
def test_nan_dump
|
127
133
|
assert_equal('null', Oj.dump(0/0.0, :nan => :null))
|
128
134
|
assert_equal('3.3e14159265358979323846', Oj.dump(0/0.0, :nan => :huge))
|
metadata
CHANGED
@@ -1,15 +1,35 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oj
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.10.
|
4
|
+
version: 3.10.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Ohler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bigdecimal
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
13
33
|
- !ruby/object:Gem::Dependency
|
14
34
|
name: rake-compiler
|
15
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -277,7 +297,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
277
297
|
requirements:
|
278
298
|
- - ">="
|
279
299
|
- !ruby/object:Gem::Version
|
280
|
-
version: '2.
|
300
|
+
version: '2.4'
|
281
301
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
282
302
|
requirements:
|
283
303
|
- - ">="
|