From 327e92677c04a14a84b0405f21e33b8a7d65fe52 Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Tue, 31 Dec 2019 13:46:14 +0100 Subject: [PATCH 1/2] fix searchsorted corner case #34157 --- base/sort.jl | 12 ++++++++++-- test/sorting.jl | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/base/sort.jl b/base/sort.jl index 8d7bfba5a0093..4e92e6fd562e3 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -252,8 +252,12 @@ function searchsortedlast(a::AbstractRange{<:Integer}, x::Real, o::DirectOrderin require_one_based_indexing(a) if step(a) == 0 lt(o, x, first(a)) ? 0 : length(a) + elseif x < first(a) + 0 + elseif x >= last(a) + length(a) else - clamp( fld(floor(Integer, x) - first(a), step(a)) + 1, 0, length(a)) + fld(floor(Integer, x) - first(a), step(a)) + 1 end end @@ -261,8 +265,12 @@ function searchsortedfirst(a::AbstractRange{<:Integer}, x::Real, o::DirectOrderi require_one_based_indexing(a) if step(a) == 0 lt(o, first(a), x) ? length(a)+1 : 1 + elseif x <= first(a) + firstindex(a) + elseif x > last(a) + length(a) + 1 else - clamp(-fld(floor(Integer, -x) + first(a), step(a)) + 1, 1, length(a) + 1) + -fld(floor(Integer, -x) + first(a), step(a)) + 1 end end diff --git a/test/sorting.jl b/test/sorting.jl index 57c70f3105aa5..7abc8ba16d2ff 100644 --- a/test/sorting.jl +++ b/test/sorting.jl @@ -138,6 +138,26 @@ end @test searchsortedlast(500:1.0:600, -1.0e20) == 0 @test searchsortedlast(500:1.0:600, 1.0e20) == 101 end + + @testset "issue #34157" begin + @test searchsortedfirst(10:20, -Inf) == 1 + @test searchsortedfirst(10:20, Inf) == 12 + @test searchsortedlast(10:20, -Inf) == 0 + @test searchsortedlast(10:20, Inf) == 11 + + @test searchsortedfirst(2:2:4, Inf) == 3 + @test searchsortedfirst(2:2:4, -Inf) == 1 + @test searchsortedlast(2:2:4, Inf) == 2 + @test searchsortedlast(2:2:4, -Inf) == 0 + + @test searchsorted(1:2.0, -Inf) === 1:0 + @test searchsorted([1,2], -Inf) === 1:0 + @test searchsorted(1:2, -Inf) === 1:0 + + @test searchsorted(1:2.0, Inf) === 3:2 + @test searchsorted([1,2], Inf) === 3:2 + @test searchsorted(1:2, Inf) === 3:2 + end end # exercise the codepath in searchsorted* methods for ranges that check for zero step range struct ConstantRange{T} <: AbstractRange{T} From 18d87e14a6c0db8b4a31fd9c8e1e24986e8206f0 Mon Sep 17 00:00:00 2001 From: Jan Weidner Date: Wed, 1 Jan 2020 08:05:43 +0100 Subject: [PATCH 2/2] fix --- base/sort.jl | 32 +++++++++++++++++++++----------- test/sorting.jl | 38 +++++++++++++++++++++++++++----------- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/base/sort.jl b/base/sort.jl index 4e92e6fd562e3..6400b722c9829 100644 --- a/base/sort.jl +++ b/base/sort.jl @@ -250,27 +250,37 @@ end function searchsortedlast(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering) require_one_based_indexing(a) - if step(a) == 0 + h = step(a) + if h == 0 lt(o, x, first(a)) ? 0 : length(a) - elseif x < first(a) - 0 - elseif x >= last(a) - length(a) + elseif h > 0 && x < first(a) + firstindex(a) - 1 + elseif h > 0 && x >= last(a) + lastindex(a) + elseif h < 0 && x > first(a) + firstindex(a) - 1 + elseif h < 0 && x <= last(a) + lastindex(a) else - fld(floor(Integer, x) - first(a), step(a)) + 1 + fld(floor(Integer, x) - first(a), h) + 1 end end function searchsortedfirst(a::AbstractRange{<:Integer}, x::Real, o::DirectOrdering) require_one_based_indexing(a) - if step(a) == 0 + h = step(a) + if h == 0 lt(o, first(a), x) ? length(a)+1 : 1 - elseif x <= first(a) + elseif h > 0 && x <= first(a) + firstindex(a) + elseif h > 0 && x > last(a) + lastindex(a) + 1 + elseif h < 0 && x >= first(a) firstindex(a) - elseif x > last(a) - length(a) + 1 + elseif h < 0 && x < last(a) + lastindex(a) + 1 else - -fld(floor(Integer, -x) + first(a), step(a)) + 1 + -fld(floor(Integer, -x) + first(a), h) + 1 end end diff --git a/test/sorting.jl b/test/sorting.jl index 7abc8ba16d2ff..4559deddd3fd0 100644 --- a/test/sorting.jl +++ b/test/sorting.jl @@ -138,18 +138,7 @@ end @test searchsortedlast(500:1.0:600, -1.0e20) == 0 @test searchsortedlast(500:1.0:600, 1.0e20) == 101 end - @testset "issue #34157" begin - @test searchsortedfirst(10:20, -Inf) == 1 - @test searchsortedfirst(10:20, Inf) == 12 - @test searchsortedlast(10:20, -Inf) == 0 - @test searchsortedlast(10:20, Inf) == 11 - - @test searchsortedfirst(2:2:4, Inf) == 3 - @test searchsortedfirst(2:2:4, -Inf) == 1 - @test searchsortedlast(2:2:4, Inf) == 2 - @test searchsortedlast(2:2:4, -Inf) == 0 - @test searchsorted(1:2.0, -Inf) === 1:0 @test searchsorted([1,2], -Inf) === 1:0 @test searchsorted(1:2, -Inf) === 1:0 @@ -157,6 +146,33 @@ end @test searchsorted(1:2.0, Inf) === 3:2 @test searchsorted([1,2], Inf) === 3:2 @test searchsorted(1:2, Inf) === 3:2 + + for coll in [ + Base.OneTo(10), + 1:2, + -4:6, + 5:2:10, + [1,2], + 1.0:4, + [10.0,20.0], + ] + for huge in [Inf, 1e300] + @test searchsortedfirst(coll, huge) === lastindex(coll) + 1 + @test searchsortedfirst(coll, -huge)=== firstindex(coll) + @test searchsortedlast(coll, huge) === lastindex(coll) + @test searchsortedlast(coll, -huge) === firstindex(coll) - 1 + @test searchsorted(coll, huge) === lastindex(coll)+1 : lastindex(coll) + @test searchsorted(coll, -huge) === firstindex(coll) : firstindex(coll) - 1 + + @test searchsortedfirst(reverse(coll), huge, rev=true) === firstindex(coll) + @test searchsortedfirst(reverse(coll), -huge, rev=true) === lastindex(coll) + 1 + @test searchsortedlast(reverse(coll), huge, rev=true) === firstindex(coll) - 1 + @test searchsortedlast(reverse(coll), -huge, rev=true) === lastindex(coll) + @test searchsorted(reverse(coll), huge, rev=true) === firstindex(coll):firstindex(coll) - 1 + @test searchsorted(reverse(coll), -huge, rev=true) === lastindex(coll)+1:lastindex(coll) + + end + end end end # exercise the codepath in searchsorted* methods for ranges that check for zero step range