Skip to content

Commit f151e89

Browse files
committed
require explicit predicates in find functions
fix #23120, fix #19186
1 parent ff9fb48 commit f151e89

24 files changed

+95
-177
lines changed

NEWS.md

+6
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,12 @@ Deprecated or removed
468468
* The timing functions `tic`, `toc`, and `toq` are deprecated in favor of `@time` and `@elapsed`
469469
([#17046]).
470470

471+
* Methods of `findfirst`, `findnext`, `findlast`, and `findprev` that accept a value to
472+
search for are deprecated in favor of passing a predicate ([#19186], [#10593]).
473+
474+
* `find` functions now operate only on booleans by default. To look for non-zeros, use
475+
`x->x!=0` or `!iszero` ([#23120]).
476+
471477
Command-line option changes
472478
---------------------------
473479

base/array.jl

+32-122
Original file line numberDiff line numberDiff line change
@@ -1596,14 +1596,14 @@ cat(n::Integer, x::Integer...) = reshape([x...], (ntuple(x->1, n-1)..., length(x
15961596
"""
15971597
findnext(A, i::Integer)
15981598
1599-
Find the next linear index >= `i` of a non-zero element of `A`, or `0` if not found.
1599+
Find the next linear index >= `i` of a true element of `A`, or `0` if not found.
16001600
16011601
# Examples
16021602
```jldoctest
1603-
julia> A = [0 0; 1 0]
1604-
2×2 Array{Int64,2}:
1605-
0 0
1606-
1 0
1603+
julia> A = [false false; true false]
1604+
2×2 Array{Bool,2}:
1605+
false false
1606+
true false
16071607
16081608
julia> findnext(A,1)
16091609
2
@@ -1615,8 +1615,14 @@ julia> findnext(A,3)
16151615
function findnext(A, start::Integer)
16161616
l = endof(A)
16171617
i = start
1618+
warned = false
16181619
while i <= l
1619-
if A[i] != 0
1620+
a = A[i]
1621+
if !warned && !(a isa Bool)
1622+
depwarn("In the future `findnext` will only work on boolean collections. Use `findnext(x->x!=0, A)` instead.", :findnext)
1623+
warned = true
1624+
end
1625+
if a != 0
16201626
return i
16211627
end
16221628
i = nextind(A, i)
@@ -1646,58 +1652,6 @@ julia> findfirst(zeros(3))
16461652
"""
16471653
findfirst(A) = findnext(A, 1)
16481654

1649-
"""
1650-
findnext(A, v, i::Integer)
1651-
1652-
Find the next linear index >= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
1653-
1654-
# Examples
1655-
```jldoctest
1656-
julia> A = [1 4; 2 2]
1657-
2×2 Array{Int64,2}:
1658-
1 4
1659-
2 2
1660-
1661-
julia> findnext(A,4,4)
1662-
0
1663-
1664-
julia> findnext(A,4,3)
1665-
3
1666-
```
1667-
"""
1668-
function findnext(A, v, start::Integer)
1669-
l = endof(A)
1670-
i = start
1671-
while i <= l
1672-
if A[i] == v
1673-
return i
1674-
end
1675-
i = nextind(A, i)
1676-
end
1677-
return 0
1678-
end
1679-
"""
1680-
findfirst(A, v)
1681-
1682-
Return the linear index of the first element equal to `v` in `A`.
1683-
Returns `0` if `v` is not found.
1684-
1685-
# Examples
1686-
```jldoctest
1687-
julia> A = [4 6; 2 2]
1688-
2×2 Array{Int64,2}:
1689-
4 6
1690-
2 2
1691-
1692-
julia> findfirst(A,2)
1693-
2
1694-
1695-
julia> findfirst(A,3)
1696-
0
1697-
```
1698-
"""
1699-
findfirst(A, v) = findnext(A, v, 1)
1700-
17011655
"""
17021656
findnext(predicate::Function, A, i::Integer)
17031657
@@ -1754,14 +1708,14 @@ findfirst(testf::Function, A) = findnext(testf, A, 1)
17541708
"""
17551709
findprev(A, i::Integer)
17561710
1757-
Find the previous linear index <= `i` of a non-zero element of `A`, or `0` if not found.
1711+
Find the previous linear index <= `i` of a true element of `A`, or `0` if not found.
17581712
17591713
# Examples
17601714
```jldoctest
1761-
julia> A = [0 0; 1 2]
1762-
2×2 Array{Int64,2}:
1763-
0 0
1764-
1 2
1715+
julia> A = [false false; true true]
1716+
2×2 Array{Bool,2}:
1717+
false false
1718+
true true
17651719
17661720
julia> findprev(A,2)
17671721
2
@@ -1772,8 +1726,14 @@ julia> findprev(A,1)
17721726
"""
17731727
function findprev(A, start::Integer)
17741728
i = start
1729+
warned = false
17751730
while i >= 1
1776-
A[i] != 0 && return i
1731+
a = A[i]
1732+
if !warned && !(a isa Bool)
1733+
depwarn("In the future `findprev` will only work on boolean collections. Use `findprev(x->x!=0, A)` instead.", :findprev)
1734+
warned = true
1735+
end
1736+
a != 0 && return i
17771737
i = prevind(A, i)
17781738
end
17791739
return 0
@@ -1806,59 +1766,6 @@ julia> findlast(A)
18061766
"""
18071767
findlast(A) = findprev(A, endof(A))
18081768

1809-
"""
1810-
findprev(A, v, i::Integer)
1811-
1812-
Find the previous linear index <= `i` of an element of `A` equal to `v` (using `==`), or `0` if not found.
1813-
1814-
# Examples
1815-
```jldoctest
1816-
julia> A = [0 0; 1 2]
1817-
2×2 Array{Int64,2}:
1818-
0 0
1819-
1 2
1820-
1821-
julia> findprev(A, 1, 4)
1822-
2
1823-
1824-
julia> findprev(A, 1, 1)
1825-
0
1826-
```
1827-
"""
1828-
function findprev(A, v, start::Integer)
1829-
i = start
1830-
while i >= 1
1831-
A[i] == v && return i
1832-
i = prevind(A, i)
1833-
end
1834-
return 0
1835-
end
1836-
1837-
"""
1838-
findlast(A, v)
1839-
1840-
Return the linear index of the last element equal to `v` in `A`.
1841-
Returns `0` if there is no element of `A` equal to `v`.
1842-
1843-
# Examples
1844-
```jldoctest
1845-
julia> A = [1 2; 2 1]
1846-
2×2 Array{Int64,2}:
1847-
1 2
1848-
2 1
1849-
1850-
julia> findlast(A,1)
1851-
4
1852-
1853-
julia> findlast(A,2)
1854-
3
1855-
1856-
julia> findlast(A,3)
1857-
0
1858-
```
1859-
"""
1860-
findlast(A, v) = findprev(A, v, endof(A))
1861-
18621769
"""
18631770
findprev(predicate::Function, A, i::Integer)
18641771
@@ -1952,9 +1859,7 @@ _index_remapper(iter) = OneTo(typemax(Int)) # safe for objects that don't imple
19521859
"""
19531860
find(A)
19541861
1955-
Return a vector of the linear indexes of the non-zeros in `A` (determined by `A[i]!=0`). A
1956-
common use of this is to convert a boolean array to an array of indexes of the `true`
1957-
elements. If there are no non-zero elements of `A`, `find` returns an empty array.
1862+
Return a vector of the linear indices of the true values in `A`.
19581863
19591864
# Examples
19601865
```jldoctest
@@ -1968,7 +1873,7 @@ julia> find(A)
19681873
1
19691874
4
19701875
1971-
julia> find(zeros(3))
1876+
julia> find(falses(3))
19721877
0-element Array{Int64,1}
19731878
```
19741879
"""
@@ -1977,7 +1882,12 @@ function find(A)
19771882
I = Vector{Int}(nnzA)
19781883
cnt = 1
19791884
inds = _index_remapper(A)
1885+
warned = false
19801886
for (i,a) in enumerate(A)
1887+
if !warned && !(a isa Bool)
1888+
depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find)
1889+
warned = true
1890+
end
19811891
if a != 0
19821892
I[cnt] = inds[i]
19831893
cnt += 1
@@ -1986,7 +1896,7 @@ function find(A)
19861896
return I
19871897
end
19881898

1989-
find(x::Number) = x == 0 ? Array{Int,1}(0) : [1]
1899+
find(x::Bool) = x ? [1] : Array{Int,1}(0)
19901900
find(testf::Function, x::Number) = !testf(x) ? Array{Int,1}(0) : [1]
19911901

19921902
findn(A::AbstractVector) = find(A)

base/combinatorics.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ function permute!!(a, p::AbstractVector{<:Integer})
7575
count = 0
7676
start = 0
7777
while count < length(a)
78-
ptr = start = findnext(p, start+1)
78+
ptr = start = findnext(!iszero, p, start+1)
7979
temp = a[start]
8080
next = p[start]
8181
count += 1
@@ -125,7 +125,7 @@ function ipermute!!(a, p::AbstractVector{<:Integer})
125125
count = 0
126126
start = 0
127127
while count < length(a)
128-
start = findnext(p, start+1)
128+
start = findnext(!iszero, p, start+1)
129129
temp = a[start]
130130
next = p[start]
131131
count += 1

base/datafmt.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ function val_opts(opts)
370370
for (opt_name, opt_val) in opts
371371
in(opt_name, valid_opts) ||
372372
throw(ArgumentError("unknown option $opt_name"))
373-
opt_typ = valid_opt_types[findfirst(valid_opts, opt_name)]
373+
opt_typ = valid_opt_types[findfirst(Base.equalto(opt_name), valid_opts)]
374374
isa(opt_val, opt_typ) ||
375375
throw(ArgumentError("$opt_name should be of type $opt_typ, got $(typeof(opt_val))"))
376376
d[opt_name] = opt_val

base/deprecated.jl

+6
Original file line numberDiff line numberDiff line change
@@ -1855,6 +1855,12 @@ end
18551855
nothing
18561856
end
18571857

1858+
@deprecate find(x::Number) find(!iszero, x)
1859+
@deprecate findnext(A, v, i::Integer) findnext(x->x==v, A, i)
1860+
@deprecate findfirst(A, v) findfirst(x->x==v, A)
1861+
@deprecate findprev(A, v, i::Integer) findprev(x->x==v, A, i)
1862+
@deprecate findlast(A, v) findlast(x->x==v, A)
1863+
18581864
# END 0.7 deprecations
18591865

18601866
# BEGIN 1.0 deprecations

base/event.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ function ensure_rescheduled(othertask::Task)
234234
# if the current task was queued,
235235
# also need to return it to the runnable state
236236
# before throwing an error
237-
i = findfirst(Workqueue, ct)
237+
i = findfirst(t->t===ct, Workqueue)
238238
i == 0 || deleteat!(Workqueue, i)
239239
ct.state = :runnable
240240
end

base/file.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ function tempname(temppath::AbstractString,uunique::UInt32)
271271
tempp = cwstring(temppath)
272272
tname = Vector{UInt16}(32767)
273273
uunique = ccall(:GetTempFileNameW,stdcall,UInt32,(Ptr{UInt16},Ptr{UInt16},UInt32,Ptr{UInt16}), tempp,temp_prefix,uunique,tname)
274-
lentname = findfirst(tname,0)-1
274+
lentname = findfirst(Base.equalto(0),tname)-1
275275
if uunique == 0 || lentname <= 0
276276
error("GetTempFileName failed: $(Libc.FormatMessage())")
277277
end

base/inference.jl

+4-4
Original file line numberDiff line numberDiff line change
@@ -1583,7 +1583,7 @@ function builtin_tfunction(@nospecialize(f), argtypes::Array{Any,1},
15831583
end
15841584
tf = t_ifunc[iidx]
15851585
else
1586-
fidx = findfirst(t_ffunc_key, f)
1586+
fidx = findfirst(x->x===f, t_ffunc_key)
15871587
if fidx == 0
15881588
# unknown/unhandled builtin function
15891589
return Any
@@ -4757,7 +4757,7 @@ function statement_cost(ex::Expr, line::Int, src::CodeInfo, mod::Module, params:
47574757
elseif f == Main.Core.arrayref
47584758
return plus_saturate(argcost, isknowntype(ex.typ) ? 4 : params.inline_nonleaf_penalty)
47594759
end
4760-
fidx = findfirst(t_ffunc_key, f)
4760+
fidx = findfirst(x->x===f, t_ffunc_key)
47614761
if fidx == 0
47624762
# unknown/unhandled builtin or anonymous function
47634763
# Use the generic cost of a direct function call
@@ -5604,7 +5604,7 @@ function _getfield_elim_pass!(e::Expr, sv::InferenceState)
56045604
if alloc !== false
56055605
flen, fnames = alloc
56065606
if isa(j, QuoteNode)
5607-
j = findfirst(fnames, j.value)
5607+
j = findfirst(x->x == j.value, fnames)
56085608
end
56095609
if 1 <= j <= flen
56105610
ok = true
@@ -5899,7 +5899,7 @@ function replace_getfield!(e::Expr, tupname, vals, field_names, sv::InferenceSta
58995899
a.args[3]
59005900
else
59015901
@assert isa(a.args[3], QuoteNode)
5902-
findfirst(field_names, a.args[3].value)
5902+
findfirst(x->x == a.args[3].value, field_names)
59035903
end
59045904
@assert(idx > 0) # clients should check that all getfields are valid
59055905
val = vals[idx]

base/operators.jl

+2
Original file line numberDiff line numberDiff line change
@@ -972,3 +972,5 @@ julia> filter(!isalpha, str)
972972
```
973973
"""
974974
!(f::Function) = (x...)->!f(x...)
975+
976+
equalto(y) = x->isequal(x,y)

base/permuteddimsarray.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ function _copy!(P::PermutedDimsArray{T,N,perm}, src) where {T,N,perm}
148148
copy!(parent(P), src) # it's not permuted
149149
else
150150
R1 = CartesianRange(indices(src)[1:d])
151-
d1 = findfirst(perm, d+1) # first permuted dim of dest
151+
d1 = findfirst(Base.equalto(d+1), perm) # first permuted dim of dest
152152
R2 = CartesianRange(indices(src)[d+2:d1-1])
153153
R3 = CartesianRange(indices(src)[d1+1:end])
154154
_permutedims!(P, src, R1, R2, R3, d+1, d1)

base/pkg/query.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ function prune_versions(reqs::Requires, deps::Dict{String,Dict{VersionNumber,Ava
359359
vmaskp[vn] = falses(luds)
360360
end
361361
for (vn,a) in fdepsp
362-
vmind = findfirst(uniqdepssets, a.requires)
362+
vmind = findfirst(Base.equalto(a.requires), uniqdepssets)
363363
@assert vmind > 0
364364
vm = vmaskp[vn]
365365
vm[vmind] = true
@@ -389,7 +389,7 @@ function prune_versions(reqs::Requires, deps::Dict{String,Dict{VersionNumber,Ava
389389
nc = length(vmask0_uniq)
390390
classes = [VersionNumber[] for c0 = 1:nc]
391391
for (vn,vm) in vmaskp
392-
c0 = findfirst(vmask0_uniq, vm)
392+
c0 = findfirst(Base.equalto(vm), vmask0_uniq)
393393
push!(classes[c0], vn)
394394
end
395395
map(sort!, classes)

base/precompile.jl

-1
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,6 @@ precompile(Tuple{Type{BoundsError}, Array{Int64, 2}, Tuple{Base.UnitRange{Int64}
819819
precompile(Tuple{typeof(Base.throw_boundserror), Array{Int64, 2}, Tuple{Base.UnitRange{Int64}, Int64}})
820820
precompile(Tuple{getfield(Base.Cartesian, Symbol("#@nexprs")), Int64, Expr})
821821
precompile(Tuple{typeof(Base.Cartesian._nexprs), Int64, Expr})
822-
precompile(Tuple{typeof(Core.Inference.findnext), Array{Function, 1}, typeof(===), Int64})
823822
precompile(Tuple{typeof(Core.Inference.builtin_tfunction), typeof(===), Array{Any, 1}, Core.Inference.InferenceState, Core.Inference.InferenceParams})
824823
precompile(Tuple{typeof(Core.Inference.typeinf_frame), Core.MethodInstance, Bool, Bool, Core.Inference.InferenceParams})
825824
precompile(Tuple{typeof(Core.Inference.typeinf), Core.Inference.InferenceState})

base/repl/LineEdit.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,10 @@ const _space = UInt8(' ')
620620

621621
_notspace(c) = c != _space
622622

623-
beginofline(buf, pos=position(buf)) = findprev(buf.data, _newline, pos)
623+
beginofline(buf, pos=position(buf)) = findprev(Base.equalto(_newline), buf.data, pos)
624624

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

0 commit comments

Comments
 (0)