Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move searchsorted* functions to SortedSearch stdlib module #25133

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3411,6 +3411,10 @@ end
# PR #25113
@deprecate_binding CartesianRange CartesianIndices

@deprecate_moved searchsorted "SortedSearch"
@deprecate_moved searchsortedfirst "SortedSearch"
@deprecate_moved searchsortedlast "SortedSearch"

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
3 changes: 0 additions & 3 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,6 @@ export
rot180,
rotl90,
rotr90,
searchsorted,
searchsortedfirst,
searchsortedlast,
shuffle,
shuffle!,
size,
Expand Down
2 changes: 1 addition & 1 deletion base/linalg/svd.jl
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ svdvals(S::SVD{<:Any,T}) where {T} = (S[:S])::Vector{T}

# SVD least squares
function ldiv!(A::SVD{T}, B::StridedVecOrMat) where T
k = searchsortedlast(A.S, eps(real(T))*A.S[1], rev=true)
k = Base.Sort.searchsortedlast(A.S, eps(real(T))*A.S[1], rev=true)
view(A.Vt,1:k,:)' * (view(A.S,1:k) .\ (view(A.U,:,1:k)' * B))
end

Expand Down
2 changes: 1 addition & 1 deletion base/repl/REPLCompletions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ const sorted_keywords = [
"true", "try", "using", "while"]

function complete_keyword(s::Union{String,SubString{String}})
r = searchsorted(sorted_keywords, s)
r = Base.Sort.searchsorted(sorted_keywords, s)
i = first(r)
n = length(sorted_keywords)
while i <= n && startswith(sorted_keywords[i],s)
Expand Down
9 changes: 6 additions & 3 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ import
export # also exported by Base
# order-only:
issorted,
searchsorted,
searchsortedfirst,
searchsortedlast,
# order & algorithm:
sort,
sort!,
Expand Down Expand Up @@ -287,6 +284,8 @@ if `a` does not contain values equal to `x`.

# Examples
```jldoctest
julia> using SortedSearch

julia> a = [4, 3, 2, 1]
4-element Array{Int64,1}:
4
Expand All @@ -311,6 +310,8 @@ specified order. Return `length(a) + 1` if `x` is greater than all values in `a`

# Examples
```jldoctest
julia> using SortedSearch

julia> searchsortedfirst([1, 2, 4, 5, 14], 4)
3

Expand All @@ -331,6 +332,8 @@ be sorted.

# Examples
```jldoctest
julia> using SortedSearch

julia> searchsortedlast([1, 2, 4, 5, 14], 4)
3

Expand Down
2 changes: 2 additions & 0 deletions base/sparse/sparsematrix.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

using Base.Sort: searchsortedfirst, searchsortedlast

# Compressed sparse columns data structure
# Assumes that no zeros are stored in the data structure
# Assumes that row values in rowval for each column are sorted
Expand Down
1 change: 1 addition & 0 deletions base/sysimg.jl
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,7 @@ Base.require(:SuiteSparse)
Base.require(:Test)
Base.require(:Unicode)
Base.require(:Distributed)
Base.require(:SortedSearch)

@eval Base begin
@deprecate_binding Test root_module(:Test) true ", run `using Test` instead"
Expand Down
2 changes: 1 addition & 1 deletion base/version.jl
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ function check_new_version(existing::Vector{VersionNumber}, ver::VersionNumber)
end
error("$ver is not a valid initial version (try 0.0.0, 0.0.1, 0.1 or 1.0)")
end
idx = searchsortedlast(existing, ver)
idx = Base.Sort.searchsortedlast(existing, ver)
prv = existing[idx]
ver == prv && error("version $ver already exists")
nxt = thismajor(ver) != thismajor(prv) ? nextmajor(prv) :
Expand Down
8 changes: 6 additions & 2 deletions doc/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ if Sys.iswindows()
cp_q("../stdlib/IterativeEigensolvers/docs/src/index.md", "src/stdlib/iterativeeigensolvers.md")
cp_q("../stdlib/Unicode/docs/src/index.md", "src/stdlib/unicode.md")
cp_q("../stdlib/Distributed/docs/src/index.md", "src/stdlib/distributed.md")
cp_q("../stdlib/SortedSearch/docs/src/index.md", "src/stdlib/sortedsearch.md")
else
symlink_q("../../../stdlib/DelimitedFiles/docs/src/index.md", "src/stdlib/delimitedfiles.md")
symlink_q("../../../stdlib/Test/docs/src/index.md", "src/stdlib/test.md")
Expand All @@ -46,6 +47,7 @@ else
symlink_q("../../../stdlib/IterativeEigensolvers/docs/src/index.md", "src/stdlib/iterativeeigensolvers.md")
symlink_q("../../../stdlib/Unicode/docs/src/index.md", "src/stdlib/unicode.md")
symlink_q("../../../stdlib/Distributed/docs/src/index.md", "src/stdlib/distributed.md")
symlink_q("../../../stdlib/SortedSearch/docs/src/index.md", "src/stdlib/sortedsearch.md")
end

const PAGES = [
Expand Down Expand Up @@ -125,6 +127,7 @@ const PAGES = [
"stdlib/crc32c.md",
"stdlib/iterativeeigensolvers.md",
"stdlib/unicode.md",
"stdlib/sortedsearch.md",
],
"Developer Documentation" => [
"devdocs/reflection.md",
Expand Down Expand Up @@ -160,12 +163,13 @@ const PAGES = [
]

using DelimitedFiles, Test, Mmap, SharedArrays, Profile, Base64, FileWatching, CRC32c,
Dates, IterativeEigensolvers, Unicode, Distributed
Dates, IterativeEigensolvers, Unicode, Distributed, SortedSearch

makedocs(
build = joinpath(pwd(), "_build/html/en"),
modules = [Base, Core, BuildSysImg, DelimitedFiles, Test, Mmap, SharedArrays, Profile,
Base64, FileWatching, Dates, IterativeEigensolvers, Unicode, Distributed],
Base64, FileWatching, Dates, IterativeEigensolvers, Unicode, Distributed,
SortedSearch],
clean = false,
doctest = "doctest" in ARGS,
linkcheck = "linkcheck" in ARGS,
Expand Down
1 change: 1 addition & 0 deletions doc/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
* [File Events](@ref lib-filewatching)
* [Iterative Eigensolvers](@ref lib-itereigen)
* [Unicode](@ref)
* [SortedSearch](@ref)

## Developer Documentation

Expand Down
5 changes: 4 additions & 1 deletion doc/src/manual/arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,10 +273,13 @@ julia> x[1, [2 3; 4 1]]
```

Empty ranges of the form `n:n-1` are sometimes used to indicate the inter-index location between
`n-1` and `n`. For example, the [`searchsorted`](@ref) function uses this convention to indicate
`n-1` and `n`. For example, the [`searchsorted`](@ref) function from the standard library
module `SortedSearch` uses this convention to indicate
the insertion point of a value not found in a sorted array:

```jldoctest
julia> using SortedSearch

julia> a = [1,2,5,6,7];

julia> searchsorted(a, 3)
Expand Down
1 change: 1 addition & 0 deletions doc/src/stdlib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ filewatching.md
crc32c.md
dates.md
unicode.md
sortedsearch.md
3 changes: 0 additions & 3 deletions doc/src/stdlib/sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,6 @@ Base.Sort.sortcols

```@docs
Base.issorted
Base.Sort.searchsorted
Base.Sort.searchsortedfirst
Base.Sort.searchsortedlast
Base.Sort.partialsort!
Base.Sort.partialsort
Base.Sort.partialsortperm
Expand Down
7 changes: 7 additions & 0 deletions stdlib/SortedSearch/docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# SortedSearch

```@docs
SortedSearch.searchsorted
SortedSearch.searchsortedfirst
SortedSearch.searchsortedlast
```
11 changes: 11 additions & 0 deletions stdlib/SortedSearch/src/SortedSearch.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

__precompile__(true)

module SortedSearch

using Base.Sort: searchsorted, searchsortedfirst, searchsortedlast

export searchsorted, searchsortedfirst, searchsortedlast

end
97 changes: 97 additions & 0 deletions stdlib/SortedSearch/test/runtests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

using SortedSearch
using Base.Order: Forward

@testset "searchsorted" begin
numTypes = [ Int8, Int16, Int32, Int64, Int128,
UInt8, UInt16, UInt32, UInt64, UInt128,
Float16, Float32, Float64, BigInt, BigFloat]

@test searchsorted([1:10;], 1, by=(x -> x >= 5)) == 1:4
@test searchsorted([1:10;], 10, by=(x -> x >= 5)) == 5:10
@test searchsorted([1:5; 1:5; 1:5], 1, 6, 10, Forward) == 6:6
@test searchsorted(ones(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(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(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(R[1:10;], T(1), by=(x -> x >= 5)) == 1:4
@test searchsorted(R[1:10;], T(10), by=(x -> x >= 5)) == 5:10
@test searchsorted(R[1:5; 1:5; 1:5], T(1), 6, 10, Forward) == 6:6
@test searchsorted(ones(R, 15), T(1), 6, 10, Forward) == 6:10
end

for (rg,I) in [(49:57,47:59), (1:2:17,-1:19), (-3:0.5:2,-5:.5:4)]
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)
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
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
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

@testset "issue 8866" begin
@test searchsortedfirst(500:1.0:600, -1.0e20) == 1
@test searchsortedfirst(500:1.0:600, 1.0e20) == 102
@test searchsortedlast(500:1.0:600, -1.0e20) == 0
@test searchsortedlast(500:1.0:600, 1.0e20) == 101
end
end

# exercise the codepath in searchsorted* methods for ranges that check for zero step range
struct ConstantRange{T} <: AbstractRange{T}
val::T
len::Int
end

Base.length(r::ConstantRange) = r.len
Base.getindex(r::ConstantRange, i::Int) = (1 <= i <= r.len || throw(BoundsError(r,i)); r.val)
Base.step(r::ConstantRange) = 0

@testset "searchsorted method with ranges which check for zero step range" begin
r = ConstantRange(1, 5)

@test searchsortedfirst(r, 1.0, Forward) == 1
@test searchsortedfirst(r, 1, Forward) == 1
@test searchsortedfirst(r, UInt(1), Forward) == 1

@test searchsortedlast(r, 1.0, Forward) == 5
@test searchsortedlast(r, 1, Forward) == 5
@test searchsortedlast(r, UInt(1), Forward) == 5
end

@testset "issue #19005" begin
@test searchsortedfirst(0:256, 0x80) == 129
@test searchsortedlast(0:256, 0x80) == 129
end
2 changes: 1 addition & 1 deletion stdlib/SuiteSparse/src/cholmod.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1259,7 +1259,7 @@ function getindex(A::Sparse{T}, i0::Integer, i1::Integer) where T
r1 = Int(unsafe_load(s.p, i1) + 1)
r2 = Int(unsafe_load(s.p, i1 + 1))
(r1 > r2) && return zero(T)
r1 = Int(searchsortedfirst(unsafe_wrap(Array, s.i, (s.nzmax,), false),
r1 = Int(Base.Sort.searchsortedfirst(unsafe_wrap(Array, s.i, (s.nzmax,), false),
i0 - 1, r1, r2, Base.Order.Forward))
((r1 > r2) || (unsafe_load(s.i, r1) + 1 != i0)) ? zero(T) : unsafe_load(s.x, r1)
end
Expand Down
2 changes: 1 addition & 1 deletion test/compile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ try
Dict(s => Base.module_uuid(Base.root_module(s)) for s in
[:Base64, :CRC32c, :Dates, :DelimitedFiles, :FileWatching,
:IterativeEigensolvers, :Logging, :Mmap, :Profile, :SharedArrays,
:SuiteSparse, :Test, :Unicode, :Distributed]))
:SuiteSparse, :Test, :Unicode, :Distributed, :SortedSearch]))
@test discard_module.(deps) == deps1

@test current_task()(0x01, 0x4000, 0x30031234) == 2
Expand Down
Loading