Skip to content

Commit 40d4f4a

Browse files
committed
searchsorted ranges: simplify code, fix bug with Unsigned needle
This avoids computing `length` unnecessarily, which often requires a division, and is therefore often expensive.
1 parent 454fc51 commit 40d4f4a

File tree

2 files changed

+54
-73
lines changed

2 files changed

+54
-73
lines changed

base/sort.jl

Lines changed: 26 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -231,92 +231,62 @@ end
231231

232232
function searchsortedlast(a::AbstractRange{<:Real}, x::Real, o::DirectOrdering)::keytype(a)
233233
require_one_based_indexing(a)
234-
if step(a) == 0
235-
lt(o, x, first(a)) ? 0 : length(a)
234+
f, h, l = first(a), step(a), last(a)
235+
if lt(o, x, f)
236+
0
237+
elseif h == 0 || !lt(o, x, l)
238+
length(a)
236239
else
237-
n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a)))
240+
n = round(Integer, (x - f) / h + 1)
238241
lt(o, x, a[n]) ? n - 1 : n
239242
end
240243
end
241244

242245
function searchsortedfirst(a::AbstractRange{<:Real}, x::Real, o::DirectOrdering)::keytype(a)
243246
require_one_based_indexing(a)
244-
if step(a) == 0
245-
lt(o, first(a), x) ? length(a) + 1 : 1
247+
f, h, l = first(a), step(a), last(a)
248+
if !lt(o, f, x)
249+
1
250+
elseif h == 0 || lt(o, l, x)
251+
length(a) + 1
246252
else
247-
n = round(Integer, clamp((x - first(a)) / step(a) + 1, 1, length(a)))
253+
n = round(Integer, (x - f) / h + 1)
248254
lt(o, a[n], x) ? n + 1 : n
249255
end
250256
end
251257

252258
function searchsortedlast(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering)::keytype(a)
253259
require_one_based_indexing(a)
254-
h = step(a)
255-
if h == 0
256-
lt(o, x, first(a)) ? 0 : length(a)
257-
elseif h > 0 && x < first(a)
258-
firstindex(a) - 1
259-
elseif h > 0 && x >= last(a)
260-
lastindex(a)
261-
elseif h < 0 && x > first(a)
262-
firstindex(a) - 1
263-
elseif h < 0 && x <= last(a)
264-
lastindex(a)
260+
f, h, l = first(a), step(a), last(a)
261+
if lt(o, x, f)
262+
0
263+
elseif h == 0 || !lt(o, x, l)
264+
length(a)
265265
else
266266
if o isa ForwardOrdering
267-
fld(floor(Integer, x) - first(a), h) + 1
267+
fld(floor(Integer, x) - f, h) + 1
268268
else
269-
fld(ceil(Integer, x) - first(a), h) + 1
269+
fld(ceil(Integer, x) - f, h) + 1
270270
end
271271
end
272272
end
273273

274274
function searchsortedfirst(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering)::keytype(a)
275275
require_one_based_indexing(a)
276-
h = step(a)
277-
if h == 0
278-
lt(o, first(a), x) ? length(a)+1 : 1
279-
elseif h > 0 && x <= first(a)
280-
firstindex(a)
281-
elseif h > 0 && x > last(a)
282-
lastindex(a) + 1
283-
elseif h < 0 && x >= first(a)
284-
firstindex(a)
285-
elseif h < 0 && x < last(a)
286-
lastindex(a) + 1
276+
f, h, l = first(a), step(a), last(a)
277+
if !lt(o, f, x)
278+
1
279+
elseif h == 0 || lt(o, l, x)
280+
length(a) + 1
287281
else
288282
if o isa ForwardOrdering
289-
-fld(floor(Integer, -x) + Signed(first(a)), h) + 1
283+
cld(ceil(Integer, x) - f, h) + 1
290284
else
291-
-fld(ceil(Integer, -x) + Signed(first(a)), h) + 1
285+
cld(floor(Integer, x) - f, h) + 1
292286
end
293287
end
294288
end
295289

296-
function searchsortedfirst(a::AbstractRange{<:Integer}, x::Unsigned, o::DirectOrdering)::keytype(a)
297-
require_one_based_indexing(a)
298-
if lt(o, first(a), x)
299-
if step(a) == 0
300-
length(a) + 1
301-
else
302-
min(cld(x - first(a), step(a)), length(a)) + 1
303-
end
304-
else
305-
1
306-
end
307-
end
308-
309-
function searchsortedlast(a::AbstractRange{<:Integer}, x::Unsigned, o::DirectOrdering)::keytype(a)
310-
require_one_based_indexing(a)
311-
if lt(o, x, first(a))
312-
0
313-
elseif step(a) == 0
314-
length(a)
315-
else
316-
min(fld(x - first(a), step(a)) + 1, length(a))
317-
end
318-
end
319-
320290
searchsorted(a::AbstractRange{<:Real}, x::Real, o::DirectOrdering) =
321291
searchsortedfirst(a, x, o) : searchsortedlast(a, x, o)
322292

test/sorting.jl

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ end
105105
@test searchsorted(fill(R(1), 15), T(1), 6, 10, Forward) == 6:10
106106
end
107107

108-
for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
108+
for (rg,I) in Any[(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
109109
rg_r = reverse(rg)
110110
rgv, rgv_r = [rg;], [rg_r;]
111111
for i = I
@@ -144,7 +144,7 @@ end
144144

145145
@testset "issue 32568" begin
146146
for R in numTypes, T in numTypes
147-
for arr in [R[1:5;], R(1):R(5), R(1):2:R(5)]
147+
for arr in Any[R[1:5;], R(1):R(5), R(1):2:R(5)]
148148
@test eltype(searchsorted(arr, T(2))) == keytype(arr)
149149
@test eltype(searchsorted(arr, T(2), big(1), big(4), Forward)) == keytype(arr)
150150
@test searchsortedfirst(arr, T(2)) isa keytype(arr)
@@ -164,35 +164,46 @@ end
164164
@test searchsorted([1,2], Inf) === 3:2
165165
@test searchsorted(1:2, Inf) === 3:2
166166

167-
for coll in [
167+
for coll in Any[
168168
Base.OneTo(10),
169169
1:2,
170+
0x01:0x02,
170171
-4:6,
171172
5:2:10,
172173
[1,2],
173174
1.0:4,
174175
[10.0,20.0],
175176
]
176-
for huge in [Inf, 1e300]
177+
for huge in Any[Inf, 1e300, typemax(Int64), typemax(UInt64)]
177178
@test searchsortedfirst(coll, huge) === lastindex(coll) + 1
178-
@test searchsortedfirst(coll, -huge)=== firstindex(coll)
179179
@test searchsortedlast(coll, huge) === lastindex(coll)
180-
@test searchsortedlast(coll, -huge) === firstindex(coll) - 1
181180
@test searchsorted(coll, huge) === lastindex(coll)+1 : lastindex(coll)
182-
@test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1
183-
184-
@test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll)
185-
@test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1
186-
@test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1
187-
@test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll)
188-
@test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1
189-
@test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll)
181+
if !(eltype(coll) <: Unsigned)
182+
@test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll)
183+
@test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1
184+
@test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1
185+
end
186+
187+
if !(huge isa Unsigned)
188+
@test searchsortedfirst(coll, -huge)=== firstindex(coll)
189+
@test searchsortedlast(coll, -huge) === firstindex(coll) - 1
190+
@test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1
191+
if !(eltype(coll) <: Unsigned)
192+
@test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1
193+
@test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll)
194+
@test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll)
195+
end
196+
end
190197
end
191198
end
192-
@testset "issue ##34408" begin
199+
200+
@test_broken length(reverse(0x1:0x2)) == 2
201+
@testset "issue #34408" begin
193202
r = 1f8-10:1f8
194203
# collect(r) = Float32[9.999999e7, 9.999999e7, 9.999999e7, 9.999999e7, 1.0e8, 1.0e8, 1.0e8, 1.0e8, 1.0e8]
195-
@test_broken searchsorted(collect(r)) == searchsorted(r)
204+
for i in r
205+
@test_broken searchsorted(collect(r), i) == searchsorted(r, i)
206+
end
196207
end
197208
end
198209
@testset "issue #35272" begin
@@ -329,7 +340,7 @@ end
329340
@test insorted(T(10), R.(collect(1:10)), by=(>=(5)))
330341
end
331342

332-
for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
343+
for (rg,I) in Any[(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
333344
rg_r = reverse(rg)
334345
rgv, rgv_r = collect(rg), collect(rg_r)
335346
for i = I

0 commit comments

Comments
 (0)