From 9bdf07fb4be009427ea6690694782f9a07b83d78 Mon Sep 17 00:00:00 2001 From: Jeff Bezanson Date: Thu, 21 Sep 2017 18:59:11 -0400 Subject: [PATCH] require explicit predicates in `find` functions fix #23120, fix #19186 --- NEWS.md | 9 ++ base/array.jl | 182 +++++++++++------------------------- base/combinatorics.jl | 4 +- base/datafmt.jl | 2 +- base/deprecated.jl | 8 ++ base/event.jl | 2 +- base/exports.jl | 1 + base/file.jl | 2 +- base/inference.jl | 8 +- base/operators.jl | 19 ++++ base/permuteddimsarray.jl | 2 +- base/pkg/query.jl | 4 +- base/precompile.jl | 1 - base/repl/LineEdit.jl | 4 +- base/sharedarray.jl | 2 +- base/sparse/sparsematrix.jl | 18 +++- base/sparse/sparsevector.jl | 16 +++- doc/src/stdlib/arrays.md | 4 - doc/src/stdlib/base.md | 1 + test/arrayops.jl | 36 +++---- test/bitarray.jl | 6 +- test/inference.jl | 4 +- test/libgit2.jl | 4 +- test/offsetarray.jl | 2 +- test/runtests.jl | 2 +- test/sparse/sparsevector.jl | 8 +- test/strings/search.jl | 8 +- test/threads.jl | 2 +- 28 files changed, 170 insertions(+), 191 deletions(-) diff --git a/NEWS.md b/NEWS.md index d882ff64563a3..5e872410ac924 100644 --- a/NEWS.md +++ b/NEWS.md @@ -297,6 +297,9 @@ Library improvements * REPL Undo via Ctrl-/ and Ctrl-_ + * New function `equalto(x)`, which returns a function that compares its argument to `x` + using `isequal` ([#23812]). + Compiler/Runtime improvements ----------------------------- @@ -489,6 +492,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 --------------------------- diff --git a/base/array.jl b/base/array.jl index 051c678bf1a35..61fbfbbf78685 100644 --- a/base/array.jl +++ b/base/array.jl @@ -1599,14 +1599,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 @@ -1618,8 +1618,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) @@ -1630,8 +1636,9 @@ end """ findfirst(A) -Return the linear index of the first non-zero value in `A` (determined by `A[i]!=0`). +Return the linear index of the first `true` value in `A`. Returns `0` if no such value is found. +To search for other kinds of values, pass a predicate as the first argument. # Examples ```jldoctest @@ -1649,58 +1656,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) @@ -1750,6 +1705,9 @@ julia> findfirst(iseven, A) julia> findfirst(x -> x>10, A) 0 + +julia> findfirst(equalto(4), A) +3 ``` """ findfirst(testf::Function, A) = findnext(testf, A, 1) @@ -1757,14 +1715,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 @@ -1775,8 +1733,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 @@ -1785,8 +1749,8 @@ end """ findlast(A) -Return the linear index of the last non-zero value in `A` (determined by `A[i]!=0`). -Returns `0` if there is no non-zero value in `A`. +Return the linear index of the last `true` value in `A`. +Returns `0` if there is no `true` value in `A`. # Examples ```jldoctest @@ -1809,59 +1773,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) @@ -1921,16 +1832,23 @@ If there are no such elements of `A`, find returns an empty array. # Examples ```jldoctest -julia> A = [1 2; 3 4] -2×2 Array{Int64,2}: - 1 2 - 3 4 +julia> A = [1 2 0; 3 4 0] +2×3 Array{Int64,2}: + 1 2 0 + 3 4 0 -julia> find(isodd,A) +julia> find(isodd, A) 2-element Array{Int64,1}: 1 2 +julia> find(!iszero, A) +4-element Array{Int64,1}: + 1 + 2 + 3 + 4 + julia> find(isodd, [2, 4]) 0-element Array{Int64,1} ``` @@ -1955,9 +1873,8 @@ _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`. +To search for other kinds of values, pass a predicate as the first argument. # Examples ```jldoctest @@ -1971,7 +1888,7 @@ julia> find(A) 1 4 -julia> find(zeros(3)) +julia> find(falses(3)) 0-element Array{Int64,1} ``` """ @@ -1980,7 +1897,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 @@ -1989,7 +1911,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) diff --git a/base/combinatorics.jl b/base/combinatorics.jl index 28e0e451b89b7..fe25ce2a65905 100644 --- a/base/combinatorics.jl +++ b/base/combinatorics.jl @@ -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 @@ -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 diff --git a/base/datafmt.jl b/base/datafmt.jl index 6ceecd14acf40..294620400cba8 100644 --- a/base/datafmt.jl +++ b/base/datafmt.jl @@ -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(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 diff --git a/base/deprecated.jl b/base/deprecated.jl index d8362b23a9eb1..c8b8a1084c770 100644 --- a/base/deprecated.jl +++ b/base/deprecated.jl @@ -1918,6 +1918,14 @@ end @deprecate strwidth textwidth @deprecate charwidth textwidth +@deprecate find(x::Number) find(!iszero, x) +@deprecate findnext(A, v, i::Integer) findnext(equalto(v), A, i) +@deprecate findfirst(A, v) findfirst(equalto(v), A) +@deprecate findprev(A, v, i::Integer) findprev(equalto(v), A, i) +@deprecate findlast(A, v) findlast(equalto(v), A) +# also remove deprecation warnings in find* functions in array.jl, sparse/sparsematrix.jl, +# and sparse/sparsevector.jl. + # END 0.7 deprecations # BEGIN 1.0 deprecations diff --git a/base/event.jl b/base/event.jl index 74bb6ba3069a3..57ccd302a0692 100644 --- a/base/event.jl +++ b/base/event.jl @@ -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 diff --git a/base/exports.jl b/base/exports.jl index ca34c71c12f38..b3e3b288cd65b 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -859,6 +859,7 @@ export identity, isbits, isequal, + equalto, isimmutable, isless, ifelse, diff --git a/base/file.jl b/base/file.jl index 9876aeb5ac89a..5f0e15dce2b80 100644 --- a/base/file.jl +++ b/base/file.jl @@ -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(iszero,tname)-1 if uunique == 0 || lentname <= 0 error("GetTempFileName failed: $(Libc.FormatMessage())") end diff --git a/base/inference.jl b/base/inference.jl index ec9ac4b9536d0..e4dce78d1af54 100644 --- a/base/inference.jl +++ b/base/inference.jl @@ -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 @@ -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 @@ -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(equalto(j.value), fnames) end if 1 <= j <= flen ok = true @@ -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(equalto(a.args[3].value), field_names) end @assert(idx > 0) # clients should check that all getfields are valid val = vals[idx] diff --git a/base/operators.jl b/base/operators.jl index 138e6b7c2dcf1..0c3f092c7d421 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -972,3 +972,22 @@ julia> filter(!isalpha, str) ``` """ !(f::Function) = (x...)->!f(x...) + +struct EqualTo{T} <: Function + x::T + + EqualTo(x::T) where {T} = new{T}(x) +end + +(f::EqualTo)(y) = isequal(f.x, y) + +""" + equalto(x) + +Create a function that compares its argument to `x` using [`isequal`](@ref); i.e. returns +`y->isequal(x,y)`. + +The returned function is of type `Base.EqualTo`. This allows dispatching to +specialized methods by using e.g. `f::Base.EqualTo` in a method signature. +""" +const equalto = EqualTo diff --git a/base/permuteddimsarray.jl b/base/permuteddimsarray.jl index cc91063e5108b..fd875a644360d 100644 --- a/base/permuteddimsarray.jl +++ b/base/permuteddimsarray.jl @@ -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(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) diff --git a/base/pkg/query.jl b/base/pkg/query.jl index dbe1919f0664d..0233d159186a6 100644 --- a/base/pkg/query.jl +++ b/base/pkg/query.jl @@ -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(equalto(a.requires), uniqdepssets) @assert vmind > 0 vm = vmaskp[vn] vm[vmind] = true @@ -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(equalto(vm), vmask0_uniq) push!(classes[c0], vn) end map(sort!, classes) diff --git a/base/precompile.jl b/base/precompile.jl index 4981c89231dd3..86bcc216f32c8 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -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}) diff --git a/base/repl/LineEdit.jl b/base/repl/LineEdit.jl index 36c8ffb726f19..43e5b494ce77e 100644 --- a/base/repl/LineEdit.jl +++ b/base/repl/LineEdit.jl @@ -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(equalto(_newline), buf.data, pos) function endofline(buf, pos=position(buf)) - eol = findnext(buf.data[pos+1:buf.size], _newline, 1) + eol = findnext(equalto(_newline), buf.data[pos+1:buf.size], 1) eol == 0 ? buf.size : pos + eol - 1 end diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 3cdeb3bcd88a1..d1c5070f02f0c 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -390,7 +390,7 @@ sub_1dim(S::SharedArray, pidx) = view(S.s, range_1dim(S, pidx)) function init_loc_flds(S::SharedArray{T,N}, empty_local=false) where T where N if myid() in S.pids - S.pidx = findfirst(S.pids, myid()) + S.pidx = findfirst(equalto(myid()), S.pids) if isa(S.refs[1], Future) refid = remoteref_id(S.refs[S.pidx]) else diff --git a/base/sparse/sparsematrix.jl b/base/sparse/sparsematrix.jl index 8b14e08bc6daf..d69721a9c3479 100644 --- a/base/sparse/sparsematrix.jl +++ b/base/sparse/sparsematrix.jl @@ -1283,19 +1283,31 @@ dropzeros(A::SparseMatrixCSC, trim::Bool = true) = dropzeros!(copy(A), trim) ## Find methods function find(S::SparseMatrixCSC) + if !(eltype(S) <: Bool) + depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find) + end + return find(x->x!=0, S) +end + +function find(p::Function, S::SparseMatrixCSC) + if p(zero(eltype(S))) + return invoke(find, Tuple{Function, Any}, p, S) + end sz = size(S) - I, J = findn(S) + I, J = _findn(p, S) return sub2ind(sz, I, J) end -function findn(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} +findn(S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} = _findn(x->x!=0, S) + +function _findn(p::Function, S::SparseMatrixCSC{Tv,Ti}) where {Tv,Ti} numnz = nnz(S) I = Vector{Ti}(numnz) J = Vector{Ti}(numnz) count = 1 @inbounds for col = 1 : S.n, k = S.colptr[col] : (S.colptr[col+1]-1) - if S.nzval[k] != 0 + if p(S.nzval[k]) I[count] = S.rowval[k] J[count] = col count += 1 diff --git a/base/sparse/sparsevector.jl b/base/sparse/sparsevector.jl index aed5f9adc3830..8c5d5ab18115d 100644 --- a/base/sparse/sparsevector.jl +++ b/base/sparse/sparsevector.jl @@ -649,7 +649,17 @@ function getindex(A::SparseMatrixCSC{Tv}, I::AbstractVector) where Tv SparseVector(n, rowvalB, nzvalB) end -function find(x::SparseVector{<:Any,Ti}) where Ti +function find(x::SparseVector) + if !(eltype(x) <: Bool) + depwarn("In the future `find(A)` will only work on boolean collections. Use `find(x->x!=0, A)` instead.", :find) + end + return find(x->x!=0, x) +end + +function find(p::Function, x::SparseVector{<:Any,Ti}) where Ti + if p(zero(eltype(x))) + return invoke(find, Tuple{Function, Any}, p, x) + end numnz = nnz(x) I = Vector{Ti}(numnz) @@ -658,7 +668,7 @@ function find(x::SparseVector{<:Any,Ti}) where Ti count = 1 @inbounds for i = 1 : numnz - if nzval[i] != 0 + if p(nzval[i]) I[count] = nzind[i] count += 1 end @@ -1886,7 +1896,7 @@ function sort(x::SparseVector{Tv,Ti}; kws...) where {Tv,Ti} allvals = push!(copy(nonzeros(x)),zero(Tv)) sinds = sortperm(allvals;kws...) n,k = length(x),length(allvals) - z = findfirst(sinds,k) + z = findfirst(equalto(k),sinds) newnzind = collect(Ti,1:k-1) newnzind[z:end] .+= n-k+1 newnzvals = allvals[deleteat!(sinds[1:k],z)] diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index abdcc1c865fb1..86bcddb6fa1d1 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -111,17 +111,13 @@ Base.find(::Function, ::Any) Base.findn Base.findnz Base.findfirst(::Any) -Base.findfirst(::Any, ::Any) Base.findfirst(::Function, ::Any) Base.findlast(::Any) -Base.findlast(::Any, ::Any) Base.findlast(::Function, ::Any) Base.findnext(::Any, ::Integer) Base.findnext(::Function, ::Any, ::Integer) -Base.findnext(::Any, ::Any, ::Integer) Base.findprev(::Any, ::Integer) Base.findprev(::Function, ::Any, ::Integer) -Base.findprev(::Any, ::Any, ::Integer) Base.permutedims Base.permutedims! Base.PermutedDimsArray diff --git a/doc/src/stdlib/base.md b/doc/src/stdlib/base.md index 639006a819fa4..e3d95203fdca0 100644 --- a/doc/src/stdlib/base.md +++ b/doc/src/stdlib/base.md @@ -136,6 +136,7 @@ Core.invoke Base.invokelatest Base.:(|>) Base.:(∘) +Base.equalto ``` ## Syntax diff --git a/test/arrayops.jl b/test/arrayops.jl index 3f8cb8a786888..70997260272ea 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -427,44 +427,44 @@ end @test X[Y[end],1] == 5 @test X[end,Y[end]] == 11 end + @testset "find, findfirst, findnext, findlast, findprev" begin a = [0,1,2,3,0,1,2,3] - @test find(a) == [2,3,4,6,7,8] + @test find(!iszero, a) == [2,3,4,6,7,8] @test find(a.==2) == [3,7] @test find(isodd,a) == [2,4,6,8] - @test findfirst(a) == 2 + @test findfirst(!iszero, a) == 2 @test findfirst(a.==0) == 1 @test findfirst(a.==5) == 0 - @test findfirst([1,2,4,1,2,3,4], 3) == 6 + @test findfirst(equalto(3), [1,2,4,1,2,3,4]) == 6 + @test findfirst(!equalto(1), [1,2,4,1,2,3,4]) == 2 @test findfirst(isodd, [2,4,6,3,9,2,0]) == 4 @test findfirst(isodd, [2,4,6,2,0]) == 0 - @test findnext(a,4) == 4 - @test findnext(a,5) == 6 - @test findnext(a,1) == 2 - @test findnext(a,1,4) == 6 - @test findnext(a,5,4) == 0 - @test findlast(a) == 8 + @test findnext(!iszero,a,4) == 4 + @test findnext(!iszero,a,5) == 6 + @test findnext(!iszero,a,1) == 2 + @test findnext(equalto(1),a,4) == 6 + @test findnext(equalto(5),a,4) == 0 + @test findlast(!iszero, a) == 8 @test findlast(a.==0) == 5 @test findlast(a.==5) == 0 - @test findlast([1,2,4,1,2,3,4], 3) == 6 + @test findlast(equalto(3), [1,2,4,1,2,3,4]) == 6 @test findlast(isodd, [2,4,6,3,9,2,0]) == 5 @test findlast(isodd, [2,4,6,2,0]) == 0 - @test findprev(a,4) == 4 - @test findprev(a,5) == 4 - @test findprev(a,1) == 0 - @test findprev(a,1,4) == 2 - @test findprev(a,1,8) == 6 + @test findprev(!iszero,a,4) == 4 + @test findprev(!iszero,a,5) == 4 + @test findprev(!iszero,a,1) == 0 + @test findprev(equalto(1),a,4) == 2 + @test findprev(equalto(1),a,8) == 6 @test findprev(isodd, [2,4,5,3,9,2,0], 7) == 5 @test findprev(isodd, [2,4,5,3,9,2,0], 2) == 0 end @testset "find with general iterables" begin s = "julia" - # FIXME once 16269 is resolved - # @test find(s) == [1,2,3,4,5] @test find(c -> c == 'l', s) == [3] g = graphemes("日本語") @test find(isascii, g) == Int[] - @test find((i % 2 for i in 1:10)) == collect(1:2:9) + @test find(!iszero, (i % 2 for i in 1:10)) == collect(1:2:9) end @testset "findn" begin b = findn(ones(2,2,2,2)) diff --git a/test/bitarray.jl b/test/bitarray.jl index 55101550a2c5a..2e273f65d07d0 100644 --- a/test/bitarray.jl +++ b/test/bitarray.jl @@ -1069,9 +1069,9 @@ timesofar("datamove") @check_bit_operation findfirst(b1) Int - @check_bit_operation findfirst(b1, true) Int - @check_bit_operation findfirst(b1, false) Int - @check_bit_operation findfirst(b1, 3) Int + @check_bit_operation findfirst(!iszero, b1) Int + @check_bit_operation findfirst(iszero, b1) Int + @check_bit_operation findfirst(equalto(3), b1) Int @check_bit_operation findfirst(x->x, b1) Int @check_bit_operation findfirst(x->!x, b1) Int diff --git a/test/inference.jl b/test/inference.jl index 6d8e5cf78ac20..81910152cf37e 100644 --- a/test/inference.jl +++ b/test/inference.jl @@ -1102,7 +1102,7 @@ isdefined_f3(x) = isdefined(x, 3) @test find_call(first(code_typed(isdefined_f3, Tuple{Tuple{Vararg{Int}}})[1]).code, isdefined, 3) let isa_tfunc = Core.Inference.t_ffunc_val[ - findfirst(Core.Inference.t_ffunc_key, isa)][3] + findfirst(x->x===isa, Core.Inference.t_ffunc_key)][3] @test isa_tfunc(Array, Const(AbstractArray)) === Const(true) @test isa_tfunc(Array, Type{AbstractArray}) === Const(true) @test isa_tfunc(Array, Type{AbstractArray{Int}}) == Bool @@ -1142,7 +1142,7 @@ let isa_tfunc = Core.Inference.t_ffunc_val[ end let subtype_tfunc = Core.Inference.t_ffunc_val[ - findfirst(Core.Inference.t_ffunc_key, <:)][3] + findfirst(x->x===(<:), Core.Inference.t_ffunc_key)][3] @test subtype_tfunc(Type{<:Array}, Const(AbstractArray)) === Const(true) @test subtype_tfunc(Type{<:Array}, Type{AbstractArray}) === Const(true) @test subtype_tfunc(Type{<:Array}, Type{AbstractArray{Int}}) == Bool diff --git a/test/libgit2.jl b/test/libgit2.jl index c353e2f74f3e4..e582227e14eeb 100644 --- a/test/libgit2.jl +++ b/test/libgit2.jl @@ -51,8 +51,8 @@ end @testset "Check library features" begin f = LibGit2.features() - @test findfirst(f, LibGit2.Consts.FEATURE_SSH) > 0 - @test findfirst(f, LibGit2.Consts.FEATURE_HTTPS) > 0 + @test findfirst(equalto(LibGit2.Consts.FEATURE_SSH), f) > 0 + @test findfirst(equalto(LibGit2.Consts.FEATURE_HTTPS), f) > 0 end @testset "OID" begin diff --git a/test/offsetarray.jl b/test/offsetarray.jl index 993b7de476772..a15727bfa2c97 100644 --- a/test/offsetarray.jl +++ b/test/offsetarray.jl @@ -364,7 +364,7 @@ I,J,N = findnz(z) @test I == [-1] @test J == [0] @test N == [2] -@test find(h) == [-2:1;] +@test find(!iszero,h) == [-2:1;] @test find(x->x>0, h) == [-1,1] @test find(x->x<0, h) == [-2,0] @test find(x->x==0, h) == [2] diff --git a/test/runtests.jl b/test/runtests.jl index 927165bf4048b..cda2c103313b5 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -16,7 +16,7 @@ end const node1_tests = String[] function move_to_node1(t) if t in tests - splice!(tests, findfirst(tests, t)) + splice!(tests, findfirst(equalto(t), tests)) push!(node1_tests, t) end end diff --git a/test/sparse/sparsevector.jl b/test/sparse/sparsevector.jl index e953231204ac5..fcc0baac1447b 100644 --- a/test/sparse/sparsevector.jl +++ b/test/sparse/sparsevector.jl @@ -256,10 +256,12 @@ let x = SparseVector(10, [2, 7, 9], [2.0, 7.0, 9.0]) end # find and findnz tests -@test find(spv_x1) == find(x1_full) -@test findnz(spv_x1) == (find(x1_full), filter(x->x!=0, x1_full)) +@test find(!iszero, spv_x1) == find(!iszero, x1_full) +@test find(spv_x1 .> 1) == find(x1_full .> 1) +@test find(x->x>1, spv_x1) == find(x->x>1, x1_full) +@test findnz(spv_x1) == (find(!iszero, x1_full), filter(x->x!=0, x1_full)) let xc = SparseVector(8, [2, 3, 5], [1.25, 0, -0.75]), fc = Array(xc) - @test find(xc) == find(fc) + @test find(!iszero, xc) == find(!iszero, fc) @test findnz(xc) == ([2, 5], [1.25, -0.75]) end diff --git a/test/strings/search.jl b/test/strings/search.jl index cb0c342844db0..0462f9dfe0a5b 100644 --- a/test/strings/search.jl +++ b/test/strings/search.jl @@ -381,7 +381,7 @@ end @test_throws ErrorException "ab" ∈ "abc" # issue #15723 -@test findfirst("⨳(", '(') == 4 -@test findnext("(⨳(", '(', 2) == 5 -@test findlast("(⨳(", '(') == 5 -@test findprev("(⨳(", '(', 2) == 1 +@test findfirst(equalto('('), "⨳(") == 4 +@test findnext(equalto('('), "(⨳(", 2) == 5 +@test findlast(equalto('('), "(⨳(") == 5 +@test findprev(equalto('('), "(⨳(", 2) == 1 diff --git a/test/threads.jl b/test/threads.jl index fc0a1d984a84b..af29f80e74257 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -25,7 +25,7 @@ function test_threaded_loop_and_atomic_add() @test x[] == 10000 # Next test checks that all loop iterations ran, # and were unique (via pigeon-hole principle). - @test findfirst(found,false) == 0 + @test !(false in found) if was_inorder println(STDERR, "Warning: threaded loop executed in order") end