Skip to content

Commit e3618dc

Browse files
committed
[GR-59866] Add Range#overlap?
PullRequest: truffleruby/4451
2 parents 9e605e0 + ccb20a8 commit e3618dc

File tree

4 files changed

+117
-0
lines changed

4 files changed

+117
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ Compatibility:
4949
* `Kernel#lambda` with now raises `ArgumentError` when given a non-lambda, non-literal block (#3681, @Th3-M4jor).
5050
* Add `rb_data_define()` to define Data (#3681, @andrykonchin).
5151
* Add `Refinement#target` (#3681, @andrykonchin).
52+
* Add `Range#overlap?` (#3681, @andrykonchin).
5253

5354
Performance:
5455

spec/ruby/core/range/overlap_spec.rb

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
require_relative '../../spec_helper'
2+
3+
ruby_version_is '3.3' do
4+
describe "Range#overlap?" do
5+
it "returns true if other Range overlaps self" do
6+
(0..2).overlap?(1..3).should == true
7+
(1..3).overlap?(0..2).should == true
8+
(0..2).overlap?(0..2).should == true
9+
(0..3).overlap?(1..2).should == true
10+
(1..2).overlap?(0..3).should == true
11+
12+
('a'..'c').overlap?('b'..'d').should == true
13+
end
14+
15+
it "returns false if other Range does not overlap self" do
16+
(0..2).overlap?(3..4).should == false
17+
(0..2).overlap?(-4..-1).should == false
18+
19+
('a'..'c').overlap?('d'..'f').should == false
20+
end
21+
22+
it "raises TypeError when called with non-Range argument" do
23+
-> {
24+
(0..2).overlap?(1)
25+
}.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
26+
end
27+
28+
it "returns true when beginningless and endless Ranges overlap" do
29+
(0..2).overlap?(..3).should == true
30+
(0..2).overlap?(..1).should == true
31+
(0..2).overlap?(..0).should == true
32+
33+
(..3).overlap?(0..2).should == true
34+
(..1).overlap?(0..2).should == true
35+
(..0).overlap?(0..2).should == true
36+
37+
(0..2).overlap?(-1..).should == true
38+
(0..2).overlap?(1..).should == true
39+
(0..2).overlap?(2..).should == true
40+
41+
(-1..).overlap?(0..2).should == true
42+
(1..).overlap?(0..2).should == true
43+
(2..).overlap?(0..2).should == true
44+
45+
(0..).overlap?(2..).should == true
46+
(..0).overlap?(..2).should == true
47+
end
48+
49+
it "returns false when beginningless and endless Ranges do not overlap" do
50+
(0..2).overlap?(..-1).should == false
51+
(0..2).overlap?(3..).should == false
52+
53+
(..-1).overlap?(0..2).should == false
54+
(3..).overlap?(0..2).should == false
55+
end
56+
57+
it "returns false when Ranges are not compatible" do
58+
(0..2).overlap?('a'..'d').should == false
59+
end
60+
61+
it "return false when self is empty" do
62+
(2..0).overlap?(1..3).should == false
63+
(2...2).overlap?(1..3).should == false
64+
(1...1).overlap?(1...1).should == false
65+
(2..0).overlap?(2..0).should == false
66+
67+
('c'..'a').overlap?('b'..'d').should == false
68+
('a'...'a').overlap?('b'..'d').should == false
69+
('b'...'b').overlap?('b'...'b').should == false
70+
('c'...'a').overlap?('c'...'a').should == false
71+
end
72+
73+
it "return false when other Range is empty" do
74+
(1..3).overlap?(2..0).should == false
75+
(1..3).overlap?(2...2).should == false
76+
77+
('b'..'d').overlap?('c'..'a').should == false
78+
('b'..'d').overlap?('c'...'c').should == false
79+
end
80+
81+
it "takes into account exclusive end" do
82+
(0...2).overlap?(2..4).should == false
83+
(2..4).overlap?(0...2).should == false
84+
85+
('a'...'c').overlap?('c'..'e').should == false
86+
('c'..'e').overlap?('a'...'c').should == false
87+
end
88+
end
89+
end

src/main/ruby/truffleruby/core/range.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,20 @@ def minmax(&block)
442442
end
443443
end
444444

445+
def overlap?(other)
446+
Truffle::Type.rb_check_type(other, Range)
447+
448+
# ranges don't overlap
449+
return false if Truffle::RangeOperations.greater_than?(self.begin, other.end, other.exclude_end?)
450+
return false if Truffle::RangeOperations.greater_than?(other.begin, self.end, self.exclude_end?)
451+
452+
# empty range doesn't overlap any other range
453+
return false if Truffle::RangeOperations.greater_than?(self.begin, self.end, self.exclude_end?)
454+
return false if Truffle::RangeOperations.greater_than?(other.begin, other.end, other.exclude_end?)
455+
456+
true
457+
end
458+
445459
def %(n)
446460
Truffle::RangeOperations.step_no_block(self, n)
447461
end

src/main/ruby/truffleruby/core/truffle/range_operations.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,5 +138,18 @@ def self.cover?(range, value)
138138

139139
true
140140
end
141+
142+
# MRI: empty_region_p
143+
def self.greater_than?(from, to, to_exclusive)
144+
return false if Primitive.nil?(from)
145+
return false if Primitive.nil?(to)
146+
147+
cmp = from <=> to
148+
149+
return true if Primitive.nil?(cmp)
150+
return true if cmp == 0 && to_exclusive
151+
152+
cmp > 0 # that's from > to
153+
end
141154
end
142155
end

0 commit comments

Comments
 (0)