ruby-changes:54732
From: naruse <ko1@a...>
Date: Wed, 30 Jan 2019 15:20:15 +0900 (JST)
Subject: [ruby-changes:54732] naruse:r66949 (ruby_2_6): merge revision(s) 66947: [Backport #15518]
naruse 2019-01-30 15:20:10 +0900 (Wed, 30 Jan 2019) New Revision: 66949 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66949 Log: merge revision(s) 66947: [Backport #15518] enumerator.c: fix arith_seq_first for Infinity * enumerator.c (arith_seq_first): fix for Float::INFINITY. * test/ruby/test_arithmetic_sequence.rb: add tests. * numeric.c (ruby_float_step_size): export for internal use. * internal.h: add prototype declaration of ruby_float_step_size. [ruby-core:90937][Bug #15518] Modified directories: branches/ruby_2_6/ Modified files: branches/ruby_2_6/enumerator.c branches/ruby_2_6/internal.h branches/ruby_2_6/numeric.c branches/ruby_2_6/test/ruby/test_arithmetic_sequence.rb branches/ruby_2_6/version.h Index: ruby_2_6/numeric.c =================================================================== --- ruby_2_6/numeric.c (revision 66948) +++ ruby_2_6/numeric.c (revision 66949) @@ -2481,7 +2481,7 @@ num_truncate(int argc, VALUE *argv, VALU https://github.com/ruby/ruby/blob/trunk/ruby_2_6/numeric.c#L2481 return flo_truncate(argc, argv, rb_Float(num)); } -static double +double ruby_float_step_size(double beg, double end, double unit, int excl) { const double epsilon = DBL_EPSILON; Index: ruby_2_6/internal.h =================================================================== --- ruby_2_6/internal.h (revision 66948) +++ ruby_2_6/internal.h (revision 66949) @@ -1669,6 +1669,7 @@ enum ruby_num_rounding_mode { https://github.com/ruby/ruby/blob/trunk/ruby_2_6/internal.h#L1669 int rb_num_to_uint(VALUE val, unsigned int *ret); VALUE ruby_num_interval_step_size(VALUE from, VALUE to, VALUE step, int excl); +double ruby_float_step_size(double beg, double end, double unit, int excl); int ruby_float_step(VALUE from, VALUE to, VALUE step, int excl, int allow_endless); double ruby_float_mod(double x, double y); int rb_num_negative_p(VALUE); Index: ruby_2_6/version.h =================================================================== --- ruby_2_6/version.h (revision 66948) +++ ruby_2_6/version.h (revision 66949) @@ -1,10 +1,10 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_6/version.h#L1 #define RUBY_VERSION "2.6.1" #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 32 +#define RUBY_PATCHLEVEL 33 #define RUBY_RELEASE_YEAR 2019 #define RUBY_RELEASE_MONTH 1 -#define RUBY_RELEASE_DAY 29 +#define RUBY_RELEASE_DAY 30 #include "ruby/version.h" Index: ruby_2_6/test/ruby/test_arithmetic_sequence.rb =================================================================== --- ruby_2_6/test/ruby/test_arithmetic_sequence.rb (revision 66948) +++ ruby_2_6/test/ruby/test_arithmetic_sequence.rb (revision 66949) @@ -141,12 +141,31 @@ class TestArithmeticSequence < Test::Uni https://github.com/ruby/ruby/blob/trunk/ruby_2_6/test/ruby/test_arithmetic_sequence.rb#L141 assert_equal([], seq.first(1)) assert_equal([], seq.first(3)) + seq = 1.step(10, by: 0) + assert_equal(1, seq.first) + assert_equal([1], seq.first(1)) + assert_equal([1, 1, 1], seq.first(3)) + seq = 10.0.step(-1.0, by: -2.0) assert_equal(10.0, seq.first) assert_equal([10.0], seq.first(1)) assert_equal([10.0, 8.0, 6.0], seq.first(3)) end + def test_first_bug15518 + bug15518 = '[Bug #15518]' + seq = (1 .. 10.0).step(1) + five_float_classes = Array.new(5) { Float } + assert_equal(five_float_classes, seq.first(5).map(&:class), bug15518) + assert_equal([1.0, 2.0, 3.0, 4.0, 5.0], seq.first(5), bug15518) + seq = (1 .. Float::INFINITY).step(1) + assert_equal(five_float_classes, seq.first(5).map(&:class), bug15518) + assert_equal([1.0, 2.0, 3.0, 4.0, 5.0], seq.first(5), bug15518) + seq = (1 .. Float::INFINITY).step(1r) + assert_equal(five_float_classes, seq.first(5).map(&:class), bug15518) + assert_equal([1.0, 2.0, 3.0, 4.0, 5.0], seq.first(5), bug15518) + end + def test_last seq = 1.step(10) assert_equal(10, seq.last) Index: ruby_2_6/enumerator.c =================================================================== --- ruby_2_6/enumerator.c (revision 66948) +++ ruby_2_6/enumerator.c (revision 66949) @@ -2809,27 +2809,132 @@ rb_arithmetic_sequence_extract(VALUE obj https://github.com/ruby/ruby/blob/trunk/ruby_2_6/enumerator.c#L2809 static VALUE arith_seq_first(int argc, VALUE *argv, VALUE self) { - VALUE b, e, s, len_1; + VALUE b, e, s, ary; + long n; + int x; + + rb_check_arity(argc, 0, 1); b = arith_seq_begin(self); e = arith_seq_end(self); s = arith_seq_step(self); - - if (!NIL_P(e)) { - len_1 = rb_int_idiv(rb_int_minus(e, b), s); - if (rb_num_negative_int_p(len_1)) { - if (argc == 0) { + if (argc == 0) { + if (!NIL_P(e)) { + VALUE zero = INT2FIX(0); + int r = rb_cmpint(rb_num_coerce_cmp(s, zero, idCmp), s, zero); + if (r > 0 && RTEST(rb_funcall(b, '>', 1, e))) { + return Qnil; + } + if (r < 0 && RTEST(rb_funcall(b, '<', 1, e))) { return Qnil; } - return rb_ary_new_capa(0); } + return b; } - if (argc == 0) { - return b; + // TODO: the following code should be extracted as arith_seq_take + + n = NUM2LONG(argv[0]); + if (n < 0) { + rb_raise(rb_eArgError, "attempt to take negative size"); } + if (n == 0) { + return rb_ary_new_capa(0); + } + + x = arith_seq_exclude_end_p(self); - /* TODO: optimization */ + if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(s)) { + long i = FIX2LONG(b), unit = FIX2LONG(s); + ary = rb_ary_new_capa(n); + while (n > 0 && FIXABLE(i)) { + rb_ary_push(ary, LONG2FIX(i)); + i += unit; // FIXABLE + FIXABLE never overflow; + --n; + } + if (n > 0) { + b = LONG2NUM(i); + while (n > 0) { + rb_ary_push(ary, b); + b = rb_big_plus(b, s); + --n; + } + } + return ary; + } + else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(s)) { + long i = FIX2LONG(b); + long end = FIX2LONG(e); + long unit = FIX2LONG(s); + long len; + + if (unit >= 0) { + if (!x) end += 1; + + len = end - i; + if (len < 0) len = 0; + ary = rb_ary_new_capa((n < len) ? n : len); + while (n > 0 && i < end) { + rb_ary_push(ary, LONG2FIX(i)); + if (i + unit < i) break; + i += unit; + --n; + } + } + else { + if (!x) end -= 1; + + len = i - end; + if (len < 0) len = 0; + ary = rb_ary_new_capa((n < len) ? n : len); + while (n > 0 && i > end) { + rb_ary_push(ary, LONG2FIX(i)); + if (i + unit > i) break; + i += unit; + --n; + } + } + return ary; + } + else if (RB_FLOAT_TYPE_P(b) || RB_FLOAT_TYPE_P(e) || RB_FLOAT_TYPE_P(s)) { + /* generate values like ruby_float_step */ + + double unit = NUM2DBL(s); + double beg = NUM2DBL(b); + double end = NIL_P(e) ? (unit < 0 ? -1 : 1)*HUGE_VAL : NUM2DBL(e); + double len = ruby_float_step_size(beg, end, unit, x); + long i; + + if (n > len) + n = (long)len; + + if (isinf(unit)) { + if (len > 0) { + ary = rb_ary_new_capa(1); + rb_ary_push(ary, DBL2NUM(beg)); + } + else { + ary = rb_ary_new_capa(0); + } + } + else if (unit == 0) { + VALUE val = DBL2NUM(beg); + ary = rb_ary_new_capa(n); + for (i = 0; i < len; ++i) { + rb_ary_push(ary, val); + } + } + else { + ary = rb_ary_new_capa(n); + for (i = 0; i < n; ++i) { + double d = i*unit+beg; + if (unit >= 0 ? end < d : d < end) d = end; + rb_ary_push(ary, DBL2NUM(d)); + } + } + + return ary; + } return rb_call_super(argc, argv); } Index: ruby_2_6 =================================================================== --- ruby_2_6 (revision 66948) +++ ruby_2_6 (revision 66949) Property changes on: ruby_2_6 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /trunk:r66947 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/