Revision bc7ba3d5c8b2dab1c0e19537739b67c2da902d11 authored by Keno Fischer on 20 March 2024, 06:35:46 UTC, committed by GitHub on 20 March 2024, 06:35:46 UTC
This passes slightly more information into this function (the full
`inst` rather than just the `stmt`) in order to allow external absint to
access additional fields (the flags and the info) if necessary to make
concrete evaluation decisions. It also splits out the actual concrete
evaluation from the part that just maps the `inst` to a CodeInstance.
1 parent e0bb95a
Raw File
sets.jl
# This file is a part of Julia. License is MIT: https://julialang.org/license

# Set tests
isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl")
using .Main.OffsetArrays

using Dates

@testset "Construction, collect" begin
    @test Set([1,2,3]) isa Set{Int}
    @test Set{Int}([3]) isa Set{Int}
    data_in = (1,"banana", ())
    s = Set(data_in)
    data_out = collect(s)
    @test s isa Set{Any}
    @test data_out isa Array{Any,1}
    @test all(map(in(data_out), data_in))
    @test length(data_out) == length(data_in)
    let f17741 = x -> x < 0 ? false : 1
        @test isa(Set(x for x = 1:3), Set{Int})
        @test isa(Set(x for x = 1:3 for j = 1:1), Set{Int})
        @test isa(Set(sin(x) for x = 1:3), Set{Float64})
        @test isa(Set(f17741(x) for x = 1:3), Set{Int})
        @test isa(Set(f17741(x) for x = -1:1), Set{Integer})
        @test isa(Set(f17741(x) for x = 1:0), Set{Integer})
    end
    let s1 = Set(["foo", "bar"]), s2 = Set(s1)
        @test s1 == s2
        x = pop!(s1)
        @test s1 != s2
        @test !(x in s1)
        @test x in s2
        push!(s1, "baz")
        push!(s2, "baz2")
        @test "baz" in s1
        @test !("baz" in s2)
        @test !("baz2" in s1)
        @test "baz2" in s2
    end
end

@testset "hash" begin
    s1 = Set(["bar", "foo"])
    s2 = Set(["foo", "bar"])
    s3 = Set(["baz"])
    @test hash(s1) == hash(s2)
    @test hash(s1) != hash(s3)
    d1 = Dict(Set([3]) => 33, Set([2]) => 22)
    d2 = Dict(Set([2]) => 33, Set([3]) => 22)
    @test hash(d1) != hash(d2)
end

@testset "equality" for eq in (isequal, ==)
    @test  eq(Set(), Set())
    @test !eq(Set(), Set([1]))
    @test  eq(Set{Any}(Any[1,2]), Set{Int}([1,2]))
    @test !eq(Set{Any}(Any[1,2]), Set{Int}([1,2,3]))

    # Comparison of unrelated types
    @test  eq(Set{Int}(), Set{AbstractString}())
    @test !eq(Set{Int}(), Set{AbstractString}([""]))
    @test !eq(Set{AbstractString}(), Set{Int}([0]))
    @test !eq(Set{Int}([1]), Set{AbstractString}())
    @test  eq(Set{Any}([1,2,3]), Set{Int}([1,2,3]))
    @test  eq(Set{Int}([1,2,3]), Set{Any}([1,2,3]))
    @test !eq(Set{Any}([1,2,3]), Set{Int}([1,2,3,4]))
    @test !eq(Set{Int}([1,2,3]), Set{Any}([1,2,3,4]))
    @test !eq(Set{Any}([1,2,3,4]), Set{Int}([1,2,3]))
    @test !eq(Set{Int}([1,2,3,4]), Set{Any}([1,2,3]))

    # Special cases
    @test  eq(Set([-0.0]), Set([-0.0]))
    @test !eq(Set([0.0]), Set([-0.0]))
    @test  eq(Set([NaN]), Set([NaN]))
    @test !eq(Set([NaN]), Set([1.0]))
    @test  eq(Set([missing]), Set([missing]))
    @test !eq(Set([missing]), Set([1]))
end

@testset "hash and == for Set/BitSet" begin
    for s = (Set([1]), Set(1:10), Set(-100:7:100))
        b = BitSet(s)
        @test hash(s) == hash(b)
        @test s == b
    end
end

@testset "eltype, empty" begin
    s1 = empty(Set([1,"hello"]))
    @test isequal(s1, Set())
    @test ===(eltype(s1), Any)
    s2 = empty(Set{Float32}([2.0f0,3.0f0,4.0f0]))
    @test isequal(s2, Set())
    @test ===(eltype(s2), Float32)
    s3 = empty(Set([1,"hello"]),Float32)
    @test isequal(s3, Set())
    @test ===(eltype(s3), Float32)
end
@testset "show" begin
    @test sprint(show, Set()) == "Set{Any}()"
    @test repr([Set(),Set()]) == "Set{Any}[Set(), Set()]"
    @test sprint(show, Set(['a'])) == "Set(['a'])"
end
@testset "isempty, length, in, push, pop, delete" begin
    # also test for no duplicates
    s = Set(); push!(s,1); push!(s,2); push!(s,3)
    @test !isempty(s)
    @test in(1,s)
    @test in(2,s)
    @test length(s) == 3
    push!(s,1); push!(s,2); push!(s,3)
    @test length(s) == 3
    @test pop!(s,1) == 1
    @test !in(1,s)
    @test in(2,s)
    @test length(s) == 2
    @test_throws KeyError pop!(s,1)
    @test pop!(s,1,:foo) === :foo
    @test length(delete!(s,2)) == 1
    @test !in(1,s)
    @test !in(2,s)
    @test pop!(s) == 3
    @test length(s) == 0
    @test isempty(s)
    @test_throws ArgumentError pop!(s)
    @test length(Set(['x',120])) == 2

    # Test that pop! returns the element in the set, not the query
    s = Set{Any}(Any[0x01, UInt(2), 3, 4.0])
    @test pop!(s, 1) === 0x01
    @test pop!(s, 2) === UInt(2)
    @test pop!(s, 3) === 3
    @test pop!(s, 4) === 4.0
    @test_throws KeyError pop!(s, 5)
end

@testset "in!" begin
    s = Set()
    @test !(in!(0x01, s))
    @test !(in!(Int32(2), s))
    @test in!(1, s)
    @test in!(2.0, s)
    (a, b, c...) = sort!(collect(s))
    @test a === 0x01
    @test b === Int32(2)
    @test isempty(c)

    # in! will convert to the right type automatically
    s = Set{Int32}()
    @test !(in!(1, s))
    @test only(s) === Int32(1)
    @test_throws Exception in!("hello", s)

    # Other set types
    s = BitSet()
    @test !(in!(13, s))
    @test in!(UInt16(13), s)
    @test only(s) === 13
end

@testset "copy" begin
    data_in = (1,2,9,8,4)
    s = Set(data_in)
    c = copy(s)
    @test isequal(s,c)
    v = pop!(s)
    @test !in(v,s)
    @test  in(v,c)
    push!(s,100)
    push!(c,200)
    @test !in(100,c)
    @test !in(200,s)
end

@testset "copy(::KeySet) (issue #41537)" begin
    @test union(keys(Dict(1=>2, 3=>4))) == copy(keys(Dict(1=>2, 3=>4))) == Set([1,3])
end

@testset "copy!" begin
    for S = (Set, BitSet)
        s = S([1, 2])
        for a = ([1], UInt[1], [3, 4, 5], UInt[3, 4, 5])
            @test s === copy!(s, Set(a)) == S(a)
            @test s === copy!(s, BitSet(a)) == S(a)
        end
    end
    s = Set([1, 2])
    s2 = copy(s)
    @test copy!(s, s) == s2
end

@testset "sizehint, empty" begin
    s = Set([1])
    @test isequal(sizehint!(s, 10), Set([1]))
    @test isequal(empty!(s), Set())
    s2 = GenericSet(s)
    sizehint!(s2, 10)
    @test s2 == GenericSet(s)
end

@testset "shrinking" begin # Similar test as for the underlying Dict
    d = Set(i for i = 1:1000)
    filter!(x -> x < 10, d)
    sizehint!(d, 10)
    @test length(d.dict.slots) < 100
    sizehint!(d, 1000)
    sizehint!(d, 1; shrink = false)
    @test length(d.dict.slots) >= 1000
    sizehint!(d, 1; shrink = true)
    @test length(d.dict.slots) < 1000
end

@testset "rehash!" begin
    # Use a pointer type to have defined behavior for uninitialized
    # array element
    s = Set(["a", "b", "c"])
    Base.rehash!(s)
    k = s.dict.keys
    Base.rehash!(s)
    @test length(k) == length(s.dict.keys)
    for i in 1:length(k)
        if isassigned(k, i)
            @test k[i] == s.dict.keys[i]
        else
            @test !isassigned(s.dict.keys, i)
        end
    end
    @test s == Set(["a", "b", "c"])
end

@testset "start, done, next" begin
    for data_in in ((7, 8, 4, 5),
                  ("hello", 23, 2.7, (), [], (1, 8)))
        local data_in, s, t
        s = Set(data_in)

        s_new = Set()
        for el in s
            push!(s_new, el)
        end
        @test isequal(s, s_new)

        t = tuple(s...)
        @test length(t) == length(s)
        for e in t
            @test in(e,s)
        end
    end
end

@testset "union" begin
    for S in (Set, BitSet, Vector)
        s = ∪(S([1,2]), S([3,4]))
        @test s == S([1,2,3,4])
        s = union(S([5,6,7,8]), S([7,8,9]))
        @test s == S([5,6,7,8,9])
        s = S([1,3,5,7])
        union!(s, (2,3,4,5))
        @test s == S([1,3,5,7,2,4]) # order matters for Vector
        let s1 = S([1, 2, 3])
            @test s1 !== union(s1) == s1
            @test s1 !== union(s1, 2:4) == S([1,2,3,4])
            @test s1 !== union(s1, [2,3,4]) == S([1,2,3,4])
            @test s1 !== union(s1, [2,3,4], S([5])) == S([1,2,3,4,5])
            @test s1 === union!(s1, [2,3,4], S([5])) == S([1,2,3,4,5])
        end
    end
    @test union(Set([1]), BitSet()) isa Set{Int}
    @test union(BitSet([1]), Set()) isa BitSet
    @test union([1], BitSet()) isa Vector{Int}
    # union must uniquify
    @test union([1, 2, 1]) == union!([1, 2, 1]) == [1, 2]
    @test union([1, 2, 1], [2, 2]) == union!([1, 2, 1], [2, 2]) == [1, 2]
    s2 = Set([nothing])
    union!(s2, [nothing])
    @test s2 == Set([nothing])

    @testset "promotion" begin
        ints = [1:5, [1, 2], Set([1, 2])]
        floats = [2:0.1:3, [2.0, 3.5], Set([2.0, 3.5])]

        for a in ints, b in floats
            @test eltype(union(a, b)) == Float64
            @test eltype(union(b, a)) == Float64
        end
    end
end

@testset "intersect" begin
    for S in (Set, BitSet, Vector)
        s = S([1,2]) ∩ S([3,4])
        @test s == S()
        s = intersect(S([5,6,7,8]), S([7,8,9]))
        slong = S(collect(3:63))
        # test #36339 length/order short-cut
        @test intersect(S([5,6,7,8]), slong) == intersect(slong, S([5,6,7,8]))
        @test s == S([7,8])
        @test intersect(S([2,3,1]), S([4,2,3]), S([5,4,3,2])) == S([2,3])
        let s1 = S([1,2,3])
            @test s1 !== intersect(s1) == s1
            @test s1 !== intersect(s1, 2:10) == S([2,3])
            @test s1 !== intersect(s1, [2,3,4]) == S([2,3])
            @test s1 !== intersect(s1, [2,3,4], 3:4) == S([3])
            @test s1 === intersect!(s1, [2,3,4], 3:4) == S([3])
        end
    end
    @test intersect(Set([1]), BitSet()) isa Set{Int}
    @test intersect(BitSet([1]), Set()) isa Set{Any}
    @test intersect(BitSet([1]), Set([1])) isa BitSet
    @test intersect(BitSet([1]), Set([1]), Set([1])) isa BitSet
    @test intersect([1], BitSet()) isa Vector{Int}
    # intersect must uniquify
    @test intersect([1, 2, 1]) == intersect!([1, 2, 1]) == [1, 2]
    @test intersect([1, 2, 1], [2, 2]) == intersect!([1, 2, 1], [2, 2]) == [2]

    # issue #25801
    x = () ∩ (:something,)
    y = () ∩ (42,)
    @test isempty(x)
    @test isempty(y)

    # Discussed in PR#41769
    @testset "promotion" begin
        ints = [1:5, [1, 2], Set([1, 2])]
        floats = [2:0.1:3, [2.0, 3.5], Set([2.0, 3.5])]

        for a in ints, b in floats
            @test eltype(intersect(a, b)) == Float64
            @test eltype(intersect(b, a)) == Float64
            @test eltype(intersect(a, a, b)) == Float64
        end
    end

    # 3-argument version is correctly covered
    @test intersect(Set([1,2]), Set([2]), Set([1,2,3])) == Set([2])
    @test intersect(Set([1,2]), Set([2]), Set([1.,2,3])) == Set([2.])
end

@testset "setdiff" begin
    for S in (Set, BitSet, Vector)
        @test setdiff(S([1,2,3]), S())        == S([1,2,3])
        @test setdiff(S([1,2,3]), S([1]))     == S([2,3])
        @test setdiff(S([1,2,3]), S([1,2]))   == S([3])
        @test setdiff(S([1,2,3]), S([1,2,3])) == S()
        @test setdiff(S([1,2,3]), S([4]))     == S([1,2,3])
        @test setdiff(S([1,2,3]), S([4,1]))   == S([2,3])
        let s1 = S([1, 2, 3])
            @test s1 !== setdiff(s1) == s1
            @test s1 !== setdiff(s1, 2:10) == S([1])
            @test s1 !== setdiff(s1, [2,3,4]) == S([1])
            @test s1 !== setdiff(s1, S([2,3,4]), S([1])) == S()
            @test s1 === setdiff!(s1, S([2,3,4]), S([1])) == S()
        end
    end

    @test setdiff(Set([1]), BitSet()) isa Set{Int}
    @test setdiff(BitSet([1]), Set()) isa BitSet
    @test setdiff([1], BitSet()) isa Vector{Int}
    # setdiff must uniquify
    @test setdiff([1, 2, 1]) == setdiff!([1, 2, 1]) == [1, 2]
    @test setdiff([1, 2, 1], [2, 2]) == setdiff!([1, 2, 1], [2, 2]) == [1]

    s = Set([1,3,5,7])
    setdiff!(s,(3,5))
    @test isequal(s,Set([1,7]))
    s = Set([1,2,3,4])
    setdiff!(s, Set([2,4,5,6]))
    @test isequal(s,Set([1,3]))

    # setdiff iterates the shorter set - make sure this algorithm works
    sa, sb = Set([1,2,3,4,5,6,7]), Set([2,3,9])
    @test Set([1,4,5,6,7]) == setdiff(sa, sb) !== sa
    @test Set([1,4,5,6,7]) == setdiff!(sa, sb) === sa
    sa, sb = Set([1,2,3,4,5,6,7]), Set([2,3,9])
    @test Set([9]) == setdiff(sb, sa) !== sb
    @test Set([9]) == setdiff!(sb, sa) === sb
end

@testset "ordering" begin
    @test Set() < Set([1])
    @test Set([1]) < Set([1,2])
    @test !(Set([3]) < Set([1,2]))
    @test !(Set([3]) > Set([1,2]))
    @test Set([1,2,3]) > Set([1,2])
    @test !(Set([3]) <= Set([1,2]))
    @test !(Set([3]) >= Set([1,2]))
    @test Set([1]) <= Set([1,2])
    @test Set([1,2]) <= Set([1,2])
    @test Set([1,2]) >= Set([1,2])
    @test Set([1,2,3]) >= Set([1,2])
    @test !(Set([1,2,3]) >= Set([1,2,4]))
    @test !(Set([1,2,3]) <= Set([1,2,4]))
end

@testset "issubset, symdiff, isdisjoint" begin
    for S in (Set, BitSet, Vector)
        for (l,r) in ((S([1,2]),     S([3,4])),
                      (S([5,6,7,8]), S([7,8,9])),
                      (S([1,2]),     S([3,4])),
                      (S([5,6,7,8]), S([7,8,9])),
                      (S([1,2,3]),   S()),
                      (S(),          S()),
                      (S(),          S([1,2,3])),
                      (S([1,2,3]),   S([1])),
                      (S([1,2,3]),   S([1,2])),
                      (S([1,2,3]),   S([1,2,3])),
                      (S([1,2,3]),   S([4])),
                      (S([1,2,3]),   S([4,1])))
            @test issubset(intersect(l,r), l)
            @test issubset(intersect(l,r), r)
            @test issubset(l, union(l,r))
            @test issubset(r, union(l,r))
            @test issubset(union(l,r))(r)
            @test isdisjoint(l,l) == isempty(l)
            @test isdisjoint(l)(l) == isempty(l)
            @test isdisjoint(l,r) == isempty(intersect(l,r))
            if S === Vector
                @test sort(union(intersect(l,r),symdiff(l,r))) == sort(union(l,r))
            else
                @test union(intersect(l,r),symdiff(l,r)) == union(l,r)
            end
        end
        if S !== Vector
            @test ⊆(S([1]), S([1,2]))
            @test ⊊(S([1]), S([1,2]))
            @test !⊊(S([1]), S([1]))
            @test ⊈(S([1]), S([2]))
            @test ⊇(S([1,2]), S([1]))
            @test ⊋(S([1,2]), S([1]))
            @test !⊋(S([1]), S([1]))
            @test ⊉(S([1]), S([2]))

            @test ⊆(S([1,2]))(S([1]))
            @test ⊊(S([1,2]))(S([1]))
            @test !⊊(S([1]))(S([1]))
            @test ⊈(S([2]))(S([1]))
            @test ⊇(S([1]))(S([1,2]))
            @test ⊋(S([1]))(S([1,2]))
            @test !⊋(S([1]))(S([1]))
            @test ⊉(S([2]))(S([1]))
        end
        let s1 = S([1,2,3,4])
            @test s1 !== symdiff(s1) == s1
            @test s1 !== symdiff(s1, S([2,4,5,6])) == S([1,3,5,6])
            @test s1 !== symdiff(s1, S([2,4,5,6]), [1,6,7]) == S([3,5,7])
            @test s1 === symdiff!(s1, S([2,4,5,6]), [1,6,7]) == S([3,5,7])
        end
    end
    @test symdiff(Set([1,2,3,4]), Set([2,4,5,6])) == Set([1,3,5,6])
    @test symdiff(Set([1]), BitSet()) isa Set{Int}
    @test symdiff(BitSet([1]), Set{Int}()) isa BitSet
    @test symdiff([1], BitSet()) isa Vector{Int}
    #symdiff does uniquify
    @test symdiff([1, 2, 1]) == symdiff!([1, 2, 1]) == [1,2]
    @test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [1]
    @test symdiff([1, 2, 1], [2, 2]) == symdiff!([1, 2, 1], [2, 2]) == [1]

    # Base.hasfastin
    @test all(Base.hasfastin, Any[Dict(1=>2), Set(1), BitSet(1), 1:9, 1:2:9,
                                  Dict, Set, BitSet, UnitRange, StepRange])
    @test !any(Base.hasfastin, Any[[1, 2, 3], "123",
                                   Array, String])

    # tests for Dict
    d1 = Dict(1=>nothing, 2=>nothing)
    d2 = Dict(1=>nothing, 3=>nothing)
    d3 = Dict(1=>nothing, 2=>nothing, 3=>nothing)
    @test d3 == merge(d1, d2)
    @test !issubset(d1, d2)
    @test !issubset(d2, d1)
    @test !issubset(d3, d1)
    @test !issubset(d3, d2)
    @test issubset(d1, d3)
    @test issubset(d2, d3)

    # no fast in, long enough container
    @test issubset(Set(Bool[]), rand(Bool, 100)) == true
    # neither has a fast in, right doesn't have a length
    @test isdisjoint([1, 3, 5, 7, 9], Iterators.filter(iseven, 1:10))

    # range fast-path
    for (truth, a, b) in (
                   # Integers
                   (true, 1:10, 11:20), # not overlapping
                   (false, 1:10, 5:20), # partial overlap
                   (false, 5:9, 1:10), # complete overlap
                   # complete overlap, unequal steps
                   (false, 3:6:60, 9:9:60),
                   (true, 4:6:60, 9:9:60),
                   (true, 0:6:12, 9:9:60),
                   (false, 6:6:18, 9:9:60),
                   (false, 12:6:18, 9:9:60),
                   (false, 18:6:18, 9:9:60),
                   (true, 1:2:3, 2:3:5),
                   (true, 1:4:5, 2:1:4),
                   (false, 4:12:124, 1:1:8),
                   # potential overflow
                   (false, 0x1:0x3:0x4, 0x4:0x3:0x4),
                   (true, 0x3:0x3:0x6, 0x4:0x3:0x4),
                   (false, typemax(Int8):Int8(3):typemax(Int8), typemin(Int8):Int8(3):typemax(Int8)),
                   # Chars
                   (true, 'a':'l', 'o':'p'), # not overlapping
                   (false, 'a':'l', 'h':'p'), # partial overlap
                   (false, 'a':'l', 'c':'e'), # complete overlap
                   # Floats
                   (true, 1.:10., 11.:20.), # not overlapping
                   (false, 1.:10., 5.:20.), # partial overlap
                   (false, 5.:9., 1.:10.), # complete overlap
                   # Inputs that may hang
                   (false, -6011687643038262928:3545293653953105048, -6446834672754204848:3271267329311042532),
                   )
        @test isdisjoint(a, b) == truth
        @test isdisjoint(b, a) == truth
        @test isdisjoint(a, reverse(b)) == truth
        @test isdisjoint(reverse(a), b) == truth
        @test isdisjoint(b, reverse(a)) == truth
        @test isdisjoint(reverse(b), a) == truth
    end
    @test isdisjoint(10:9, 1:10) # empty range
    @test !isdisjoint(1e-100:.1:1, 0:.1:1)
    @test !isdisjoint(eps()/4:.1:.71, 0:.1:1)
end

@testset "unique" begin
    u = @inferred(unique([1, 1, 2]))
    @test in(1, u)
    @test in(2, u)
    @test length(u) == 2
    @test unique(iseven, []) == []
    # type promotion
    @test unique(x -> x^2, [1, 3.]) == [1, 3.]
    @test @inferred(unique(iseven, [5, 1, 8, 9, 3, 4, 10, 7, 2, 6])) == [5, 8]
    @test @inferred(unique(x->x^2, Integer[3, -4, 5, 4])) == Integer[3, -4, 5]
    @test @inferred(unique(iseven, Integer[3, -4, 5, 4]; seen=Set{Bool}())) == Integer[3, -4]
    @test @inferred(unique(n -> n % 3, [5, 1, 8, 9, 3, 4, 10, 7, 2, 6])) == [5, 1, 9]
    for r = (Base.OneTo(-1), Base.OneTo(0), Base.OneTo(1), Base.OneTo(5),
             1:0, 1:1, 1:2, 1:10, 1:.5:.5, 1:.5:1, 1:.5:10, 3:-2:5, 3:-2:3, 3:-2:1,
             StepRangeLen(1.0, 2.0, 0), StepRangeLen(1.0, 2.0, 2), StepRangeLen(1.0, 2.0, 3),
             StepRangeLen(1.0, 0.0, 0), StepRangeLen(1.0, -0.0, 1), StepRangeLen(1.0, 0.0, 2),
             LinRange(1, 2, 3), LinRange(1, 1, 0), LinRange(1, 1, 1), LinRange(1, 1, 10))
        @test @inferred(unique(r)) == invoke(unique, Tuple{Any}, r)
    end
end

@testset "issue 20105" begin
    @test @inferred(unique(x for x in 1:1)) == [1]
    @test unique(x for x in Any[1, 1.0])::Vector{Real} == [1]
    @test unique(x for x in Real[1, 1.0])::Vector{Real} == [1]
    @test @inferred(unique(Integer[1, 1, 2]))::Vector{Integer} == [1, 2]
    @test unique(x for x in []) isa Vector{Any}
end

@testset "unique!" begin
    u = []
    @test unique!(u) === u
    u = [1,1,3,2,1]
    @inferred(unique!(u))
    @test u == [1,3,2]
    @test @inferred(unique!([])) == []
    @test @inferred(unique!(Float64[])) == Float64[]
    u = [1,2,2,3,5,5]
    @test unique!(u) === u
    @test u == [1,2,3,5]
    u = [6,5,5,3,3,2,1]
    @test unique!(u) === u
    @test u == [6,5,3,2,1]
    u = OffsetArray([1,2,2,3,5,5], -1)
    @test unique!(u) === u
    @test u == OffsetArray([1,2,3,5], -1)
    u = OffsetArray([5,5,4,4,2,2,0,-1,-1], -1)
    @test unique!(u) === u
    @test u == OffsetArray([5,4,2,0,-1], -1)
    u = OffsetArray(["w","we","w",5,"r",5,5], -1)
    @test unique!(u) === u
    @test u == OffsetArray(["w","we",5,"r"], -1)
    u = [0.0,-0.0,1.0,2]
    @test unique!(u) === u
    @test u == [0.0,-0.0,1.0,2.0]
    u = [1,NaN,NaN,3]
    @test unique!(u) === u
    @test u[1] == 1
    @test isnan(u[2])
    @test u[3] == 3
    u = [5,"w","we","w","r",5,"w"]
    unique!(u)
    @test u == [5,"w","we","r"]
    u = [1,2,5,1,3,2]
    @test unique!(x -> x ^ 2, [1, -1, 3, -3, 5, -5]) == [1, 3, 5]
    @test unique!(n -> n % 3, [5, 1, 8, 9, 3, 4, 10, 7, 2, 6]) == [5, 1, 9]
    @test @inferred(unique!(iseven, [2, 3, 5, 7, 9])) == [2, 3]
    @test @inferred(unique!(x -> x % 2 == 0 ? :even : :odd, [1, 2, 3, 4, 2, 2, 1])) == [1, 2]
    @test @inferred(unique!(x -> x % 2 == 0 ? :even : "odd", [1, 2, 3, 4, 2, 2, 1]; seen=Set{Union{Symbol,String}}())) == [1, 2]

    @test isempty(unique!(Union{}[]))
    @test eltype(unique!([i for i in ["1"] if i isa Int])) <: Union{}
end

@testset "allunique" begin
    @test allunique([])
    @test allunique(Set())
    @test allunique([1,2,3])
    @test allunique([1 2; 3 4])
    @test allunique([:a,:b,:c])
    @test allunique(Set([1,2,3]))
    @test !allunique([1,1,2])
    @test !allunique([:a,:b,:c,:a])
    @test allunique(unique(randn(100)))  # longer than 32
    @test allunique(collect(1:100)) # sorted/unique && longer than 32
    @test allunique(collect(100:-1:1)) # sorted/unique && longer than 32
    @test !allunique(fill(1,100)) # sorted/repeating && longer than 32
    @test allunique(collect('A':'z')) # 58-element Vector{Char}
    @test !allunique(repeat(1:99, 1, 2))
    @test !allunique(vcat(pi, randn(1998), pi))  # longer than 1000
    @test allunique(eachrow(hcat(1:10, 1:10)))
    @test allunique(x for x in 'A':'Z' if randn()>0)
    @test !allunique(x for x in repeat(1:2000, 3) if true)
    @test allunique([0.0, -0.0])
    @test allunique(x for x in [0.0, -0.0] if true)
    @test !allunique([NaN, NaN])
    @test !allunique(x for x in [NaN, NaN] if true)
    # ranges
    @test allunique(4:7)
    @test allunique(1:1)
    @test allunique(4.0:0.3:7.0)
    @test allunique(4:-1:5)       # empty range
    @test allunique(7:-1:1)       # negative step
    @test allunique(Date(2018, 8, 7):Day(1):Date(2018, 8, 11))  # JuliaCon 2018
    @test allunique(DateTime(2018, 8, 7):Hour(1):DateTime(2018, 8, 11))
    @test allunique(('a':1:'c')[1:2]) == true
    @test allunique(collect(1:1001))
    for r = (Base.OneTo(-1), Base.OneTo(0), Base.OneTo(1), Base.OneTo(5),
             1:0, 1:1, 1:2, 1:10, 1:.5:.5, 1:.5:1, 1:.5:10, 3:-2:5, 3:-2:3, 3:-2:1,
             StepRangeLen(1.0, 2.0, 0), StepRangeLen(1.0, 2.0, 2), StepRangeLen(1.0, 2.0, 3),
             StepRangeLen(1.0, 0.0, 0), StepRangeLen(1.0, -0.0, 1), StepRangeLen(1.0, 0.0, 2),
             LinRange(1, 2, 3), LinRange(1, 1, 0), LinRange(1, 1, 1), LinRange(1, 1, 10))
        @test allunique(r) == invoke(allunique, Tuple{Any}, r)
    end
    # tuples
    @test allunique(())
    @test allunique((1,2,3))
    @test allunique(ntuple(identity, 40))
    @test !allunique((1,2,3,4,3))
    @test allunique((0.0, -0.0))
    @test !allunique((NaN, NaN))
    # Known length 1, need not evaluate:
    @test allunique(error(x) for x in [1])
end

@testset "allunique(f, xs)" begin
    @test allunique(sin, 1:3)
    @test !allunique(sin, [1,2,3,1])
    @test allunique(sin, (1, 2, pi, im))  # eltype Any
    @test allunique(abs2, 1:100)
    @test !allunique(abs, -10:10)
    @test allunique(abs2, Vector{Any}(1:100))
    # These cases don't call the function at all:
    @test allunique(error, [])
    @test allunique(error, [1])
end

@testset "allequal" begin
    # sets & dictionaries
    @test allequal(Set())
    @test allequal(Set(1))
    @test !allequal(Set([1, 2]))
    @test allequal(Dict())
    @test allequal(Dict(:a => 1))
    @test !allequal(Dict(:a => 1, :b => 2))
    # vectors
    @test allequal([])
    @test allequal([1])
    @test allequal([1, 1])
    @test !allequal([1, 1, 2])
    @test allequal([:a, :a])
    @test !allequal([:a, :b])
    # ranges
    @test !allequal(1:2)
    @test allequal(1:1)
    @test !allequal(4.0:0.3:7.0)
    @test allequal(4:-1:5)       # empty range
    @test !allequal(7:-1:1)       # negative step
    @test !allequal(Date(2018, 8, 7):Day(1):Date(2018, 8, 11))  # JuliaCon 2018
    @test !allequal(DateTime(2018, 8, 7):Hour(1):DateTime(2018, 8, 11))
    @test allequal(StepRangeLen(1.0, 0.0, 2))
    @test !allequal(StepRangeLen(1.0, 1.0, 2))
    @test allequal(LinRange(1, 1, 0))
    @test allequal(LinRange(1, 1, 1))
    @test allequal(LinRange(1, 1, 2))
    @test !allequal(LinRange(1, 2, 2))
    # Known length 1, need not evaluate:
    @test allequal(error(x) for x in [1])
    # Empty, but !haslength:
    @test allequal(error(x) for x in 1:3 if false)
end

@testset "allequal(f, xs)" begin
    @test allequal(abs2, [3, -3])
    @test allequal(x -> 1, rand(3))
    @test !allequal(x -> rand(), [1,1,1])
    # tuples
    @test allequal(abs2, (3, -3))
    @test allequal(x -> 1, Tuple(rand(3)))
    @test !allequal(x -> rand(), (1,1,1))
    # These cases don't call the function at all:
    @test allequal(error, [])
    @test allequal(error, ())
    @test allequal(error, (x for x in 1:3 if false))
    @test allequal(error, [1])
    @test allequal(error, (1,))
end

@testset "filter(f, ::$S)" for S = (Set, BitSet)
    s = S([1,2,3,4])
    @test s !== filter( isodd, s) == S([1,3])
    @test s === filter!(isodd, s) == S([1,3])
end
@testset "first" begin
    @test_throws ArgumentError first(Set())
    @test first(Set(2)) == 2
end
@testset "pop!" begin
    s = Set(1:5)
    @test 2 in s
    @test pop!(s, 2) == 2
    @test !(2 in s)
    @test_throws KeyError pop!(s, 2)
    @test pop!(s, 2, ()) == ()
    @test 3 in s
    @test pop!(s, 3, ()) == 3
    @test !(3 in s)
    @test pop!(Set(1:2), 2, nothing) == 2
end

@testset "convert" begin
    iset = Set([17, 4711])
    cfset = convert(Set{Float64}, iset)
    @test typeof(cfset) == Set{Float64}
    @test cfset == iset
    fset = Set([17.0, 4711.0])
    ciset = convert(Set{Int}, fset)
    @test typeof(ciset) == Set{Int}
    @test ciset == fset
    ssset = Set(split("foo bar"))
    cssset = convert(Set{String}, ssset)
    @test typeof(cssset) == Set{String}
    @test cssset == Set(["foo", "bar"])
end

@testset "fuzzy testing Set & BitSet" begin
    b1, b2 = rand(-1000:1000, 2)
    e1 = rand(b1-9:1000) # -9 to have an empty list sometimes
    e2 = rand(b2-9:1000)
    l1, l2 = rand(1:1000, 2)
    a1 = b1 <= e1 ? rand(b1:e1, l1) : Int[]
    a2 = b2 <= e2 ? rand(b2:e2, l2) : Int[]
    s1, s2 = Set(a1), Set(a2)
    t1, t2 = BitSet(a1), BitSet(a2)

    for (s, t) = ((s1, t1), (s2, t2))
        @test length(s) == length(t)
        @test issubset(s, t)
        @test issubset(t, s)
        @test isempty(s) == isempty(t)
        isempty(s) && continue
        @test maximum(s) == maximum(t)
        @test minimum(s) == minimum(t)
        @test extrema(s) == extrema(t)
        rs, rt = rand(s), rand(t)
        @test rs in s
        @test rt in s
        @test rs in t
        @test rt in t
        for y in (rs, rt)
            ss = copy(s)
            tt = copy(t)
            pop!(ss, y)
            pop!(tt, y)
            @test BitSet(ss) == tt
            @test Set(tt) == ss
            z = rand(1001:1100) # z ∉ s or t
            push!(ss, z)
            push!(tt, z)
            @test BitSet(ss) == tt
            @test Set(tt) == ss
        end
    end

    res = Dict{String,Union{Bool,Vector{Int}}}()
    function check(desc, val)
        n = val isa Bool ? val : sort!(collect(val))
        r = get!(res, desc, n)
        if n isa Bool || r !== n
            @test r == n
        end
    end
    asbitset(x) = x isa BitSet ? x : BitSet(x)
    asset(x) = x isa Set ? x : Set(x)

    for x1 = (s1, t1), x2 = (s2, t2)
        check("union", union(x1, x2))
        check("intersect", intersect(x1, x2))
        check("symdiff", symdiff(x1, x2))
        check("setdiff", setdiff(x1, x2))
        check("== as Bitset", asbitset(x1) == asbitset(x2))
        check("== as Set", asset(x1) == asset(x2))
        check("issubset", issubset(x1, x2))
        if typeof(x1) == typeof(x2)
            check("<", x1 < x2)
            check("<=", x1 > x2)
            check("union!", union!(copy(x1), x2))
            check("setdiff!", setdiff!(copy(x1), x2))
            x1 isa Set && continue
            check("intersect!", intersect!(copy(x1), x2))
            check("symdiff!", symdiff!(copy(x1), x2))
        end
    end
end

@testset "replace! & replace" begin
    a = [1, 2, 3, 1]
    @test replace(x -> iseven(x) ? 2x : x, a) == [1, 4, 3, 1]
    @test replace(x -> iseven(x) ? 2x : x, Tuple(a)) === (1, 4, 3, 1)
    @test replace!(x -> iseven(x) ? 2x : x, a) === a
    @test a == [1, 4, 3, 1]
    @test replace(a, 1=>0) == [0, 4, 3, 0]
    @test replace(Tuple(a), 1=>0) === (0, 4, 3, 0)
    for count = (1, 0x1, big(1))
        @test replace(a, 1=>0, count=count) == [0, 4, 3, 1]
        @test replace(Tuple(a), 1=>0, count=count) === (0, 4, 3, 1)
    end
    @test replace!(a, 1=>2) === a
    @test a == [2, 4, 3, 2]
    @test replace!(x->2x, a, count=0x2) == [4, 8, 3, 2]

    d = Dict(1=>2, 3=>4)
    @test replace!(x -> x.first > 2 ? x.first=>2*x.second : x, d) === d
    @test d == Dict(1=>2, 3=>8)
    @test replace(d, (3=>8)=>(0=>0)) == Dict(1=>2, 0=>0)
    @test replace!(d, (3=>8)=>(2=>2)) === d
    @test d == Dict(1=>2, 2=>2)

    s = Set([1, 2, 3])
    @test replace(x -> x > 1 ? 2x : x, s) == Set([1, 4, 6])
    for count = (1, 0x1, big(1))
        @test replace(x -> x > 1 ? 2x : x, s, count=count) in [Set([1, 4, 3]), Set([1, 2, 6])]
    end
    @test replace(s, 1=>4) == Set([2, 3, 4])
    @test replace!(s, 1=>2) === s
    @test s == Set([2, 3])
    @test replace!(x->2x, s, count=0x1) in [Set([4, 3]), Set([2, 6])]

    for count = (0, 0x0, big(0)) # count == 0 --> no replacements
        @test replace([1, 2], 1=>0, 2=>0; count) == [1, 2]
        @test replace((1, 2), 1=>0, 2=>0; count) === (1, 2)
        for dict = (Dict(1=>2, 2=>3), IdDict(1=>2, 2=>3))
            @test replace(dict, (1=>2) => (1=>3); count) == dict
        end
        @test replace(Set([1, 2]), 2=>-1; count) == Set([1, 2])
    end

    # test collisions with AbstractSet/AbstractDict
    @test replace!(x->2x, Set([3, 6])) == Set([6, 12])
    @test replace!(x->2x, Set([1:20;])) == Set([2:2:40;])
    @test replace!(kv -> (2kv[1] => kv[2]), Dict(1=>2, 2=>4, 4=>8, 8=>16)) == Dict(2=>2, 4=>4, 8=>8, 16=>16)

    # avoid recursive call issue #25384
    @test_throws MethodError replace!("")

    # test eltype promotion
    x = @inferred replace([1, 2], 2=>2.5)
    @test x == [1, 2.5] && x isa Vector{Float64}

    x = @inferred replace([1, 2], 2=>missing)
    @test isequal(x, [1, missing]) && x isa Vector{Union{Int, Missing}}

    x = @inferred replace([1, missing], missing=>2)
    @test x == [1, 2] && x isa Vector{Int}
    x = @inferred replace([1, missing], missing=>2, count=1)
    @test x == [1, 2] && x isa Vector{Union{Int, Missing}}
    x = @inferred replace([1, missing], missing=>missing)
    @test isequal(x, [1, missing]) && x isa Vector{Union{Int, Missing}}
    x = @inferred replace([1, missing], missing=>2, 1=>missing)
    @test isequal(x, [missing, 2]) && x isa Vector{Union{Int, Missing}}

    # eltype promotion for dicts
    d = Dict(1=>2, 3=>4)
    f = replace(d, (1=>2) => (1=>nothing))
    @test f == Dict(3=>4, 1=>nothing)
    @test eltype(f) == Pair{Int, Union{Nothing, Int}}
    f = replace(d, (1=>2) => (1=>missing), (3=>4)=>(3=>missing))
    @test valtype(f) == Union{Missing,Int}
    f = replace(d, (1=>2) => (1=>'a'), (3=>4)=>(3=>'b'))
    @test valtype(f) == Any
    @test f == Dict(3=>'b', 1=>'a')

    # eltype promotion for sets
    s = Set([1, 2, 3])
    f = replace(s, 2=>missing, 3=>nothing)
    @test f == Set([1, missing, nothing])
    @test eltype(f) == Union{Int,Missing,Nothing}
    f = replace(s, 2=>'a')
    @test eltype(f) == Any
    @test f == Set([1, 3, 'a'])

    # test that isequal is used
    @test replace([NaN, 1.0], NaN=>0.0) == [0.0, 1.0]
    @test replace((NaN, 1.0), NaN=>0.0) === (0.0, 1.0)
    @test replace([1, missing], missing=>0) == [1, 0]
    @test replace((1, missing), missing=>0) === (1, 0)

    # test that MethodError is thrown for pairs
    @test_throws MethodError replace(identity, 1=>2)
    @test_throws MethodError replace(identity, 1=>2, 3=>4)
    @test_throws MethodError replace!(identity, 1=>2)
    @test_throws MethodError replace!(identity, 1=>2, 3=>4)

    # test replace and friends for AbstractDicts
    d1 = GenericDict(Dict(1=>2, 3=>4))
    d2 = replace(d1, (1=>2) => (1=>"a"))
    @test d2 == Dict(1=>"a", 3=>4)
    @test d2 isa Dict{Int, Any}
    @test d1 === replace!(d1, (1=>2) => (1=>-2))
    @test d1 == Dict(1=>-2, 3=>4)

    dd = Dict(1=>2, 3=>1, 5=>1, 7=>1)
    for d1 in (dd, GenericDict(dd))
        @test replace(d1, (1=>2) => (1=>"a"), count=0) == d1
        d2 = replace(kv->(kv[2] == 1 ? kv[1]=>2 : kv), d1, count=2)
        @test count(==(2), values(d2)) == 3
        @test count(==(1), values(d2)) == 1
    end
end

@testset "⊆, ⊊, ⊈, ⊇, ⊋, ⊉, <, <=, issetequal" begin
    a = [2, 1, 2]
    b = [2, 3, 1, 3]
    ua = unique(a)
    ub = unique(b)
    for TA in (Tuple, identity, Set, BitSet, IdSet{Int}),
        TB in (Tuple, identity, Set, BitSet, IdSet{Int}),
        uA = false:true,
        uB = false:true
        A = TA(uA ? ua : a)
        B = TB(uB ? ub : b)
        @test A ⊆ B
        @test A ⊊ B
        @test !(A ⊈ B)
        @test !(A ⊇ B)
        @test !(A ⊋ B)
        @test A ⊉ B
        @test !(B ⊆ A)
        @test !(B ⊊ A)
        @test B ⊈ A
        @test B ⊇ A
        @test B ⊋ A
        @test !(B ⊉ A)
        @test !issetequal(A, B)
        @test !issetequal(B, A)
        @test !issetequal(B)(A)
        @test !issetequal(A)(B)
        for T = (Tuple, identity, Set, BitSet, IdSet{Int})
            @test issetequal(A, T(A))
            @test issetequal(B, T(B))
        end
        if A isa AbstractSet && B isa AbstractSet
            @test A <= B
            @test A <  B
            @test !(A >= B)
            @test !(A >  B)
            @test !(B <= A)
            @test !(B <  A)
            @test B >= A
            @test B >  A
        end
    end
    # first doesn't have length
    @test issetequal(Iterators.filter(iseven, 1:10), [2, 4, 6, 8, 10])
    # both don't have length
    @test issetequal(Iterators.filter(iseven, 1:10), Iterators.filter(iseven, 1:10))
end

@testset "optimized union! with max_values" begin
    # issue #30315
    T = Union{Nothing, Bool}
    @test Base.max_values(T) == 3
    d = Set{T}()
    union!(d, (nothing, true, false))
    @test length(d) == 3
    @test d == Set((nothing, true, false))
    @test nothing in d
    @test true    in d
    @test false   in d

    for X = (Int8, Int16, Int32, Int64)
        @test Base.max_values(Union{Nothing, X}) == (sizeof(X) < sizeof(Int) ?
                                                     2^(8*sizeof(X)) + 1 :
                                                     typemax(Int))
    end
    # this does not account for non-empty intersections of the unioned types
    @test Base.max_values(Union{Int8,Int16}) == 2^8 + 2^16
end

struct OpenInterval{T}
    lower::T
    upper::T
end
Base.in(x, i::OpenInterval) = i.lower < x < i.upper
Base.IteratorSize(::Type{<:OpenInterval}) = Base.SizeUnknown()

@testset "Continuous sets" begin
    i = OpenInterval(2, 4)
    @test 3 ∈ i
    @test issubset(3, i)
end

@testset "IdSet" begin
    a = [1]
    b = [2]
    c = [3]
    d = [4]
    e = [5]
    A = IdSet{Vector{Int}}([a, b, c, d])
    @test !isempty(A)
    B = copy(A)
    @test A ⊆ B
    @test B ⊆ A
    A = filter!(x->isodd(x[1]), A)
    @test A ⊆ B
    @test !(B ⊆ A)
    @test !isempty(A)
    a_ = pop!(A, a)
    @test a_ === a
    @test !isempty(A)
    e_ = pop!(A, a, e)
    @test e_ === e
    @test !isempty(A)
    A = empty!(A)
    @test isempty(A)
end

@testset "⊊, ⊋" begin
    @test !((1, 2) ⊊ (1, 2, 2))
    @test !((1, 2, 2) ⊋ (1, 2))
end

@testset "AbstractSet & Fallback" begin
    mutable struct TestSet{T} <: AbstractSet{T}
        set::Set{T}
        function TestSet{T}() where T
            new{T}(Set{T}())
        end
    end
    set = TestSet{Any}()
    @test sizehint!(set, 1) === set
    @test sizehint!(set, 1; shrink = true) === set
    @test sizehint!(set, 1; shrink = false) === set
end
back to top