Permalink
Browse files

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]

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_2_6@66949 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
  • Loading branch information...
nurse committed Jan 30, 2019
1 parent fdca654 commit 0a9410cea1186fadfc346c66b56d90401419bbda
Showing with 138 additions and 13 deletions.
  1. +115 −10 enumerator.c
  2. +1 −0 internal.h
  3. +1 −1 numeric.c
  4. +19 −0 test/ruby/test_arithmetic_sequence.rb
  5. +2 −2 version.h
@@ -2809,27 +2809,132 @@ rb_arithmetic_sequence_extract(VALUE obj, rb_arithmetic_sequence_components_t *c
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);
}

/* TODO: optimization */
x = arith_seq_exclude_end_p(self);

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);
}
@@ -1669,6 +1669,7 @@ enum ruby_num_rounding_mode {

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);
@@ -2481,7 +2481,7 @@ num_truncate(int argc, VALUE *argv, VALUE num)
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;
@@ -141,12 +141,31 @@ def test_first
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)
@@ -1,10 +1,10 @@
#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"

0 comments on commit 0a9410c

Please sign in to comment.