Skip to content

Commit

Permalink
Move searchsorted* functions to SortedSearch stdlib module
Browse files Browse the repository at this point in the history
Keep them under Base.Sorted but unexported, since they are used
in a few places in Base, in particular for sparse vectors and matrices.
  • Loading branch information
nalimilan committed Dec 16, 2017
1 parent f5dab58 commit 2e99780
Show file tree
Hide file tree
Showing 19 changed files with 146 additions and 107 deletions.
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

0 comments on commit 2e99780

Please sign in to comment.