From 3ecccf89b903acf64e6cd1b37e59262bf0cc56f2 Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Tue, 7 Nov 2017 21:59:13 +1000 Subject: [PATCH] WIP: Make sets indexable * All `AbstractSet`s can be indexed. They are containers with equal values and keys, much like `Base.OneTo(n)`. This will enable a certain semantic with `keys` and indexing common across arrays, associatives and sets. --- NEWS.md | 3 +++ base/bitset.jl | 4 +--- base/essentials.jl | 1 - base/set.jl | 22 ++++++++++++++++++---- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/NEWS.md b/NEWS.md index 24433407a34b5..2fd9f50929ef8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -362,6 +362,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..ceaa147f5aaae 100644 --- a/base/bitset.jl +++ b/base/bitset.jl @@ -15,15 +15,13 @@ very large integers), use [`Set`](@ref) instead. """ BitSet(itr) = union!(BitSet(), itr) -eltype(::Type{BitSet}) = Int -similar(s::BitSet) = BitSet() +empty(s::BitSet) = BitSet() copy(s1::BitSet) = copy!(BitSet(), s1) function copy!(dest::BitSet, src::BitSet) resize!(dest.bits, length(src.bits)) 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/essentials.jl b/base/essentials.jl index cc4e01f647709..96e1ed2782710 100644 --- a/base/essentials.jl +++ b/base/essentials.jl @@ -6,7 +6,6 @@ const Callable = Union{Function,Type} const Bottom = Union{} -abstract type AbstractSet{T} end abstract type Associative{K,V} end # The real @inline macro is not available until after array.jl, so this diff --git a/base/set.jl b/base/set.jl index a50f1fbc187dc..c269c4fe9c031 100644 --- a/base/set.jl +++ b/base/set.jl @@ -1,5 +1,21 @@ # 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::AbstractSet) = eltype(typeof(set)) +eltype(set::Type{<:AbstractSet{T}}) = T +empty(s::AbstractSet{T}) where {T} = empty(s, T) + +# Set + mutable struct Set{T} <: AbstractSet{T} dict::Dict{T,Void} @@ -23,9 +39,7 @@ 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}() +empty(s::AbstractSet, T::Type) = Set{T}() # default empty set type function show(io::IO, s::Set) print(io, "Set") @@ -64,7 +78,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...)