Skip to content

Commit

Permalink
Add fast isdisjoint method for ranges (#46356)
Browse files Browse the repository at this point in the history
Co-authored-by: Lilith Orion Hafner <lilithhafner@gmail.com>
Co-authored-by: Oscar Smith <oscardssmith@gmail.com>
  • Loading branch information
3 people authored Dec 7, 2022
1 parent 894f1a5 commit 3e9ca03
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 0 deletions.
21 changes: 21 additions & 0 deletions base/abstractset.jl
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,27 @@ function isdisjoint(a, b)
_isdisjoint(a, b)
end

function isdisjoint(a::AbstractRange{T}, b::AbstractRange{T}) where T
(isempty(a) || isempty(b)) && return true
fa, la = extrema(a)
fb, lb = extrema(b)
if (la < fb) | (lb < fa)
return true
else
return _overlapping_range_isdisjoint(a, b)
end
end

_overlapping_range_isdisjoint(a::AbstractRange{T}, b::AbstractRange{T}) where T = invoke(isdisjoint, Tuple{Any,Any}, a, b)

function _overlapping_range_isdisjoint(a::AbstractRange{T}, b::AbstractRange{T}) where T<:Integer
if abs(step(a)) == abs(step(b))
return mod(minimum(a), step(a)) != mod(minimum(b), step(a))
else
return invoke(isdisjoint, Tuple{Any,Any}, a, b)
end
end

## partial ordering of sets by containment

==(a::AbstractSet, b::AbstractSet) = length(a) == length(b) && a b
Expand Down
42 changes: 42 additions & 0 deletions test/sets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,48 @@ end
@test issubset(Set(Bool[]), rand(Bool, 100)) == true
# neither has a fast in, right doesn't have a length
@test isdisjoint([1, 3, 5, 7, 9], Iterators.filter(iseven, 1:10))

# range fast-path
for (truth, a, b) in (
# Integers
(true, 1:10, 11:20), # not overlapping
(false, 1:10, 5:20), # partial overlap
(false, 5:9, 1:10), # complete overlap
# complete overlap, unequal steps
(false, 3:6:60, 9:9:60),
(true, 4:6:60, 9:9:60),
(true, 0:6:12, 9:9:60),
(false, 6:6:18, 9:9:60),
(false, 12:6:18, 9:9:60),
(false, 18:6:18, 9:9:60),
(true, 1:2:3, 2:3:5),
(true, 1:4:5, 2:1:4),
(false, 4:12:124, 1:1:8),
# potential overflow
(false, 0x1:0x3:0x4, 0x4:0x3:0x4),
(true, 0x3:0x3:0x6, 0x4:0x3:0x4),
(false, typemax(Int8):Int8(3):typemax(Int8), typemin(Int8):Int8(3):typemax(Int8)),
# Chars
(true, 'a':'l', 'o':'p'), # not overlapping
(false, 'a':'l', 'h':'p'), # partial overlap
(false, 'a':'l', 'c':'e'), # complete overlap
# Floats
(true, 1.:10., 11.:20.), # not overlapping
(false, 1.:10., 5.:20.), # partial overlap
(false, 5.:9., 1.:10.), # complete overlap
# Inputs that may hang
(false, -6011687643038262928:3545293653953105048, -6446834672754204848:3271267329311042532),
)
@test isdisjoint(a, b) == truth
@test isdisjoint(b, a) == truth
@test isdisjoint(a, reverse(b)) == truth
@test isdisjoint(reverse(a), b) == truth
@test isdisjoint(b, reverse(a)) == truth
@test isdisjoint(reverse(b), a) == truth
end
@test isdisjoint(10:9, 1:10) # empty range
@test !isdisjoint(1e-100:.1:1, 0:.1:1)
@test !isdisjoint(eps()/4:.1:.71, 0:.1:1)
end

@testset "unique" begin
Expand Down

0 comments on commit 3e9ca03

Please sign in to comment.