Project

General

Profile

Feature #14473 » v3-0001-range.c-add-subrange-superrange-methods.patch

owst (Owen Stephens), 03/25/2018 03:55 PM

View differences:

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] }
(3-3/6)