Make Range#min, max, include?, cover?, and === to support endless range

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@63194 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
mame 2018-04-19 15:18:53 +00:00
parent 8a80985017
commit db1bdecb0d
2 changed files with 40 additions and 5 deletions

20
range.c
View File

@ -960,7 +960,7 @@ range_min(int argc, VALUE *argv, VALUE range)
struct cmp_opt_data cmp_opt = { 0, 0 }; struct cmp_opt_data cmp_opt = { 0, 0 };
VALUE b = RANGE_BEG(range); VALUE b = RANGE_BEG(range);
VALUE e = RANGE_END(range); VALUE e = RANGE_END(range);
int c = OPTIMIZED_CMP(b, e, cmp_opt); int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
if (c > 0 || (c == 0 && EXCL(range))) if (c > 0 || (c == 0 && EXCL(range)))
return Qnil; return Qnil;
@ -991,6 +991,8 @@ range_max(int argc, VALUE *argv, VALUE range)
VALUE e = RANGE_END(range); VALUE e = RANGE_END(range);
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric); int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
if (NIL_P(e)) return Qnil;
if (rb_block_given_p() || (EXCL(range) && !nm) || argc) { if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
return rb_call_super(argc, argv); return rb_call_super(argc, argv);
} }
@ -1200,9 +1202,17 @@ range_include(VALUE range, VALUE val)
!NIL_P(rb_check_to_integer(end, "to_int"))) { !NIL_P(rb_check_to_integer(end, "to_int"))) {
return r_cover_p(range, beg, end, val); return r_cover_p(range, beg, end, val);
} }
else if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) { else if (RB_TYPE_P(beg, T_STRING)) {
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive); if (RB_TYPE_P(end, T_STRING)) {
return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range)); VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range));
}
else if (NIL_P(end)) {
VALUE r = rb_funcall(beg, id_cmp, 1, val);
if (NIL_P(r)) return Qfalse;
if (rb_cmpint(r, beg, val) <= 0) return Qtrue;
return Qfalse;
}
} }
/* TODO: ruby_frame->this_func = rb_intern("include?"); */ /* TODO: ruby_frame->this_func = rb_intern("include?"); */
return rb_call_super(1, &val); return rb_call_super(1, &val);
@ -1239,7 +1249,7 @@ r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
{ {
if (r_less(beg, val) <= 0) { if (r_less(beg, val) <= 0) {
int excl = EXCL(range); int excl = EXCL(range);
if (r_less(val, end) <= -excl) if (NIL_P(end) || r_less(val, end) <= -excl)
return Qtrue; return Qtrue;
} }
return Qfalse; return Qfalse;

View File

@ -79,22 +79,27 @@ class TestRange < Test::Unit::TestCase
assert_equal(1, (1..2).min) assert_equal(1, (1..2).min)
assert_equal(nil, (2..1).min) assert_equal(nil, (2..1).min)
assert_equal(1, (1...2).min) assert_equal(1, (1...2).min)
assert_equal(1, (1..).min)
assert_equal(1.0, (1.0..2.0).min) assert_equal(1.0, (1.0..2.0).min)
assert_equal(nil, (2.0..1.0).min) assert_equal(nil, (2.0..1.0).min)
assert_equal(1, (1.0...2.0).min) assert_equal(1, (1.0...2.0).min)
assert_equal(1, (1.0..).min)
assert_equal(0, (0..0).min) assert_equal(0, (0..0).min)
assert_equal(nil, (0...0).min) assert_equal(nil, (0...0).min)
assert_equal([0,1,2], (0..10).min(3)) assert_equal([0,1,2], (0..10).min(3))
assert_equal([0,1], (0..1).min(3)) assert_equal([0,1], (0..1).min(3))
assert_equal([0,1,2], (0..).min(3))
end end
def test_max def test_max
assert_equal(2, (1..2).max) assert_equal(2, (1..2).max)
assert_equal(nil, (2..1).max) assert_equal(nil, (2..1).max)
assert_equal(1, (1...2).max) assert_equal(1, (1...2).max)
assert_equal(nil, (1..).max)
assert_equal(nil, (1...).max)
assert_equal(2.0, (1.0..2.0).max) assert_equal(2.0, (1.0..2.0).max)
assert_equal(nil, (2.0..1.0).max) assert_equal(nil, (2.0..1.0).max)
@ -109,6 +114,7 @@ class TestRange < Test::Unit::TestCase
assert_equal([10,9,8], (0..10).max(3)) assert_equal([10,9,8], (0..10).max(3))
assert_equal([9,8,7], (0...10).max(3)) assert_equal([9,8,7], (0...10).max(3))
# XXX: How should (0...).max(3) behave?
end end
def test_initialize_twice def test_initialize_twice
@ -360,6 +366,11 @@ class TestRange < Test::Unit::TestCase
assert_equal("a", ("a"..."c").first) assert_equal("a", ("a"..."c").first)
assert_equal("c", ("a"..."c").last) assert_equal("c", ("a"..."c").last)
assert_equal(0, (2...0).last) assert_equal(0, (2...0).last)
assert_equal([0, 1, 2], (0..nil).first(3))
assert_equal(0, (0..nil).first)
assert_equal("a", ("a"..nil).first)
# XXX: How should (0...).last(3) behave?
end end
def test_to_s def test_to_s
@ -389,6 +400,8 @@ class TestRange < Test::Unit::TestCase
def test_eqq def test_eqq
assert_operator(0..10, :===, 5) assert_operator(0..10, :===, 5)
assert_not_operator(0..10, :===, 11) assert_not_operator(0..10, :===, 11)
assert_operator(5..nil, :===, 11)
assert_not_operator(5..nil, :===, 0)
end end
def test_eqq_time def test_eqq_time
@ -396,6 +409,8 @@ class TestRange < Test::Unit::TestCase
t = Time.now t = Time.now
assert_nothing_raised(TypeError, bug11113) { assert_nothing_raised(TypeError, bug11113) {
assert_operator(t..(t+10), :===, t+5) assert_operator(t..(t+10), :===, t+5)
assert_operator(t.., :===, t+5)
assert_not_operator(t.., :===, t-5)
} }
end end
@ -430,6 +445,8 @@ class TestRange < Test::Unit::TestCase
assert_not_include("a"..."z", "z") assert_not_include("a"..."z", "z")
assert_not_include("a".."z", "cc") assert_not_include("a".."z", "cc")
assert_include(0...10, 5) assert_include(0...10, 5)
assert_include(5..., 10)
assert_not_include(5..., 0)
end end
def test_cover def test_cover
@ -438,6 +455,9 @@ class TestRange < Test::Unit::TestCase
assert_operator("a"..."z", :cover?, "y") assert_operator("a"..."z", :cover?, "y")
assert_not_operator("a"..."z", :cover?, "z") assert_not_operator("a"..."z", :cover?, "z")
assert_operator("a".."z", :cover?, "cc") assert_operator("a".."z", :cover?, "cc")
assert_not_operator(5..., :cover?, 0)
assert_not_operator(5..., :cover?, "a")
assert_operator(5.., :cover?, 10)
end end
def test_beg_len def test_beg_len
@ -515,6 +535,11 @@ class TestRange < Test::Unit::TestCase
assert_equal 6, (1...6.3).size assert_equal 6, (1...6.3).size
assert_equal 5, (1.1...6).size assert_equal 5, (1.1...6).size
assert_equal 42, (1..42).each.size assert_equal 42, (1..42).each.size
assert_nil ("a"..."z").size
assert_nil (1...).size
assert_nil (1.0...).size
assert_nil ("a"...).size
end end
def test_bsearch_typechecks_return_values def test_bsearch_typechecks_return_values