summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShouichi Kamiya <[email protected]>2023-08-18 10:30:57 +0900
committerNobuyoshi Nakada <[email protected]>2023-09-16 14:57:19 +0900
commite9b503f1bb9692eda1d1f55f62c19d861b88a0d5 (patch)
tree8c3a734105021eea0f5235a844e8b93dccaa3d27
parent7d08dbd015a16c27f2d9c77751e80fa6efba2d7a (diff)
[Feature #19839] Add Range#overlap?
Add a method that returns true if two range overlap, otherwise false. ``` (0..10).overlap?(5..15) #=> true (0..10).overlap?(20..30) #=> false ```
-rw-r--r--range.c29
-rw-r--r--test/ruby/test_range.rb28
2 files changed, 57 insertions, 0 deletions
diff --git a/range.c b/range.c
index b18a25ea35..946da0c4de 100644
--- a/range.c
+++ b/range.c
@@ -2151,6 +2151,34 @@ range_count(int argc, VALUE *argv, VALUE range)
}
}
+/*
+ * call-seq:
+ * overlap?(range) -> true or false
+ *
+ * Returns +true+ if +range+ overlaps with +self+, +false+ otherwise:
+ *
+ * (0..2).overlap?(1..3) #=> true
+ * (0..2).overlap?(3..4) #=> false
+ * (0..).overlap?(..0) #=> true
+ *
+ * Related: Range#cover?.
+ */
+
+static VALUE
+range_overlap(VALUE range, VALUE other)
+{
+ if (!rb_obj_is_kind_of(other, rb_cRange)) {
+ rb_raise(rb_eTypeError, "argument must be Range");
+ }
+
+ VALUE beg_self, beg_other;
+
+ beg_self = RANGE_BEG(range);
+ beg_other = RANGE_BEG(other);
+
+ return RBOOL(rb_equal(beg_self, beg_other) || range_cover(range, beg_other) || range_cover(other, beg_self));
+}
+
/* A \Range object represents a collection of values
* that are between given begin and end values.
*
@@ -2417,4 +2445,5 @@ Init_Range(void)
rb_define_method(rb_cRange, "include?", range_include, 1);
rb_define_method(rb_cRange, "cover?", range_cover, 1);
rb_define_method(rb_cRange, "count", range_count, -1);
+ rb_define_method(rb_cRange, "overlap?", range_overlap, 1);
}
diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb
index 820ca9e9c2..17d1e3a431 100644
--- a/test/ruby/test_range.rb
+++ b/test/ruby/test_range.rb
@@ -1051,4 +1051,32 @@ class TestRange < Test::Unit::TestCase
def test_count
assert_equal(Float::INFINITY, (1..).count)
end
+
+ def test_overlap?
+ assert_not_operator(0..2, :overlap?, -2..-1)
+ assert_not_operator(0..2, :overlap?, -2...0)
+ assert_operator(0..2, :overlap?, -1..0)
+ assert_operator(0..2, :overlap?, 1..2)
+ assert_operator(0..2, :overlap?, 2..3)
+ assert_not_operator(0..2, :overlap?, 3..4)
+ assert_not_operator(0...2, :overlap?, 2..3)
+
+ assert_operator(..0, :overlap?, -1..0)
+ assert_operator(...0, :overlap?, -1..0)
+ assert_operator(..0, :overlap?, 0..1)
+ assert_operator(..0, :overlap?, ..1)
+ assert_not_operator(..0, :overlap?, 1..2)
+ assert_not_operator(...0, :overlap?, 0..1)
+
+ assert_not_operator(0.., :overlap?, -2..-1)
+ assert_not_operator(0.., :overlap?, ...0)
+ assert_operator(0.., :overlap?, -1..0)
+ assert_operator(0.., :overlap?, ..0)
+ assert_operator(0.., :overlap?, 0..1)
+ assert_operator(0.., :overlap?, 1..2)
+ assert_operator(0.., :overlap?, 1..)
+
+ assert_raise(TypeError) { (0..).overlap?(1) }
+ assert_raise(TypeError) { (0..).overlap?(nil) }
+ end
end