Repository: JuliaLang/julia
File: base/array.jl (Julia)

Code before:

symdiff!(v::AbstractVector{T}, itrs...) where {T} =
    _grow!(_shrink_filter!(symdiff!(Set{T}(), v, itrs...)), v, itrs)

function _shrink!(shrinker!::F, v::AbstractVector, itrs) where F
    seen = Set{eltype(v)}()
    filter!(_grow_filter!(seen), v)
    shrinker!(seen, itrs...)
    filter!(in(seen), v)
end

intersect!(v::AbstractVector, itrs...) = _shrink!(intersect!, v, itrs)
setdiff!(  v::AbstractVector, itrs...) = _shrink!(setdiff!, v, itrs)

vectorfilter(T::Type, f, v) = T[x for x in v if f(x)]

function intersect(itr, itrs...)
    T = promote_eltype(itr, itrs...)
    keep = intersect!(Set{T}(itr), itrs...)
    vectorfilter(T, _shrink_filter!(keep), itr)
end

function setdiff(itr, itrs...)
    T = promote_eltype(itr, itrs...)
    keep = setdiff!(Set{T}(itr), itrs...)
    vectorfilter(eltype(itr), _shrink_filter!(keep), itr)
end

function intersect(v::AbstractVector, r::AbstractRange)
    T = promote_eltype(v, r)
    common = Iterators.filter(in(r), v)
    seen = Set{T}(common)
    return vectorfilter(T, _shrink_filter!(seen), common)
end
intersect(r::AbstractRange, v::AbstractVector) = intersect(v, r)

# Here instead of range.jl for bootstrapping because `@propagate_inbounds` depends on Vectors.
@propagate_inbounds function getindex(v::AbstractRange, i::Integer)
    if i isa Bool # Not via dispatch to avoid ambiguities
        throw(ArgumentError("invalid index: $i of type Bool"))
    else
        _getindex(v, i)
    end
end

"""
    wrap(Array, m::Union{Memory{T}, MemoryRef{T}}, dims)

Create an array of size `dims` using `m` as the underlying memory. This can be thought of as a safe version
of [`unsafe_wrap`](@ref) utilizing `Memory` or `MemoryRef` instead of raw pointers.
"""

Review comment (suggestion):
Would this work? Possibly I'm misunderstanding something, but I don't see why is promotion necessary, given that `setdiff!` never adds elements to the set.

```suggestion
    T = eltype(itr)
    keep = setdiff!(Set{T}(itr), itrs...)
    vectorfilter(T, _shrink_filter!(keep), itr)
```

Code after:

symdiff!(v::AbstractVector{T}, itrs...) where {T} =
    _grow!(_shrink_filter!(symdiff!(Set{T}(), v, itrs...)), v, itrs)

function _shrink!(shrinker!::F, v::AbstractVector, itrs) where F
    seen = Set{eltype(v)}()
    filter!(_grow_filter!(seen), v)
    shrinker!(seen, itrs...)
    filter!(in(seen), v)
end

intersect!(v::AbstractVector, itrs...) = _shrink!(intersect!, v, itrs)
setdiff!(  v::AbstractVector, itrs...) = _shrink!(setdiff!, v, itrs)

vectorfilter(T::Type, f, v) = T[x for x in v if f(x)]

function intersect(itr, itrs...)
    T = promote_eltype(itr, itrs...)
    keep = intersect!(Set{T}(itr), itrs...)
    vectorfilter(T, _shrink_filter!(keep), itr)
end

function setdiff(itr, itrs...)
    T = eltype(itr)
    keep = setdiff!(Set{T}(itr), itrs...)
    vectorfilter(T, _shrink_filter!(keep), itr)
end

function intersect(v::AbstractVector, r::AbstractRange)
    T = promote_eltype(v, r)
    common = Iterators.filter(in(r), v)
    seen = Set{T}(common)
    return vectorfilter(T, _shrink_filter!(seen), common)
end
intersect(r::AbstractRange, v::AbstractVector) = intersect(v, r)

# Here instead of range.jl for bootstrapping because `@propagate_inbounds` depends on Vectors.
@propagate_inbounds function getindex(v::AbstractRange, i::Integer)
    if i isa Bool # Not via dispatch to avoid ambiguities
        throw(ArgumentError("invalid index: $i of type Bool"))
    else
        _getindex(v, i)
    end
end

"""
    wrap(Array, m::Union{Memory{T}, MemoryRef{T}}, dims)

Create an array of size `dims` using `m` as the underlying memory. This can be thought of as a safe version
of [`unsafe_wrap`](@ref) utilizing `Memory` or `MemoryRef` instead of raw pointers.
"""