Skip to content

Commit

Permalink
require explicit predicates in find functions
Browse files Browse the repository at this point in the history
fix #23120, fix #19186
  • Loading branch information
JeffBezanson committed Sep 22, 2017
1 parent ff9fb48 commit f151e89
Show file tree
Hide file tree
Showing 24 changed files with 95 additions and 177 deletions.
6 changes: 6 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -468,6 +468,12 @@ Deprecated or removed
* The timing functions `tic`, `toc`, and `toq` are deprecated in favor of `@time` and `@elapsed`
([#17046]).

* Methods of `findfirst`, `findnext`, `findlast`, and `findprev` that accept a value to
search for are deprecated in favor of passing a predicate ([#19186], [#10593]).

* `find` functions now operate only on booleans by default. To look for non-zeros, use
`x->x!=0` or `!iszero` ([#23120]).

Command-line option changes
---------------------------

Expand Down
154 changes: 32 additions & 122 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1596,14 +1596,14 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
"""
findnext(A, i::Integer)
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
Find the next linear index >= `i` of a true element of `A`, or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 0]
2×2 Array{Int64,2}:
0 0
1 0
julia> A = [false false; true false]
2×2 Array{Bool,2}:
false false
true false
julia> findnext(A,1)
2
Expand All @@ -1615,8 +1615,14 @@ julia> findnext(A,3)
function findnext(A, start::Integer)
l = endof(A)
i = start
warned = false
while i <= l
if A[i] != 0
a = A[i]
if !warned && !(a isa Bool)
depwarn("In the future `findnext` will only work on boolean collections. Use `findnext(x->x!=0, A)` instead.", :findnext)
warned = true
end
if a != 0
return i
end
i = nextind(A, i)
Expand Down Expand Up @@ -1646,58 +1652,6 @@ julia> findfirst(zeros(3))
"""
findfirst(A) = findnext(A, 1)

"""
findnext(A, v, i::Integer)
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
# Examples
```jldoctest
julia> A = [1 4; 2 2]
2×2 Array{Int64,2}:
1 4
2 2
julia> findnext(A,4,4)
0
julia> findnext(A,4,3)
3
```
"""
function findnext(A, v, start::Integer)
l = endof(A)
i = start
while i <= l
if A[i] == v
return i
end
i = nextind(A, i)
end
return 0
end
"""
findfirst(A, v)
Return the linear index of the first element equal to `v` in `A`.
Returns `0` if `v` is not found.
# Examples
```jldoctest
julia> A = [4 6; 2 2]
2×2 Array{Int64,2}:
4 6
2 2
julia> findfirst(A,2)
2
julia> findfirst(A,3)
0
```
"""
findfirst(A, v) = findnext(A, v, 1)

"""
findnext(predicate::Function, A, i::Integer)
Expand Down Expand Up @@ -1754,14 +1708,14 @@ findfirst(testf::Function, A) = findnext(testf, A, 1)
"""
findprev(A, i::Integer)
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
Find the previous linear index <= `i` of a true element of `A`, or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> A = [false false; true true]
2×2 Array{Bool,2}:
false false
true true
julia> findprev(A,2)
2
Expand All @@ -1772,8 +1726,14 @@ julia> findprev(A,1)
"""
function findprev(A, start::Integer)
i = start
warned = false
while i >= 1
A[i] != 0 && return i
a = A[i]
if !warned && !(a isa Bool)
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A)` instead.", :findprev)
warned = true
end
a != 0 && return i
i = prevind(A, i)
end
return 0
Expand Down Expand Up @@ -1806,59 +1766,6 @@ julia> findlast(A)
"""
findlast(A) = findprev(A, endof(A))

"""
findprev(A, v, i::Integer)
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
# Examples
```jldoctest
julia> A = [0 0; 1 2]
2×2 Array{Int64,2}:
0 0
1 2
julia> findprev(A, 1, 4)
2
julia> findprev(A, 1, 1)
0
```
"""
function findprev(A, v, start::Integer)
i = start
while i >= 1
A[i] == v && return i
i = prevind(A, i)
end
return 0
end

"""
findlast(A, v)
Return the linear index of the last element equal to `v` in `A`.
Returns `0` if there is no element of `A` equal to `v`.
# Examples
```jldoctest
julia> A = [1 2; 2 1]
2×2 Array{Int64,2}:
1 2
2 1
julia> findlast(A,1)
4
julia> findlast(A,2)
3
julia> findlast(A,3)
0
```
"""
findlast(A, v) = findprev(A, v, endof(A))

"""
findprev(predicate::Function, A, i::Integer)
Expand Down Expand Up @@ -1952,9 +1859,7 @@ _index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't imple
"""
find(A)
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
common use of this is to convert a boolean array to an array of indexes of the `true`
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
Return a vector of the linear indices of the true values in `A`.
# Examples
```jldoctest
Expand All @@ -1968,7 +1873,7 @@ julia> find(A)
1
4
julia> find(zeros(3))
julia> find(falses(3))
0-element Array{Int64,1}
```
"""
Expand All @@ -1977,7 +1882,12 @@ function find(A)
I = Vector{Int}(nnzA)
cnt = 1
inds = _index_remapper(A)
warned = false
for (i,a) in enumerate(A)
if !warned && !(a isa Bool)
depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find)
warned = true
end
if a != 0
I[cnt] = inds[i]
cnt += 1
Expand All @@ -1986,7 +1896,7 @@ function find(A)
return I
end

find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
find(x::Bool) = x ? [1] : Array{Int,1}(0)
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]

findn(A::AbstractVector) = find(A)
Expand Down
4 changes: 2 additions & 2 deletions base/combinatorics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function permute!!(a, p::AbstractVector{<:Integer})
count = 0
start = 0
while count < length(a)
ptr = start = findnext(p, start+1)
ptr = start = findnext(!iszero, p, start+1)
temp = a[start]
next = p[start]
count += 1
Expand Down Expand Up @@ -125,7 +125,7 @@ function ipermute!!(a, p::AbstractVector{<:Integer})
count = 0
start = 0
while count < length(a)
start = findnext(p, start+1)
start = findnext(!iszero, p, start+1)
temp = a[start]
next = p[start]
count += 1
Expand Down
2 changes: 1 addition & 1 deletion base/datafmt.jl
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ function val_opts(opts)
for (opt_name, opt_val) in opts
in(opt_name, valid_opts) ||
throw(ArgumentError("unknown option $opt_name"))
opt_typ = valid_opt_types[findfirst(valid_opts, opt_name)]
opt_typ = valid_opt_types[findfirst(Base.equalto(opt_name), valid_opts)]
isa(opt_val, opt_typ) ||
throw(ArgumentError("$opt_name should be of type $opt_typ, got $(typeof(opt_val))"))
d[opt_name] = opt_val
Expand Down
6 changes: 6 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1855,6 +1855,12 @@ end
nothing
end

@deprecate find(x::Number) find(!iszero, x)
@deprecate findnext(A, v, i::Integer) findnext(x->x==v, A, i)
@deprecate findfirst(A, v) findfirst(x->x==v, A)
@deprecate findprev(A, v, i::Integer) findprev(x->x==v, A, i)
@deprecate findlast(A, v) findlast(x->x==v, A)

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
2 changes: 1 addition & 1 deletion base/event.jl
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ function ensure_rescheduled(othertask::Task)
# if the current task was queued,
# also need to return it to the runnable state
# before throwing an error
i = findfirst(Workqueue, ct)
i = findfirst(t->t===ct, Workqueue)
i == 0 || deleteat!(Workqueue, i)
ct.state = :runnable
end
Expand Down
2 changes: 1 addition & 1 deletion base/file.jl
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ function tempname(temppath::AbstractString,uunique::UInt32)
tempp = cwstring(temppath)
tname = Vector{UInt16}(32767)
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}), tempp,temp_prefix,uunique,tname)
lentname = findfirst(tname,0)-1
lentname = findfirst(Base.equalto(0),tname)-1
if uunique == 0 || lentname <= 0
error("GetTempFileName failed: $(Libc.FormatMessage())")
end
Expand Down
8 changes: 4 additions & 4 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1583,7 +1583,7 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
end
tf = t_ifunc[iidx]
else
fidx = findfirst(t_ffunc_key, f)
fidx = findfirst(x->x===f, t_ffunc_key)
if fidx == 0
# unknown/unhandled builtin function
return Any
Expand Down Expand Up @@ -4757,7 +4757,7 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, mod::Module, params:
elseif f == Main.Core.arrayref
return plus_saturate(argcost, isknowntype(ex.typ) ? 4 : params.inline_nonleaf_penalty)
end
fidx = findfirst(t_ffunc_key, f)
fidx = findfirst(x->x===f, t_ffunc_key)
if fidx == 0
# unknown/unhandled builtin or anonymous function
# Use the generic cost of a direct function call
Expand Down Expand Up @@ -5604,7 +5604,7 @@ function _getfield_elim_pass!(e::Expr, sv::InferenceState)
if alloc !== false
flen, fnames = alloc
if isa(j, QuoteNode)
j = findfirst(fnames, j.value)
j = findfirst(x->x == j.value, fnames)
end
if 1 <= j <= flen
ok = true
Expand Down Expand Up @@ -5899,7 +5899,7 @@ function replace_getfield!(e::Expr, tupname, vals, field_names, sv::InferenceSta
a.args[3]
else
@assert isa(a.args[3], QuoteNode)
findfirst(field_names, a.args[3].value)
findfirst(x->x == a.args[3].value, field_names)
end
@assert(idx > 0) # clients should check that all getfields are valid
val = vals[idx]
Expand Down
2 changes: 2 additions & 0 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -972,3 +972,5 @@ julia> filter(!isalpha, str)
```
"""
!(f::Function) = (x...)->!f(x...)

equalto(y) = x->isequal(x,y)
2 changes: 1 addition & 1 deletion base/permuteddimsarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ function _copy!(P::PermutedDimsArray{T,N,perm}, src) where {T,N,perm}
copy!(parent(P), src) # it's not permuted
else
R1 = CartesianRange(indices(src)[1:d])
d1 = findfirst(perm, d+1) # first permuted dim of dest
d1 = findfirst(Base.equalto(d+1), perm) # first permuted dim of dest
R2 = CartesianRange(indices(src)[d+2:d1-1])
R3 = CartesianRange(indices(src)[d1+1:end])
_permutedims!(P, src, R1, R2, R3, d+1, d1)
Expand Down
4 changes: 2 additions & 2 deletions base/pkg/query.jl
Original file line number Diff line number Diff line change
Expand Up @@ -359,7 +359,7 @@ function prune_versions(reqs::Requires, deps::Dict{String,Dict{VersionNumber,Ava
vmaskp[vn] = falses(luds)
end
for (vn,a) in fdepsp
vmind = findfirst(uniqdepssets, a.requires)
vmind = findfirst(Base.equalto(a.requires), uniqdepssets)
@assert vmind > 0
vm = vmaskp[vn]
vm[vmind] = true
Expand Down Expand Up @@ -389,7 +389,7 @@ function prune_versions(reqs::Requires, deps::Dict{String,Dict{VersionNumber,Ava
nc = length(vmask0_uniq)
classes = [VersionNumber[] for c0 = 1:nc]
for (vn,vm) in vmaskp
c0 = findfirst(vmask0_uniq, vm)
c0 = findfirst(Base.equalto(vm), vmask0_uniq)
push!(classes[c0], vn)
end
map(sort!, classes)
Expand Down
1 change: 0 additions & 1 deletion base/precompile.jl
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,6 @@ precompile(Tuple{Type{BoundsError}, Array{Int64, 2}, Tuple{Base.UnitRange{Int64}
precompile(Tuple{typeof(Base.throw_boundserror), Array{Int64, 2}, Tuple{Base.UnitRange{Int64}, Int64}})
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nexprs")), Int64, Expr})
precompile(Tuple{typeof(Base.Cartesian._nexprs), Int64, Expr})
precompile(Tuple{typeof(Core.Inference.findnext), Array{Function, 1}, typeof(===), Int64})
precompile(Tuple{typeof(Core.Inference.builtin_tfunction), typeof(===), Array{Any, 1}, Core.Inference.InferenceState, Core.Inference.InferenceParams})
precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Bool, Bool, Core.Inference.InferenceParams})
precompile(Tuple{typeof(Core.Inference.typeinf), Core.Inference.InferenceState})
Expand Down
4 changes: 2 additions & 2 deletions base/repl/LineEdit.jl
Original file line number Diff line number Diff line change
Expand Up @@ -620,10 +620,10 @@ const _space = UInt8(' ')

_notspace(c) = c != _space

beginofline(buf, pos=position(buf)) = findprev(buf.data, _newline, pos)
beginofline(buf, pos=position(buf)) = findprev(Base.equalto(_newline), buf.data, pos)

function endofline(buf, pos=position(buf))
eol = findnext(buf.data[pos+1:buf.size], _newline, 1)
eol = findnext(Base.equalto(_newline), buf.data[pos+1:buf.size], 1)
eol == 0 ? buf.size : pos + eol - 1
end

Expand Down
Loading

0 comments on commit f151e89

Please sign in to comment.