Feature #14473 » v3-0001-range.c-add-subrange-superrange-methods.patch
range.c | ||
---|---|---|
#include <math.h>
|
||
VALUE rb_cRange;
|
||
static ID id_beg, id_end, id_excl, id_integer_p, id_div;
|
||
static ID id_beg, id_end, id_excl, id_integer_p, id_div, id_min, id_max;
|
||
#define id_cmp idCmp
|
||
#define id_succ idSucc
|
||
... | ... | |
}
|
||
static VALUE
|
||
r_cover_min_and_max_p(VALUE range, VALUE obj, VALUE (*func)(VALUE, VALUE, VALUE))
|
||
{
|
||
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
||
rb_raise(rb_eTypeError, "not a range object");
|
||
VALUE range_min = rb_funcall(range, id_min, 0);
|
||
if (range_min == Qnil)
|
||
return Qfalse;
|
||
VALUE range_max = rb_funcall(range, id_max, 0);
|
||
if (range_cover(obj, range_min) &&
|
||
range_cover(obj, range_max) &&
|
||
(!func || (*func)(obj, range_min, range_max))) {
|
||
return Qtrue;
|
||
}
|
||
return Qfalse;
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* rng.subrange?(obj) -> true or false
|
||
*
|
||
* Returns <code>true</code> if +obj+ is a Range and it covers the min and max
|
||
* elements of the range, <code>false</code> otherwise.
|
||
* Raises +TypeError+ if +obj+ is not a Range.
|
||
*
|
||
* ("b".."d").subrange?("b".."e") #=> true
|
||
* ("b".."e").subrange?("b".."e") #=> true
|
||
* ("a".."e").subrange?("b".."e") #=> false
|
||
*/
|
||
static VALUE
|
||
range_subrange(VALUE range, VALUE obj)
|
||
{
|
||
return r_cover_min_and_max_p(range, obj, NULL);
|
||
}
|
||
#define DIFFER_AT(recv, mid, val) (!rb_equal(rb_funcall(recv, mid, 0), val))
|
||
static VALUE
|
||
r_min_or_max_differ(VALUE obj, VALUE min, VALUE max)
|
||
{
|
||
return DIFFER_AT(obj, id_min, min) || DIFFER_AT(obj, id_max, max);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* rng.strict_subrange?(obj) -> true or false
|
||
*
|
||
* Returns <code>true</code> if +obj+ is a Range and it covers the min and max
|
||
* elements of the range and the ranges differ in their min or max elements,
|
||
* <code>false</code> otherwise.
|
||
* Raises +TypeError+ if +obj+ is not a Range.
|
||
*
|
||
* ("b".."d").strict_subrange?("b".."e") #=> true
|
||
* ("b".."e").strict_subrange?("b".."e") #=> false
|
||
* ("a".."e").strict_subrange?("b".."e") #=> false
|
||
*/
|
||
static VALUE
|
||
range_strict_subrange(VALUE range, VALUE obj)
|
||
{
|
||
return r_cover_min_and_max_p(range, obj, &r_min_or_max_differ);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* rng.superrange?(obj) -> true or false
|
||
*
|
||
* Returns <code>true</code> if +obj+ is a Range and its min and max elements
|
||
* are covered by the range, <code>false</code> otherwise.
|
||
* Raises +TypeError+ if +obj+ is not a Range.
|
||
*
|
||
* ("b".."e").superrange?("b".."d") #=> true
|
||
* ("b".."e").superrange?("b".."e") #=> true
|
||
* ("b".."e").superrange?("a".."e") #=> false
|
||
*/
|
||
static VALUE
|
||
range_superrange(VALUE range, VALUE obj)
|
||
{
|
||
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
||
rb_raise(rb_eTypeError, "not a range object");
|
||
return range_subrange(obj, range);
|
||
}
|
||
/*
|
||
* call-seq:
|
||
* rng.strict_superrange?(obj) -> true or false
|
||
*
|
||
* Returns <code>true</code> if +obj+ is a Range and its min and max elements
|
||
* are covered by the range and the ranges differ in their min or max
|
||
* elements, <code>false</code> otherwise.
|
||
* Raises +TypeError+ if +obj+ is not a Range.
|
||
*
|
||
* ("b".."e").strict_superrange?("b".."d") #=> true
|
||
* ("b".."e").strict_superrange?("b".."e") #=> false
|
||
* ("b".."e").strict_superrange?("a".."e") #=> false
|
||
*/
|
||
static VALUE
|
||
range_strict_superrange(VALUE range, VALUE obj)
|
||
{
|
||
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
||
rb_raise(rb_eTypeError, "not a range object");
|
||
return range_strict_subrange(obj, range);
|
||
}
|
||
static VALUE
|
||
range_dumper(VALUE range)
|
||
{
|
||
VALUE v;
|
||
... | ... | |
id_excl = rb_intern("excl");
|
||
id_integer_p = rb_intern("integer?");
|
||
id_div = rb_intern("div");
|
||
id_min = rb_intern("min");
|
||
id_max = rb_intern("max");
|
||
rb_cRange = rb_struct_define_without_accessor(
|
||
"Range", rb_cObject, range_alloc,
|
||
... | ... | |
rb_define_method(rb_cRange, "member?", range_include, 1);
|
||
rb_define_method(rb_cRange, "include?", range_include, 1);
|
||
rb_define_method(rb_cRange, "cover?", range_cover, 1);
|
||
rb_define_method(rb_cRange, "subrange?", range_subrange, 1);
|
||
rb_define_method(rb_cRange, "strict_subrange?", range_strict_subrange, 1);
|
||
rb_define_method(rb_cRange, "superrange?", range_superrange, 1);
|
||
rb_define_method(rb_cRange, "strict_superrange?", range_strict_superrange, 1);
|
||
}
|
test/ruby/test_range.rb | ||
---|---|---|
assert_operator("a".."z", :cover?, "cc")
|
||
end
|
||
def test_subrange
|
||
assert_operator("b".."e", :subrange?, "b".."e")
|
||
assert_operator("b".."e", :subrange?, "b"..."f")
|
||
assert_operator("b"..."f", :subrange?, "b".."e")
|
||
assert_operator("b".."d", :subrange?, "b".."e")
|
||
assert_operator("c".."e", :subrange?, "b".."e")
|
||
assert_operator("c".."d", :subrange?, "b".."e")
|
||
assert_not_operator("a".."e", :subrange?, "b".."e")
|
||
assert_not_operator("a".."e", :subrange?, "b"..."f")
|
||
assert_not_operator("a"..."f", :subrange?, "b".."e")
|
||
assert_not_operator("b".."f", :subrange?, "b".."e")
|
||
assert_not_operator("a".."f", :subrange?, "b".."e")
|
||
assert_not_operator("g".."f", :subrange?, "b".."e")
|
||
assert_not_operator("b".."c", :subrange?, "d".."a")
|
||
assert_not_operator("c".."b", :subrange?, "d".."a")
|
||
assert_raise(TypeError) { ("a".."c").subrange?("x") }
|
||
end
|
||
def test_strict_subrange
|
||
assert_operator("b".."d", :strict_subrange?, "b".."e")
|
||
assert_operator("b".."d", :strict_subrange?, "b"..."f")
|
||
assert_operator("b"..."e", :strict_subrange?, "b".."e")
|
||
assert_not_operator("b".."e", :strict_subrange?, "b".."e")
|
||
assert_not_operator("b".."e", :strict_subrange?, "b"..."f")
|
||
assert_not_operator("b"..."f", :strict_subrange?, "b".."e")
|
||
assert_not_operator("a".."e", :strict_subrange?, "b".."e")
|
||
assert_not_operator("b".."f", :strict_subrange?, "b".."e")
|
||
assert_not_operator("a".."f", :strict_subrange?, "b".."e")
|
||
assert_not_operator("g".."f", :strict_subrange?, "b".."e")
|
||
assert_not_operator("b".."c", :strict_subrange?, "d".."a")
|
||
assert_not_operator("c".."b", :strict_subrange?, "d".."a")
|
||
assert_raise(TypeError) { ("a".."c").strict_subrange?("x") }
|
||
end
|
||
def test_superrange
|
||
assert_operator("b".."e", :superrange?, "b".."e")
|
||
assert_operator("b".."e", :superrange?, "b"..."f")
|
||
assert_operator("b"..."f", :superrange?, "b".."e")
|
||
assert_operator("b".."e", :superrange?, "b".."d")
|
||
assert_operator("b".."e", :superrange?, "c".."e")
|
||
assert_operator("b".."e", :superrange?, "c".."d")
|
||
assert_not_operator("b".."e", :superrange?, "a".."e")
|
||
assert_not_operator("b".."e", :superrange?, "a"..."f")
|
||
assert_not_operator("b"..."f", :superrange?, "a".."e")
|
||
assert_not_operator("b".."e", :superrange?, "b".."f")
|
||
assert_not_operator("b".."e", :superrange?, "a".."f")
|
||
assert_not_operator("b".."e", :superrange?, "b".."f")
|
||
assert_not_operator("b".."e", :superrange?, "a".."f")
|
||
assert_not_operator("b".."e", :subrange?, "g".."f")
|
||
assert_not_operator("d".."a", :subrange?, "b".."c")
|
||
assert_not_operator("d".."a", :subrange?, "c".."b")
|
||
assert_raise(TypeError) { ("a".."c").superrange?("x") }
|
||
end
|
||
def test_strict_superrange
|
||
assert_operator("b".."e", :strict_superrange?, "b".."d")
|
||
assert_operator("b".."e", :strict_superrange?, "b"..."e")
|
||
assert_operator("b"..."f", :strict_superrange?, "b".."d")
|
||
assert_operator("b".."e", :strict_superrange?, "c".."e")
|
||
assert_operator("b".."e", :strict_superrange?, "c".."d")
|
||
assert_not_operator("b".."e", :strict_superrange?, "b".."e")
|
||
assert_not_operator("b".."e", :strict_superrange?, "b"..."f")
|
||
assert_not_operator("b"..."f", :strict_superrange?, "b".."e")
|
||
assert_not_operator("b".."e", :strict_superrange?, "a".."e")
|
||
assert_not_operator("b".."e", :strict_superrange?, "b".."f")
|
||
assert_not_operator("b".."e", :strict_superrange?, "a".."f")
|
||
assert_not_operator("b".."e", :strict_subrange?, "g".."f")
|
||
assert_not_operator("d".."a", :strict_subrange?, "b".."c")
|
||
assert_not_operator("d".."a", :strict_subrange?, "c".."b")
|
||
assert_raise(TypeError) { ("a".."c").strict_superrange?("x") }
|
||
end
|
||
def test_beg_len
|
||
o = Object.new
|
||
assert_raise(TypeError) { [][o] }
|