oj 3.10.7 → 3.10.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 21e870cbb9a2f1c2b99efd6522ce9c284828865b922e299232e60abd4e916f7e
4
- data.tar.gz: d1d93c3d58b7ed858e1a4ea89698861485bbeeb19b01bc66e3e8890ab7d93583
3
+ metadata.gz: cb725babd05d3dadf33c86b0737e278f0f2eed8bb1792300dca74f5138a472a5
4
+ data.tar.gz: c60cd42eccaeea5937726f90225a611b19901ff4d133968e304de6f6d9077a31
5
5
  SHA512:
6
- metadata.gz: 7c5d6b2d7a7830b80ecc23436e50b0f42f53e82febe31ceb0168f440e5368ed323c19433894724beea83e7587013170b6a38be92b65b073d9881f8176a8d283b
7
- data.tar.gz: 1558090a4a1b066418b9f36064c845ab99e423246f26af8aff682e8f09b8cfce29531f6e677c6e4d8b16056406251b2fe54b463e4ddef121adced8c9d3c167b2
6
+ metadata.gz: 56791447ce08bbe3aca701ff0b50e17f70dbd2bae22bcc07fcdbe5216b9da7e976f6ee748bee83d12a2915148ddc83e99ac52203e9baa7a3e268023a808515e0
7
+ data.tar.gz: 9906af11fb4fd41f2a4d311d0c7e0a4d72c3947e53201fa745717f356d67cbc757ebcbbb341eff03f7d4c1cb1bb76da59d05b14e31119f098e1b398d8f164304
@@ -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->hasExp) {
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];
@@ -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->hasExp) {
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];
@@ -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);
@@ -77,7 +77,8 @@ typedef enum {
77
77
  typedef enum {
78
78
  BigDec = 'b',
79
79
  FloatDec = 'f',
80
- AutoDec = 'a'
80
+ AutoDec = 'a',
81
+ FastDec = 'F'
81
82
  } BigLoad;
82
83
 
83
84
  typedef enum {
@@ -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.hasExp = 0;
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);
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.hasExp = 1;
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,35 @@ 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
- // Rounding sometimes cuts off the last digit even if there are only
811
- // 15 digits. This attempts to fix those few cases where this
812
- // occurs.
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
- d = (double)ld;
836
- d2 = d;
867
+ ld *= powl(10.0, x);
837
868
  }
838
- if (d != d2) {
839
- volatile VALUE bd = rb_str_new(ni->str, ni->len);
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
- if (ni->neg) {
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 {
881
+ char *end;
882
+ double d = strtod(ni->str, &end);
883
+
884
+ if ((long)ni->len != (long)(end - ni->str)) {
885
+ rb_raise(oj_parse_error_class, "Invalid float");
886
+ }
887
+ rnum = rb_float_new(d);
852
888
  }
853
889
  }
854
890
  return rnum;
@@ -31,8 +31,9 @@ typedef struct _numInfo {
31
31
  int infinity;
32
32
  int nan;
33
33
  int neg;
34
- int hasExp;
34
+ int has_exp;
35
35
  int no_big;
36
+ int bigdec_load;
36
37
  } *NumInfo;
37
38
 
38
39
  typedef struct _parseInfo {
@@ -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.hasExp = 0;
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);
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.hasExp = 1;
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);
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)) {
@@ -746,6 +748,7 @@ oj_sparse2(ParseInfo pi) {
746
748
  ni.nan = 1;
747
749
  ni.neg = 0;
748
750
  ni.no_big = (FloatDec == 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");
@@ -1,5 +1,5 @@
1
1
 
2
2
  module Oj
3
3
  # Current version of the module.
4
- VERSION = '3.10.7'
4
+ VERSION = '3.10.8'
5
5
  end
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby -wW2
1
+ #!/usr/bin/env ruby
2
2
 
3
3
  if $0 == __FILE__
4
4
  $: << '.'
@@ -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.123456789012346, f)
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,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oj
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.10.7
4
+ version: 3.10.8
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-07-13 00:00:00.000000000 Z
11
+ date: 2020-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake-compiler