Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
- Add one argument ``curried'' forms of `isequal`, `==` and `in`.

- Keep the following definitions to not break Compat on julia v0.6:
   - const EqualTo{T} = Fix2{typeof(isequal),T}
   - equalto(x) = isequal(x)
   - const OccursIn{T} = Fix2{typeof(in),T}
   - occursin(x) = in(x)
  • Loading branch information
fredrikekre committed Mar 17, 2018
1 parent b43c216 commit 004d8f9
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 65 deletions.
13 changes: 7 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,8 @@ Currently, the `@compat` macro supports the following syntaxes:
`cov(::AbstractVector; corrected=)` and `cov(::AbstractVector, ::AbstractVector; corrected=)`
are only available on 0.6. ([#21709])

* `equalto` constructs an `EqualTo` object that can be used as a predicate ([#23812]).
* `isequal`, `==` and `in` have one argument "curried" forms. For example `isequal(x)`
returns a function that compares its arguments to `x` using `isequal` ([#26436]).

* `*(::Union{Char,AbstractString},::Union{Char,AbstractString})` concatenation. ([#22512])

Expand Down Expand Up @@ -350,18 +351,18 @@ Currently, the `@compat` macro supports the following syntaxes:
* `find` is now `findall` ([#25545]).

* `search` is now `findfirst`/`findnext` and `rsearch` is now `findlast`/`findprev`,
sometimes combined with `equalto` or `occursin` ([#24673]).
sometimes combined with `isequal` or `in` ([#24673], [#26436]).

* `Compat.findfirst`, `Compat.findnext`, `Compat.findlast` and `Compat.findprev`,
return `nothing` when no match is found (rather than `0` or `0:-1`)
as on Julia 0.7 ([#24673], [#26149]).

* `findin(a, b)` is now `findall(occursin(b), a)` ([#24673]).
* `findin(a, b)` is now `findall(in(b), a)` ([#24673]).

* `indmin` and `indmax` are now `argmin` and `argmax`, respectively ([#25654]).

* `Compat.indexin` accepts any iterable as first argument, returns `nothing` (rather than `0`)
for entries with no match and gives the index of the first (rather than the last) match
for entries with no match and gives the index of the first (rather than the last) match
([#25662], [#25998]).

* `isabstract` and `isleaftype` are now `isabstracttype` and `isconcretetype`, respectively
Expand Down Expand Up @@ -532,7 +533,6 @@ includes this fix. Find the minimum version from there.
[#23642]: https://github.com/JuliaLang/julia/issues/23642
[#23666]: https://github.com/JuliaLang/julia/issues/23666
[#23757]: https://github.com/JuliaLang/julia/issues/23757
[#23812]: https://github.com/JuliaLang/julia/issues/23812
[#23931]: https://github.com/JuliaLang/julia/issues/23931
[#24047]: https://github.com/JuliaLang/julia/issues/24047
[#24182]: https://github.com/JuliaLang/julia/issues/24182
Expand Down Expand Up @@ -599,4 +599,5 @@ includes this fix. Find the minimum version from there.
[#26149]: https://github.com/JuliaLang/julia/issues/26149
[#26156]: https://github.com/JuliaLang/julia/issues/26156
[#26316]: https://github.com/JuliaLang/julia/issues/26316
[#26442]: https://github.com/JuliaLang/julia/issues/26442
[#26436]: https://github.com/JuliaLang/julia/issues/26436
[#26442]: https://github.com/JuliaLang/julia/issues/26442
83 changes: 43 additions & 40 deletions src/Compat.jl
Original file line number Diff line number Diff line change
Expand Up @@ -868,27 +868,39 @@ else
import Serialization
end

# 0.7.0-DEV.1993
@static if !isdefined(Base, :EqualTo)
if VERSION >= v"0.6.0"
include_string(@__MODULE__, """
struct EqualTo{T} <: Function
x::T
@static if VERSION < v"0.7.0-DEV.4592"
struct Fix2{F,T} <: Function
f::F
x::T
Fix2(f::F, x::T) where {F,T} = new{F,T}(f, x)
Fix2(f::Type{F}, x::T) where {F,T} = new{F,T}(f, x)
end
(f::Fix2)(y) = f.f(y, f.x)

EqualTo(x::T) where {T} = new{T}(x)
end
""")
Base.:(==)(x) = Fix2(==, x)
@static if VERSION >= v"0.7.0-DEV.1993"
Base.isequal(x) = Base.equalto(x)
else
include_string(@__MODULE__, """
immutable EqualTo{T} <: Function
x::T
end
""")
Base.isequal(x) = Fix2(isequal, x)
end
@static if VERSION >= v"0.7.0-DEV.3272"
Base.in(x) = Base.occursin(x)
else
Base.in(x) = Fix2(in, x)
end
(f::EqualTo)(y) = isequal(f.x, y)
const equalto = EqualTo
end
# keep these definitions to be non breaking for 0.6 usage
@static if VERSION < v"0.7.0-DEV.1993"
const EqualTo{T} = Fix2{typeof(isequal),T}
export equalto
equalto(x) = isequal(x)
end
@static if VERSION < v"0.7.0-DEV.3272"
const OccursIn{T} = Fix2{typeof(in),T}
export occursin
occursin(x) = in(x)
end


# 0.7.0-DEV.912
if VERSION < v"0.7.0-DEV.912"
Expand Down Expand Up @@ -1486,15 +1498,6 @@ end
findprev(xs...) = Base.findprev(xs...)
findlast(xs...) = Base.findlast(xs...)
else
struct OccursIn{T} <: Function
x::T

OccursIn(x::T) where {T} = new{T}(x)
end
(f::OccursIn)(y) = y in f.x
const occursin = OccursIn
export occursin

zero2nothing(x::Integer) = x == 0 ? nothing : x
zero2nothing(x::AbstractUnitRange{<:Integer}) = x == 0:-1 ? nothing : x
zero2nothing(x) = x
Expand All @@ -1506,41 +1509,41 @@ else

Base.findnext(r::Regex, s::AbstractString, idx::Integer) = search(s, r, idx)
Base.findfirst(r::Regex, s::AbstractString) = search(s, r)
Base.findnext(c::EqualTo{Char}, s::AbstractString, i::Integer) = search(s, c.x, i)
Base.findfirst(c::EqualTo{Char}, s::AbstractString) = search(s, c.x)
Base.findnext(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) =
Base.findnext(c::Fix2{typeof(isequal),Char}, s::AbstractString, i::Integer) = search(s, c.x, i)
Base.findfirst(c::Fix2{typeof(isequal),Char}, s::AbstractString) = search(s, c.x)
Base.findnext(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) =
search(a, b.x, i)
Base.findfirst(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) =
Base.findfirst(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) =
search(a, b.x)

Base.findnext(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
Base.findnext(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
s::AbstractString, i::Integer) =
search(s, c.x, i)
Base.findfirst(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
Base.findfirst(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
s::AbstractString) =
search(s, c.x)
Base.findnext(t::AbstractString, s::AbstractString, i::Integer) = search(s, t, i)
Base.findfirst(t::AbstractString, s::AbstractString) = search(s, t)

Base.findfirst(delim::EqualTo{UInt8}, buf::Base.IOBuffer) = search(buf, delim.x)
Base.findfirst(delim::Fix2{typeof(isequal),UInt8}, buf::Base.IOBuffer) = search(buf, delim.x)

Base.findprev(c::EqualTo{Char}, s::AbstractString, i::Integer) = rsearch(s, c.x, i)
Base.findlast(c::EqualTo{Char}, s::AbstractString) = rsearch(s, c.x)
Base.findprev(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) =
Base.findprev(c::Fix2{typeof(isequal),Char}, s::AbstractString, i::Integer) = rsearch(s, c.x, i)
Base.findlast(c::Fix2{typeof(isequal),Char}, s::AbstractString) = rsearch(s, c.x)
Base.findprev(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}, i::Integer) =
rsearch(a, b.x, i)
Base.findlast(b::EqualTo{<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) =
Base.findlast(b::Fix2{typeof(isequal),<:Union{Int8,UInt8}}, a::Vector{<:Union{Int8,UInt8}}) =
rsearch(a, b.x)

Base.findprev(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
Base.findprev(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
s::AbstractString, i::Integer) = rsearch(s, c.x, i)
Base.findlast(c::OccursIn{<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
Base.findlast(c::Fix2{typeof(in),<:Union{Tuple{Vararg{Char}},AbstractVector{Char},Set{Char}}},
s::AbstractString) = rsearch(s, c.x)
Base.findprev(t::AbstractString, s::AbstractString, i::Integer) = rsearch(s, t, i)
Base.findlast(t::AbstractString, s::AbstractString) = rsearch(s, t)

findall(b::OccursIn, a) = findin(a, b.x)
findall(b::Fix2{typeof(in)}, a) = findin(a, b.x)
# To fix ambiguity
findall(b::OccursIn, a::Number) = a in b.x ? [1] : Vector{Int}()
findall(b::Fix2{typeof(in)}, a::Number) = a in b.x ? [1] : Vector{Int}()
end

@static if VERSION < v"0.7.0-DEV.4047" #26089
Expand Down
65 changes: 46 additions & 19 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -947,13 +947,26 @@ module Test24648
end

let a = [0,1,2,3,0,1,2,3]
@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 findnext(equalto(1), a, 4) == 6
# @test findnext(equalto(5), a, 4) == 0
@test findlast(equalto(3), [1,2,4,1,2,3,4]) == 6
@test findprev(equalto(1), a, 4) == 2
@test findprev(equalto(1), a, 8) == 6
# curried isequal
@test findfirst(isequal(3), [1,2,4,1,2,3,4]) == 6
@test findfirst(!isequal(1), [1,2,4,1,2,3,4]) == 2
@test findnext(isequal(1), a, 4) == 6
# @test findnext(isequal(5), a, 4) == 0
@test findlast(isequal(3), [1,2,4,1,2,3,4]) == 6
@test findprev(isequal(1), a, 4) == 2
@test findprev(isequal(1), a, 8) == 6
if VERSION < v"0.7.0-DEV.4592"
# test that equalto work on 0.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
end
# curried ==
@test findfirst(==(3), [1,2,4,1,2,3,4]) == 6
@test findfirst(!(==(1)), [1,2,4,1,2,3,4]) == 2
@test findnext(==(1), a, 4) == 6
@test findlast(==(3), [1,2,4,1,2,3,4]) == 6
@test findprev(==(1), a, 4) == 2
@test findprev(==(1), a, 8) == 6
end

# 0.7
Expand Down Expand Up @@ -1358,24 +1371,34 @@ end
for (f1, f2, i) in ((Compat.findfirst, Compat.findnext, 1),
(Compat.findlast, Compat.findprev, 2))
# Generic methods
@test f1(equalto(0), [1, 0]) == f2(equalto(0), [1, 0], i) == 2
@test f1(equalto(9), [1, 0]) == f2(equalto(9), [1, 0], i) == nothing
@test f1(occursin([0, 2]), [1, 0]) == f2(occursin([0, 2]), [1, 0], i) == 2
@test f1(occursin([0, 2]), [1, 9]) == f2(occursin([0, 2]), [1, 9], i) == nothing
@test f1(isequal(0), [1, 0]) == f2(isequal(0), [1, 0], i) == 2
@test f1(isequal(9), [1, 0]) == f2(isequal(9), [1, 0], i) == nothing
@test f1(in([0, 2]), [1, 0]) == f2(in([0, 2]), [1, 0], i) == 2
@test f1(in([0, 2]), [1, 9]) == f2(in([0, 2]), [1, 9], i) == nothing
if VERSION < v"0.7.0-DEV.4592"
# test that occursin work on 0.6
@test f1(occursin([0, 2]), [1, 0]) == f2(occursin([0, 2]), [1, 0], i) == 2
@test f1(occursin([0, 2]), [1, 9]) == f2(occursin([0, 2]), [1, 9], i) == nothing
end
@test f1([true, false]) == f2([true, false], i) == 1
@test f1([false, false]) == f2([false, false], i) == nothing

# Specific methods
@test f2(equalto('a'), "ba", i) == f1(equalto('a'), "ba") == 2
@test f2(isequal('a'), "ba", i) == f1(isequal('a'), "ba") == 2
for S in (Int8, UInt8), T in (Int8, UInt8)
# Bug in Julia 0.6
f1 === Compat.findlast && VERSION < v"0.7.0-DEV.3272" && continue
@test f2(equalto(S(1)), T[0, 1], i) == f1(equalto(S(1)), T[0, 1]) == 2
@test f2(equalto(S(9)), T[0, 1], i) == f1(equalto(S(9)), T[0, 1]) == nothing
@test f2(isequal(S(1)), T[0, 1], i) == f1(isequal(S(1)), T[0, 1]) == 2
@test f2(isequal(S(9)), T[0, 1], i) == f1(isequal(S(9)), T[0, 1]) == nothing
end
for chars in (['a', 'z'], Set(['a', 'z']), ('a', 'z'))
@test f2(occursin(chars), "ba", i) == f1(occursin(chars), "ba") == 2
@test f2(occursin(chars), "bx", i) == f1(occursin(chars), "bx") == nothing
@test f2(in(chars), "ba", i) == f1(in(chars), "ba") == 2
@test f2(in(chars), "bx", i) == f1(in(chars), "bx") == nothing
if VERSION < v"0.7.0-DEV.4592"
# test that occursin work on 0.6
@test f2(occursin(chars), "ba", i) == f1(occursin(chars), "ba") == 2
@test f2(occursin(chars), "bx", i) == f1(occursin(chars), "bx") == nothing
end
end
end
@test findnext("a", "ba", 1) == findfirst("a", "ba") == 2:2
Expand All @@ -1392,11 +1415,15 @@ end
@test Compat.findnext(r"a", "ba", 1) == Compat.findfirst(r"a", "ba") == 2:2
@test Compat.findnext(r"z", "ba", 1) == Compat.findfirst(r"z", "ba") == nothing

@test Compat.findfirst(equalto(UInt8(0)), IOBuffer(UInt8[1, 0])) == 2
@test Compat.findfirst(equalto(UInt8(9)), IOBuffer(UInt8[1, 0])) == nothing
@test Compat.findfirst(isequal(UInt8(0)), IOBuffer(UInt8[1, 0])) == 2
@test Compat.findfirst(isequal(UInt8(9)), IOBuffer(UInt8[1, 0])) == nothing

@test findall([true, false, true]) == [1, 3]
@test findall(occursin([1, 2]), [1]) == [1]
@test findall(in([1, 2]), [1]) == [1]
if VERSION < v"0.7.0-DEV.4592"
# test that occursin work on 0.6
@test findall(occursin([1, 2]), [1]) == [1]
end

# 0.7.0-DEV.3666
module TestUUIDs
Expand Down

0 comments on commit 004d8f9

Please sign in to comment.