Skip to content

Commit

Permalink
Make empty ranges compare equal (#32348)
Browse files Browse the repository at this point in the history
  • Loading branch information
sostock authored May 4, 2020
1 parent 6418be9 commit a6e27b3
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 46 deletions.
1 change: 1 addition & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ New library features

Standard library changes
------------------------
* Empty ranges now compare equal, regardless of their startpoint and step ([#32348]).
* A 1-d `Zip` iterator (where `Base.IteratorSize` is `Base.HasShape{1}()`) with defined length of `n` has now also size of `(n,)` (instead of throwing an error with truncated iterators) ([#29927]).
* The `@timed` macro now returns a `NamedTuple` ([#34149])
* New `supertypes(T)` function returns a tuple of all supertypes of `T` ([#34419]).
Expand Down
10 changes: 6 additions & 4 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -743,18 +743,20 @@ show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r)))
show(io::IO, r::OneTo) = print(io, "Base.OneTo(", r.stop, ")")

==(r::T, s::T) where {T<:AbstractRange} =
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))
==(r::OrdinalRange, s::OrdinalRange) =
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))
==(r::T, s::T) where {T<:Union{StepRangeLen,LinRange}} =
(first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s))
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s)))
==(r::Union{StepRange{T},StepRangeLen{T,T}}, s::Union{StepRange{T},StepRangeLen{T,T}}) where {T} =
(first(r) == first(s)) & (last(r) == last(s)) & (step(r) == step(s))
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))

function ==(r::AbstractRange, s::AbstractRange)
lr = length(r)
if lr != length(s)
return false
elseif iszero(lr)
return true
end
yr, ys = iterate(r), iterate(s)
while yr !== nothing
Expand Down
8 changes: 4 additions & 4 deletions base/strings/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,8 @@ end
function _split(str::AbstractString, splitter, limit::Integer, keepempty::Bool, strs::Array)
i = 1 # firstindex(str)
n = lastindex(str)
r = something(findfirst(splitter,str), 0)
if r != 0:-1
r = findfirst(splitter,str)
if !isnothing(r)
j, k = first(r), nextind(str,last(r))
while 0 < j <= n && length(strs) != limit-1
if i < k
Expand All @@ -403,8 +403,8 @@ function _split(str::AbstractString, splitter, limit::Integer, keepempty::Bool,
i = k
end
(k <= j) && (k = nextind(str,j))
r = something(findnext(splitter,str,k), 0)
r == 0:-1 && break
r = findnext(splitter,str,k)
isnothing(r) && break
j, k = first(r), nextind(str,last(r))
end
end
Expand Down
8 changes: 4 additions & 4 deletions stdlib/Dates/test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ let
@test first(reverse(dr)) < f1
@test last(reverse(dr)) >= f1
@test issorted(dr)
@test sortperm(dr) == 1:1:0
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
@test !(f1 in dr)
@test !(l1 in dr)
@test !(f1 - pos_step in dr)
Expand Down Expand Up @@ -93,7 +93,7 @@ let
@test first(reverse(dr)) > l1
@test last(reverse(dr)) <= l1
@test issorted(dr)
@test sortperm(dr) == 1:1:0
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
@test !(l1 in dr)
@test !(l1 in dr)
@test !(l1 - neg_step in dr)
Expand Down Expand Up @@ -153,7 +153,7 @@ let
@test first(reverse(dr)) < f1
@test last(reverse(dr)) >= f1
@test issorted(dr)
@test sortperm(dr) == 1:1:0
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
@test !(f1 in dr)
@test !(l1 in dr)
@test !(f1 - pos_step in dr)
Expand Down Expand Up @@ -211,7 +211,7 @@ let
@test first(reverse(dr)) > l1
@test last(reverse(dr)) <= l1
@test issorted(dr)
@test sortperm(dr) == 1:1:0
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
@test !(l1 in dr)
@test !(l1 in dr)
@test !(l1 - neg_step in dr)
Expand Down
15 changes: 10 additions & 5 deletions stdlib/REPL/test/replcompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ end
let s = "Main.CompletionFoo."
c, r = test_complete(s)
@test "bar" in c
@test r == 20:19
@test r === UnitRange{Int64}(20:19)
@test s[r] == ""
end

Expand Down Expand Up @@ -592,7 +592,12 @@ end

# The return type is of importance, before #8995 it would return nothing
# which would raise an error in the repl code.
@test (String[], 0:-1, false) == test_scomplete("\$a")
let c, r, res
c, r, res = test_scomplete("\$a")
@test c == String[]
@test r === UnitRange{Int64}(0:-1)
@test res === false
end

if Sys.isunix()
let s, c, r
Expand Down Expand Up @@ -640,7 +645,7 @@ let s, c, r
s = "/tmp/"
c,r = test_scomplete(s)
@test !("tmp/" in c)
@test r == 6:5
@test r === UnitRange{Int64}(6:5)
@test s[r] == ""
end

Expand All @@ -657,7 +662,7 @@ let s, c, r
file = joinpath(path, "repl completions")
s = "/tmp "
c,r = test_scomplete(s)
@test r == 6:5
@test r === UnitRange{Int64}(6:5)
end

# Test completing paths with an escaped trailing space
Expand Down Expand Up @@ -971,7 +976,7 @@ end
let s = ""
c, r = test_complete_context(s)
@test "bar" in c
@test r == 1:0
@test r === UnitRange{Int64}(1:0)
@test s[r] == ""
end

Expand Down
2 changes: 1 addition & 1 deletion test/core.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6796,7 +6796,7 @@ function f27597(y)
return y
end
@test f27597([1]) == [1]
@test f27597([]) == 1:0
@test f27597([]) === 1:0

# issue #22291
wrap22291(ind) = (ind...,)
Expand Down
2 changes: 1 addition & 1 deletion test/offsetarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ v = OffsetArray(rand(8), (-2,))
@test sort(A, dims=2) == OffsetArray(sort(parent(A), dims=2), A.offsets)
# Issue #33977
soa = OffsetArray([2,2,3], -2)
@test searchsorted(soa, 1) == -1:-2
@test searchsorted(soa, 1) === -1:-2
@test searchsortedfirst(soa, 1) == -1
@test searchsortedlast(soa, 1) == -2
@test first(sort!(soa; alg=QuickSort)) == 2
Expand Down
12 changes: 7 additions & 5 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -459,10 +459,10 @@ end
end
end
@testset "indexing range with empty range (#4309)" begin
@test (3:6)[5:4] == 7:6
@test (3:6)[5:4] === 7:6
@test_throws BoundsError (3:6)[5:5]
@test_throws BoundsError (3:6)[5]
@test (0:2:10)[7:6] == 12:2:10
@test (0:2:10)[7:6] === 12:2:10
@test_throws BoundsError (0:2:10)[7:7]
end
# indexing with negative ranges (#8351)
Expand Down Expand Up @@ -818,7 +818,8 @@ end
map(Int32,1:3:17), map(Int64,1:3:17), 1:0, 1:-1:0, 17:-3:0,
0.0:0.1:1.0, map(Float32,0.0:0.1:1.0),map(Float32,LinRange(0.0, 1.0, 11)),
1.0:eps():1.0 .+ 10eps(), 9007199254740990.:1.0:9007199254740994,
range(0, stop=1, length=20), map(Float32, range(0, stop=1, length=20))]
range(0, stop=1, length=20), map(Float32, range(0, stop=1, length=20)),
3:2, 5:-2:7, range(0.0, step=2.0, length=0), 3//2:3//2:0//1, LinRange(2,3,0)]
for r in Rs
local r
ar = Vector(r)
Expand All @@ -838,6 +839,7 @@ end
@test 1:1:10 == 1:10 == 1:10 == Base.OneTo(10) == Base.OneTo(10)
@test 1:10 != 2:10 != 2:11 != Base.OneTo(11)
@test Base.OneTo(10) != Base.OneTo(11) != 1:10
@test Base.OneTo(0) == 5:4
end
# issue #2959
@test 1.0:1.5 == 1.0:1.0:1.5 == 1.0:1.0
Expand Down Expand Up @@ -1555,11 +1557,11 @@ end
for stops in [-2, 0, 2, 100]
for lengths in [2, 10, 100]
if stops >= starts
@test range(starts, stops, length=lengths) == range(starts, stop=stops, length=lengths)
@test range(starts, stops, length=lengths) === range(starts, stop=stops, length=lengths)
end
end
for steps in [0.01, 1, 2]
@test range(starts, stops, step=steps) == range(starts, stop=stops, step=steps)
@test range(starts, stops, step=steps) === range(starts, stop=stops, step=steps)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions test/regex.jl
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@
# findall
@test findall(r"\w+", "foo bar") == [1:3, 5:7]
@test findall(r"\w+", "foo bar", overlap=true) == [1:3, 2:3, 3:3, 5:7, 6:7, 7:7]
@test findall(r"\w*", "foo bar") == [1:3, 4:3, 5:7, 8:7]
@test findall(r"\b", "foo bar") == [1:0, 4:3, 5:4, 8:7]
@test all(findall(r"\w*", "foo bar") .=== [1:3, 4:3, 5:7, 8:7]) # use === to compare empty ranges
@test all(findall(r"\b", "foo bar") .=== [1:0, 4:3, 5:4, 8:7]) # use === to compare empty ranges

# count
@test count(r"\w+", "foo bar") == 2
Expand Down
34 changes: 17 additions & 17 deletions test/sorting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,16 @@ end
@test searchsorted(fill(1, 15), 1, 6, 10, Forward) == 6:10

for R in numTypes, T in numTypes
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(0)) == 1:0
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(0)) === 1:0
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(1)) == 1:2
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(2)) == 3:4
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(4)) == 7:6
@test searchsorted(R[1, 1, 2, 2, 3, 3], 2.5) == 5:4
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(4)) === 7:6
@test searchsorted(R[1, 1, 2, 2, 3, 3], 2.5) === 5:4

@test searchsorted(1:3, T(0)) == 1:0
@test searchsorted(1:3, T(0)) === 1:0
@test searchsorted(1:3, T(1)) == 1:1
@test searchsorted(1:3, T(2)) == 2:2
@test searchsorted(1:3, T(4)) == 4:3
@test searchsorted(1:3, T(4)) === 4:3

@test searchsorted(R[1:10;], T(1), by=(x -> x >= 5)) == 1:4
@test searchsorted(R[1:10;], T(10), by=(x -> x >= 5)) == 5:10
Expand All @@ -109,31 +109,31 @@ end
rg_r = reverse(rg)
rgv, rgv_r = [rg;], [rg_r;]
for i = I
@test searchsorted(rg,i) == searchsorted(rgv,i)
@test searchsorted(rg_r,i,rev=true) == searchsorted(rgv_r,i,rev=true)
@test searchsorted(rg,i) === searchsorted(rgv,i)
@test searchsorted(rg_r,i,rev=true) === searchsorted(rgv_r,i,rev=true)
end
end

rg = 0.0:0.01:1.0
for i = 2:101
@test searchsorted(rg, rg[i]) == i:i
@test searchsorted(rg, prevfloat(rg[i])) == i:i-1
@test searchsorted(rg, nextfloat(rg[i])) == i+1:i
@test searchsorted(rg, prevfloat(rg[i])) === i:i-1
@test searchsorted(rg, nextfloat(rg[i])) === i+1:i
end

rg_r = reverse(rg)
for i = 1:100
@test searchsorted(rg_r, rg_r[i], rev=true) == i:i
@test searchsorted(rg_r, prevfloat(rg_r[i]), rev=true) == i+1:i
@test searchsorted(rg_r, nextfloat(rg_r[i]), rev=true) == i:i-1
@test searchsorted(rg_r, prevfloat(rg_r[i]), rev=true) === i+1:i
@test searchsorted(rg_r, nextfloat(rg_r[i]), rev=true) === i:i-1
end

@test searchsorted(1:10, 1, by=(x -> x >= 5)) == searchsorted([1:10;], 1, by=(x -> x >= 5))
@test searchsorted(1:10, 10, by=(x -> x >= 5)) == searchsorted([1:10;], 10, by=(x -> x >= 5))

@test searchsorted([], 0) == 1:0
@test searchsorted([1,2,3], 0) == 1:0
@test searchsorted([1,2,3], 4) == 4:3
@test searchsorted([], 0) === 1:0
@test searchsorted([1,2,3], 0) === 1:0
@test searchsorted([1,2,3], 4) === 4:3

@testset "issue 8866" begin
@test searchsortedfirst(500:1.0:600, -1.0e20) == 1
Expand Down Expand Up @@ -194,11 +194,11 @@ end
for v0 = (3:-1:1, 3.0:-1.0:1.0), v = (v0, collect(v0))
@test searchsorted(v, 3, rev=true) == 1:1
@test searchsorted(v, 3.0, rev=true) == 1:1
@test searchsorted(v, 2.5, rev=true) == 2:1
@test searchsorted(v, 2.5, rev=true) === 2:1
@test searchsorted(v, 2, rev=true) == 2:2
@test searchsorted(v, 1.2, rev=true) == 3:2
@test searchsorted(v, 1.2, rev=true) === 3:2
@test searchsorted(v, 1, rev=true) == 3:3
@test searchsorted(v, 0.1, rev=true) == 4:3
@test searchsorted(v, 0.1, rev=true) === 4:3
end
end
end
Expand Down
6 changes: 3 additions & 3 deletions test/strings/search.jl
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ end
for i = 1:lastindex(u8str)
@test findnext("", u8str, i) == i:i-1
end
@test findfirst("", "") == 1:0
@test findfirst("", "") === 1:0

# string backward search with a zero-char string
for i = 1:lastindex(astr)
Expand All @@ -256,7 +256,7 @@ end
for i = 1:lastindex(u8str)
@test findprev("", u8str, i) == i:i-1
end
@test findlast("", "") == 1:0
@test findlast("", "") === 1:0

# string forward search with a zero-char regex
for i = 1:lastindex(astr)
Expand Down Expand Up @@ -384,7 +384,7 @@ s_18109 = "fooα🐨βcd3"
@testset "findall" begin
@test findall("fooo", "foo") == UnitRange{Int}[]
@test findall("ing", "Spinning laughing dancing") == [6:8, 15:17, 23:25]
@test findall("", "foo") == [1:0, 2:1, 3:2, 4:3]
@test all(findall("", "foo") .=== [1:0, 2:1, 3:2, 4:3]) # use === to compare empty ranges
@test findall("αβ", "blαh blαβ blαββy") == findall("αβ", "blαh blαβ blαββy", overlap=true) == [9:11, 16:18]
@test findall("aa", "aaaaaa") == [1:2, 3:4, 5:6]
@test findall("aa", "aaaaaa", overlap=true) == [1:2, 2:3, 3:4, 4:5, 5:6]
Expand Down

0 comments on commit a6e27b3

Please sign in to comment.