diff --git a/NEWS.md b/NEWS.md index 1ac663ea1be88..32c70cadc4d3d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -364,6 +364,9 @@ Library improvements This supersedes the old behavior of reinterpret on Arrays. As a result, reinterpreting arrays with different alignment requirements (removed in 0.6) is once again allowed ([#23750]). + * `AbstractSet`s are now indexable, such that `set[x] == x` and `keys(set) == set` + ([#24508]). + Compiler/Runtime improvements ----------------------------- diff --git a/base/bitset.jl b/base/bitset.jl index 431df3f4ea9bf..2f8def248d121 100644 --- a/base/bitset.jl +++ b/base/bitset.jl @@ -15,7 +15,6 @@ very large integers), use [`Set`](@ref) instead. """ BitSet(itr) = union!(BitSet(), itr) -eltype(::Type{BitSet}) = Int similar(s::BitSet) = BitSet() copy(s1::BitSet) = copy!(BitSet(), s1) function copy!(dest::BitSet, src::BitSet) @@ -23,7 +22,6 @@ function copy!(dest::BitSet, src::BitSet) copy!(dest.bits, src.bits) dest end -eltype(s::BitSet) = Int sizehint!(s::BitSet, n::Integer) = (n > length(s.bits) && _resize0!(s.bits, n); s) # An internal function for setting the inclusion bit for a given integer n >= 0 diff --git a/base/set.jl b/base/set.jl index a50f1fbc187dc..1b95851ebde40 100644 --- a/base/set.jl +++ b/base/set.jl @@ -1,5 +1,19 @@ # This file is a part of Julia. License is MIT: https://julialang.org/license +# AbstractSet + +# AbstractSets are idempotent under indexing: +keys(set::AbstractSet) = set +@inline function getindex(set::AbstractSet, x) + @boundscheck if x ∉ set + throw(KeyError(x)) + end + return x +end +eltype(set::Type{<:AbstractSet{T}}) where {T} = T + +# Set + mutable struct Set{T} <: AbstractSet{T} dict::Dict{T,Void} @@ -23,9 +37,8 @@ function Set(g::Generator) return Set{T}(g) end -eltype(::Type{Set{T}}) where {T} = T -similar(s::Set{T}) where {T} = Set{T}() -similar(s::Set, T::Type) = Set{T}() +similar(s::AbstractSet) where {T} = similar(s, eltype(s)) +similar(s::AbstractSet, T::Type) = Set{T}() # default empty set type function show(io::IO, s::Set) print(io, "Set") @@ -64,7 +77,7 @@ rehash!(s::Set) = (rehash!(s.dict); s) start(s::Set) = start(s.dict) done(s::Set, state) = done(s.dict, state) # NOTE: manually optimized to take advantage of Dict representation -next(s::Set, i) = (s.dict.keys[i], skip_deleted(s.dict, i+1)) +@propagate_inbounds next(s::Set, i) = (s.dict.keys[i], skip_deleted(s.dict, i+1)) """ union(s1,s2...) diff --git a/test/sets.jl b/test/sets.jl index c237a6669759f..d20711b24c9ff 100644 --- a/test/sets.jl +++ b/test/sets.jl @@ -153,6 +153,12 @@ end end end +@testset "indexing" begin + s = Set(["a", "b", "c"]) + @test s["b"] == "b" + @test_throws KeyError s["d"] +end + @testset "union" begin @test isequal(union(Set([1])),Set([1])) s = ∪(Set([1,2]), Set([3,4]))