diff options
author | Kouhei Yanagita <[email protected]> | 2024-12-10 11:51:49 +0900 |
---|---|---|
committer | Nobuyoshi Nakada <[email protected]> | 2024-12-10 23:12:27 +0900 |
commit | 3422bfcab6bfdedd10e5c85f5fd6334387712bc6 (patch) | |
tree | 683ecdc8a957e1dbf1c405b59ec4726c996a3c04 | |
parent | d5abcae43500e3b51b9fcb0918d7e849e024aee1 (diff) |
[Bug #20936] Fix #size for Range#reverse_each
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/12301
-rw-r--r-- | range.c | 51 | ||||
-rw-r--r-- | test/ruby/test_range.rb | 19 |
2 files changed, 67 insertions, 3 deletions
@@ -908,6 +908,10 @@ sym_each_i(VALUE v, VALUE arg) return each_i(rb_str_intern(v), arg); } +#define CANT_ITERATE_FROM(x) \ + rb_raise(rb_eTypeError, "can't iterate from %s", \ + rb_obj_classname(x)) + /* * call-seq: * size -> non_negative_integer or Infinity or nil @@ -944,13 +948,48 @@ range_size(VALUE range) } if (!discrete_object_p(b)) { - rb_raise(rb_eTypeError, "can't iterate from %s", - rb_obj_classname(b)); + CANT_ITERATE_FROM(b); } return Qnil; } +static VALUE +range_reverse_size(VALUE range) +{ + VALUE b = RANGE_BEG(range), e = RANGE_END(range); + + if (NIL_P(e)) { + CANT_ITERATE_FROM(e); + } + + if (RB_INTEGER_TYPE_P(b)) { + if (rb_obj_is_kind_of(e, rb_cNumeric)) { + return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range)); + } + else { + CANT_ITERATE_FROM(e); + } + } + + if (NIL_P(b)) { + if (RB_INTEGER_TYPE_P(e)) { + return DBL2NUM(HUGE_VAL); + } + else { + CANT_ITERATE_FROM(e); + } + } + + if (!discrete_object_p(b)) { + CANT_ITERATE_FROM(e); + } + + return Qnil; +} + +#undef CANT_ITERATE_FROM + /* * call-seq: * to_a -> array @@ -979,6 +1018,12 @@ range_enum_size(VALUE range, VALUE args, VALUE eobj) return range_size(range); } +static VALUE +range_enum_reverse_size(VALUE range, VALUE args, VALUE eobj) +{ + return range_reverse_size(range); +} + RBIMPL_ATTR_NORETURN() static void range_each_bignum_endless(VALUE beg) @@ -1225,7 +1270,7 @@ range_reverse_each_negative_bignum_section(VALUE beg, VALUE end) static VALUE range_reverse_each(VALUE range) { - RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size); + RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_reverse_size); VALUE beg = RANGE_BEG(range); VALUE end = RANGE_END(range); diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index e0c1d20bd2..480f213029 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -823,6 +823,25 @@ class TestRange < Test::Unit::TestCase assert_equal [5, 4, 3, 2, 1], a end + def test_reverse_each_size + assert_equal(3, (1..3).reverse_each.size) + assert_equal(3, (1..3.3).reverse_each.size) + assert_raise(TypeError) { (1..nil).reverse_each.size } + assert_raise(TypeError) { (1.1..3).reverse_each.size } + assert_raise(TypeError) { (1.1..3.3).reverse_each.size } + assert_raise(TypeError) { (1.1..nil).reverse_each.size } + assert_equal(Float::INFINITY, (..3).reverse_each.size) + assert_raise(TypeError) { (nil..3.3).reverse_each.size } + assert_raise(TypeError) { (nil..nil).reverse_each.size } + + assert_equal(2, (1...3).reverse_each.size) + assert_equal(3, (1...3.3).reverse_each.size) + + assert_equal(nil, ('a'..'z').reverse_each.size) + assert_raise(TypeError) { ('a'..).reverse_each.size } + assert_raise(TypeError) { (..'z').reverse_each.size } + end + def test_begin_end assert_equal(0, (0..1).begin) assert_equal(1, (0..1).end) |