Skip to content

Commit a6e27b3

Browse files
authored
Make empty ranges compare equal (#32348)
1 parent 6418be9 commit a6e27b3

File tree

11 files changed

+56
-46
lines changed

11 files changed

+56
-46
lines changed

NEWS.md

+1
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ New library features
153153

154154
Standard library changes
155155
------------------------
156+
* Empty ranges now compare equal, regardless of their startpoint and step ([#32348]).
156157
* 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]).
157158
* The `@timed` macro now returns a `NamedTuple` ([#34149])
158159
* New `supertypes(T)` function returns a tuple of all supertypes of `T` ([#34419]).

base/range.jl

+6-4
Original file line numberDiff line numberDiff line change
@@ -743,18 +743,20 @@ show(io::IO, r::UnitRange) = print(io, repr(first(r)), ':', repr(last(r)))
743743
show(io::IO, r::OneTo) = print(io, "Base.OneTo(", r.stop, ")")
744744

745745
==(r::T, s::T) where {T<:AbstractRange} =
746-
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
746+
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))
747747
==(r::OrdinalRange, s::OrdinalRange) =
748-
(first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s))
748+
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))
749749
==(r::T, s::T) where {T<:Union{StepRangeLen,LinRange}} =
750-
(first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s))
750+
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (length(r) == length(s)) & (last(r) == last(s)))
751751
==(r::Union{StepRange{T},StepRangeLen{T,T}}, s::Union{StepRange{T},StepRangeLen{T,T}}) where {T} =
752-
(first(r) == first(s)) & (last(r) == last(s)) & (step(r) == step(s))
752+
(isempty(r) & isempty(s)) | ((first(r) == first(s)) & (step(r) == step(s)) & (last(r) == last(s)))
753753

754754
function ==(r::AbstractRange, s::AbstractRange)
755755
lr = length(r)
756756
if lr != length(s)
757757
return false
758+
elseif iszero(lr)
759+
return true
758760
end
759761
yr, ys = iterate(r), iterate(s)
760762
while yr !== nothing

base/strings/util.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,8 @@ end
392392
function _split(str::AbstractString, splitter, limit::Integer, keepempty::Bool, strs::Array)
393393
i = 1 # firstindex(str)
394394
n = lastindex(str)
395-
r = something(findfirst(splitter,str), 0)
396-
if r != 0:-1
395+
r = findfirst(splitter,str)
396+
if !isnothing(r)
397397
j, k = first(r), nextind(str,last(r))
398398
while 0 < j <= n && length(strs) != limit-1
399399
if i < k
@@ -403,8 +403,8 @@ function _split(str::AbstractString, splitter, limit::Integer, keepempty::Bool,
403403
i = k
404404
end
405405
(k <= j) && (k = nextind(str,j))
406-
r = something(findnext(splitter,str,k), 0)
407-
r == 0:-1 && break
406+
r = findnext(splitter,str,k)
407+
isnothing(r) && break
408408
j, k = first(r), nextind(str,last(r))
409409
end
410410
end

stdlib/Dates/test/ranges.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ let
3535
@test first(reverse(dr)) < f1
3636
@test last(reverse(dr)) >= f1
3737
@test issorted(dr)
38-
@test sortperm(dr) == 1:1:0
38+
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
3939
@test !(f1 in dr)
4040
@test !(l1 in dr)
4141
@test !(f1 - pos_step in dr)
@@ -93,7 +93,7 @@ let
9393
@test first(reverse(dr)) > l1
9494
@test last(reverse(dr)) <= l1
9595
@test issorted(dr)
96-
@test sortperm(dr) == 1:1:0
96+
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
9797
@test !(l1 in dr)
9898
@test !(l1 in dr)
9999
@test !(l1 - neg_step in dr)
@@ -153,7 +153,7 @@ let
153153
@test first(reverse(dr)) < f1
154154
@test last(reverse(dr)) >= f1
155155
@test issorted(dr)
156-
@test sortperm(dr) == 1:1:0
156+
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
157157
@test !(f1 in dr)
158158
@test !(l1 in dr)
159159
@test !(f1 - pos_step in dr)
@@ -211,7 +211,7 @@ let
211211
@test first(reverse(dr)) > l1
212212
@test last(reverse(dr)) <= l1
213213
@test issorted(dr)
214-
@test sortperm(dr) == 1:1:0
214+
@test sortperm(dr) === StepRange{Int64,Int}(1:1:0)
215215
@test !(l1 in dr)
216216
@test !(l1 in dr)
217217
@test !(l1 - neg_step in dr)

stdlib/REPL/test/replcompletions.jl

+10-5
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ end
132132
let s = "Main.CompletionFoo."
133133
c, r = test_complete(s)
134134
@test "bar" in c
135-
@test r == 20:19
135+
@test r === UnitRange{Int64}(20:19)
136136
@test s[r] == ""
137137
end
138138

@@ -592,7 +592,12 @@ end
592592

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

597602
if Sys.isunix()
598603
let s, c, r
@@ -640,7 +645,7 @@ let s, c, r
640645
s = "/tmp/"
641646
c,r = test_scomplete(s)
642647
@test !("tmp/" in c)
643-
@test r == 6:5
648+
@test r === UnitRange{Int64}(6:5)
644649
@test s[r] == ""
645650
end
646651

@@ -657,7 +662,7 @@ let s, c, r
657662
file = joinpath(path, "repl completions")
658663
s = "/tmp "
659664
c,r = test_scomplete(s)
660-
@test r == 6:5
665+
@test r === UnitRange{Int64}(6:5)
661666
end
662667

663668
# Test completing paths with an escaped trailing space
@@ -971,7 +976,7 @@ end
971976
let s = ""
972977
c, r = test_complete_context(s)
973978
@test "bar" in c
974-
@test r == 1:0
979+
@test r === UnitRange{Int64}(1:0)
975980
@test s[r] == ""
976981
end
977982

test/core.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -6796,7 +6796,7 @@ function f27597(y)
67966796
return y
67976797
end
67986798
@test f27597([1]) == [1]
6799-
@test f27597([]) == 1:0
6799+
@test f27597([]) === 1:0
68006800

68016801
# issue #22291
68026802
wrap22291(ind) = (ind...,)

test/offsetarray.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ v = OffsetArray(rand(8), (-2,))
502502
@test sort(A, dims=2) == OffsetArray(sort(parent(A), dims=2), A.offsets)
503503
# Issue #33977
504504
soa = OffsetArray([2,2,3], -2)
505-
@test searchsorted(soa, 1) == -1:-2
505+
@test searchsorted(soa, 1) === -1:-2
506506
@test searchsortedfirst(soa, 1) == -1
507507
@test searchsortedlast(soa, 1) == -2
508508
@test first(sort!(soa; alg=QuickSort)) == 2

test/ranges.jl

+7-5
Original file line numberDiff line numberDiff line change
@@ -459,10 +459,10 @@ end
459459
end
460460
end
461461
@testset "indexing range with empty range (#4309)" begin
462-
@test (3:6)[5:4] == 7:6
462+
@test (3:6)[5:4] === 7:6
463463
@test_throws BoundsError (3:6)[5:5]
464464
@test_throws BoundsError (3:6)[5]
465-
@test (0:2:10)[7:6] == 12:2:10
465+
@test (0:2:10)[7:6] === 12:2:10
466466
@test_throws BoundsError (0:2:10)[7:7]
467467
end
468468
# indexing with negative ranges (#8351)
@@ -818,7 +818,8 @@ end
818818
map(Int32,1:3:17), map(Int64,1:3:17), 1:0, 1:-1:0, 17:-3:0,
819819
0.0:0.1:1.0, map(Float32,0.0:0.1:1.0),map(Float32,LinRange(0.0, 1.0, 11)),
820820
1.0:eps():1.0 .+ 10eps(), 9007199254740990.:1.0:9007199254740994,
821-
range(0, stop=1, length=20), map(Float32, range(0, stop=1, length=20))]
821+
range(0, stop=1, length=20), map(Float32, range(0, stop=1, length=20)),
822+
3:2, 5:-2:7, range(0.0, step=2.0, length=0), 3//2:3//2:0//1, LinRange(2,3,0)]
822823
for r in Rs
823824
local r
824825
ar = Vector(r)
@@ -838,6 +839,7 @@ end
838839
@test 1:1:10 == 1:10 == 1:10 == Base.OneTo(10) == Base.OneTo(10)
839840
@test 1:10 != 2:10 != 2:11 != Base.OneTo(11)
840841
@test Base.OneTo(10) != Base.OneTo(11) != 1:10
842+
@test Base.OneTo(0) == 5:4
841843
end
842844
# issue #2959
843845
@test 1.0:1.5 == 1.0:1.0:1.5 == 1.0:1.0
@@ -1555,11 +1557,11 @@ end
15551557
for stops in [-2, 0, 2, 100]
15561558
for lengths in [2, 10, 100]
15571559
if stops >= starts
1558-
@test range(starts, stops, length=lengths) == range(starts, stop=stops, length=lengths)
1560+
@test range(starts, stops, length=lengths) === range(starts, stop=stops, length=lengths)
15591561
end
15601562
end
15611563
for steps in [0.01, 1, 2]
1562-
@test range(starts, stops, step=steps) == range(starts, stop=stops, step=steps)
1564+
@test range(starts, stops, step=steps) === range(starts, stop=stops, step=steps)
15631565
end
15641566
end
15651567
end

test/regex.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@
5555
# findall
5656
@test findall(r"\w+", "foo bar") == [1:3, 5:7]
5757
@test findall(r"\w+", "foo bar", overlap=true) == [1:3, 2:3, 3:3, 5:7, 6:7, 7:7]
58-
@test findall(r"\w*", "foo bar") == [1:3, 4:3, 5:7, 8:7]
59-
@test findall(r"\b", "foo bar") == [1:0, 4:3, 5:4, 8:7]
58+
@test all(findall(r"\w*", "foo bar") .=== [1:3, 4:3, 5:7, 8:7]) # use === to compare empty ranges
59+
@test all(findall(r"\b", "foo bar") .=== [1:0, 4:3, 5:4, 8:7]) # use === to compare empty ranges
6060

6161
# count
6262
@test count(r"\w+", "foo bar") == 2

test/sorting.jl

+17-17
Original file line numberDiff line numberDiff line change
@@ -88,16 +88,16 @@ end
8888
@test searchsorted(fill(1, 15), 1, 6, 10, Forward) == 6:10
8989

9090
for R in numTypes, T in numTypes
91-
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(0)) == 1:0
91+
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(0)) === 1:0
9292
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(1)) == 1:2
9393
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(2)) == 3:4
94-
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(4)) == 7:6
95-
@test searchsorted(R[1, 1, 2, 2, 3, 3], 2.5) == 5:4
94+
@test searchsorted(R[1, 1, 2, 2, 3, 3], T(4)) === 7:6
95+
@test searchsorted(R[1, 1, 2, 2, 3, 3], 2.5) === 5:4
9696

97-
@test searchsorted(1:3, T(0)) == 1:0
97+
@test searchsorted(1:3, T(0)) === 1:0
9898
@test searchsorted(1:3, T(1)) == 1:1
9999
@test searchsorted(1:3, T(2)) == 2:2
100-
@test searchsorted(1:3, T(4)) == 4:3
100+
@test searchsorted(1:3, T(4)) === 4:3
101101

102102
@test searchsorted(R[1:10;], T(1), by=(x -> x >= 5)) == 1:4
103103
@test searchsorted(R[1:10;], T(10), by=(x -> x >= 5)) == 5:10
@@ -109,31 +109,31 @@ end
109109
rg_r = reverse(rg)
110110
rgv, rgv_r = [rg;], [rg_r;]
111111
for i = I
112-
@test searchsorted(rg,i) == searchsorted(rgv,i)
113-
@test searchsorted(rg_r,i,rev=true) == searchsorted(rgv_r,i,rev=true)
112+
@test searchsorted(rg,i) === searchsorted(rgv,i)
113+
@test searchsorted(rg_r,i,rev=true) === searchsorted(rgv_r,i,rev=true)
114114
end
115115
end
116116

117117
rg = 0.0:0.01:1.0
118118
for i = 2:101
119119
@test searchsorted(rg, rg[i]) == i:i
120-
@test searchsorted(rg, prevfloat(rg[i])) == i:i-1
121-
@test searchsorted(rg, nextfloat(rg[i])) == i+1:i
120+
@test searchsorted(rg, prevfloat(rg[i])) === i:i-1
121+
@test searchsorted(rg, nextfloat(rg[i])) === i+1:i
122122
end
123123

124124
rg_r = reverse(rg)
125125
for i = 1:100
126126
@test searchsorted(rg_r, rg_r[i], rev=true) == i:i
127-
@test searchsorted(rg_r, prevfloat(rg_r[i]), rev=true) == i+1:i
128-
@test searchsorted(rg_r, nextfloat(rg_r[i]), rev=true) == i:i-1
127+
@test searchsorted(rg_r, prevfloat(rg_r[i]), rev=true) === i+1:i
128+
@test searchsorted(rg_r, nextfloat(rg_r[i]), rev=true) === i:i-1
129129
end
130130

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

134-
@test searchsorted([], 0) == 1:0
135-
@test searchsorted([1,2,3], 0) == 1:0
136-
@test searchsorted([1,2,3], 4) == 4:3
134+
@test searchsorted([], 0) === 1:0
135+
@test searchsorted([1,2,3], 0) === 1:0
136+
@test searchsorted([1,2,3], 4) === 4:3
137137

138138
@testset "issue 8866" begin
139139
@test searchsortedfirst(500:1.0:600, -1.0e20) == 1
@@ -194,11 +194,11 @@ end
194194
for v0 = (3:-1:1, 3.0:-1.0:1.0), v = (v0, collect(v0))
195195
@test searchsorted(v, 3, rev=true) == 1:1
196196
@test searchsorted(v, 3.0, rev=true) == 1:1
197-
@test searchsorted(v, 2.5, rev=true) == 2:1
197+
@test searchsorted(v, 2.5, rev=true) === 2:1
198198
@test searchsorted(v, 2, rev=true) == 2:2
199-
@test searchsorted(v, 1.2, rev=true) == 3:2
199+
@test searchsorted(v, 1.2, rev=true) === 3:2
200200
@test searchsorted(v, 1, rev=true) == 3:3
201-
@test searchsorted(v, 0.1, rev=true) == 4:3
201+
@test searchsorted(v, 0.1, rev=true) === 4:3
202202
end
203203
end
204204
end

test/strings/search.jl

+3-3
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ end
247247
for i = 1:lastindex(u8str)
248248
@test findnext("", u8str, i) == i:i-1
249249
end
250-
@test findfirst("", "") == 1:0
250+
@test findfirst("", "") === 1:0
251251

252252
# string backward search with a zero-char string
253253
for i = 1:lastindex(astr)
@@ -256,7 +256,7 @@ end
256256
for i = 1:lastindex(u8str)
257257
@test findprev("", u8str, i) == i:i-1
258258
end
259-
@test findlast("", "") == 1:0
259+
@test findlast("", "") === 1:0
260260

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

0 commit comments

Comments
 (0)