Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make keys of a dictionary a set #24580

Merged
merged 1 commit into from Dec 2, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS.md
Expand Up @@ -370,6 +370,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]).

* The `keys` of an `Associative` are now an `AbstractSet`. `Base.KeyIterator{<:Associative}`
has been changed to `KeySet{K, <:Associative{K}} <: AbstractSet{K}` ([#24580]).

Compiler/Runtime improvements
-----------------------------

Expand Down
26 changes: 13 additions & 13 deletions base/associative.jl
Expand Up @@ -14,7 +14,7 @@ end

const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__

haskey(d::Associative, k) = in(k,keys(d))
haskey(d::Associative, k) = in(k, keys(d))

function in(p::Pair, a::Associative, valcmp=(==))
v = get(a,p[1],secret_table_token)
Expand All @@ -35,29 +35,29 @@ function summary(t::Associative)
return string(typeof(t), " with ", n, (n==1 ? " entry" : " entries"))
end

struct KeyIterator{T<:Associative}
struct KeySet{K, T <: Associative{K}} <: AbstractSet{K}
dict::T
end
KeySet(dict::Associative) = KeySet{keytype(dict), typeof(dict)}(dict)

struct ValueIterator{T<:Associative}
dict::T
end

summary(iter::T) where {T<:Union{KeyIterator,ValueIterator}} =
summary(iter::T) where {T<:Union{KeySet,ValueIterator}} =
string(T.name, " for a ", summary(iter.dict))

show(io::IO, iter::Union{KeyIterator,ValueIterator}) = show(io, collect(iter))
show(io::IO, iter::Union{KeySet,ValueIterator}) = show(io, collect(iter))

length(v::Union{KeyIterator,ValueIterator}) = length(v.dict)
isempty(v::Union{KeyIterator,ValueIterator}) = isempty(v.dict)
_tt1(::Type{Pair{A,B}}) where {A,B} = A
length(v::Union{KeySet,ValueIterator}) = length(v.dict)
isempty(v::Union{KeySet,ValueIterator}) = isempty(v.dict)
_tt2(::Type{Pair{A,B}}) where {A,B} = B
eltype(::Type{KeyIterator{D}}) where {D} = _tt1(eltype(D))
eltype(::Type{ValueIterator{D}}) where {D} = _tt2(eltype(D))

start(v::Union{KeyIterator,ValueIterator}) = start(v.dict)
done(v::Union{KeyIterator,ValueIterator}, state) = done(v.dict, state)
start(v::Union{KeySet,ValueIterator}) = start(v.dict)
done(v::Union{KeySet,ValueIterator}, state) = done(v.dict, state)

function next(v::KeyIterator, state)
function next(v::KeySet, state)
n = next(v.dict, state)
n[1][1], n[2]
end
Expand All @@ -67,7 +67,7 @@ function next(v::ValueIterator, state)
n[1][2], n[2]
end

in(k, v::KeyIterator) = get(v.dict, k, secret_table_token) !== secret_table_token
in(k, v::KeySet) = get(v.dict, k, secret_table_token) !== secret_table_token

"""
keys(iterator)
Expand Down Expand Up @@ -100,7 +100,7 @@ julia> collect(keys(a))
'a'
```
"""
keys(a::Associative) = KeyIterator(a)
keys(a::Associative) = KeySet(a)

"""
values(a::Associative)
Expand Down
4 changes: 2 additions & 2 deletions base/dict.jl
Expand Up @@ -588,7 +588,7 @@ false
```
"""
haskey(h::Dict, key) = (ht_keyindex(h, key) >= 0)
in(key, v::KeyIterator{<:Dict}) = (ht_keyindex(v.dict, key) >= 0)
in(key, v::KeySet{<:Any, <:Dict}) = (ht_keyindex(v.dict, key) >= 0)

"""
getkey(collection, key, default)
Expand Down Expand Up @@ -720,7 +720,7 @@ end
isempty(t::Dict) = (t.count == 0)
length(t::Dict) = t.count

@propagate_inbounds function next(v::KeyIterator{<:Dict}, i)
@propagate_inbounds function next(v::KeySet{<:Any, <:Dict}, i)
return (v.dict.keys[i], skip_deleted(v.dict,i+1))
end
@propagate_inbounds function next(v::ValueIterator{<:Dict}, i)
Expand Down
2 changes: 1 addition & 1 deletion base/env.jl
Expand Up @@ -78,7 +78,7 @@ similar(::EnvDict) = Dict{String,String}()
getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
get(::EnvDict, k::AbstractString, def) = access_env(k->def, k)
get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k)
in(k::AbstractString, ::KeyIterator{EnvDict}) = _hasenv(k)
in(k::AbstractString, ::KeySet{String, EnvDict}) = _hasenv(k)
pop!(::EnvDict, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v)
pop!(::EnvDict, k::AbstractString, def) = haskey(ENV,k) ? pop!(ENV,k) : def
delete!(::EnvDict, k::AbstractString) = (_unsetenv(k); ENV)
Expand Down
4 changes: 2 additions & 2 deletions base/precompile.jl
Expand Up @@ -38,7 +38,7 @@ precompile(Tuple{getfield(Base, Symbol("#kw##listen")), Array{Any, 1}, typeof(Ba
precompile(Tuple{typeof(Base.ndigits0z), UInt16})
precompile(Tuple{typeof(Base.dec), UInt16, Int64, Bool})
precompile(Tuple{typeof(Base.Libc.strerror), Int32})
precompile(Tuple{typeof(Base.copy!), Array{Any, 1}, Base.KeyIterator{Base.Dict{Any, Any}}})
precompile(Tuple{typeof(Base.copy!), Array{Any, 1}, Base.KeySet{Any, Base.Dict{Any, Any}}})
precompile(Tuple{typeof(Base.promoteK), Type{Any}})
precompile(Tuple{typeof(Core.Inference.length), Tuple{Core.Inference.Const, DataType, Core.Inference.Const, Core.Inference.Const}})
precompile(Tuple{typeof(Core.Inference.getindex), Tuple{Core.Inference.Const, DataType, Core.Inference.Const, Core.Inference.Const}, Int64})
Expand Down Expand Up @@ -321,7 +321,7 @@ precompile(Tuple{typeof(Base.LineEdit.add_specialisations), Base.Dict{Char, Any}
precompile(Tuple{typeof(Base.setindex!), Base.Dict{Char, Any}, Base.Dict{Char, Any}, Char})
precompile(Tuple{typeof(Base.ht_keyindex2), Base.Dict{Char, Any}, Char})
precompile(Tuple{typeof(Base._setindex!), Base.Dict{Char, Any}, Base.Dict{Char, Any}, Char, Int64})
precompile(Tuple{typeof(Base.setdiff), Base.KeyIterator{Base.Dict{Any, Any}}, Base.KeyIterator{Base.Dict{Any, Any}}})
precompile(Tuple{typeof(Base.setdiff), Base.KeySet{Any, Base.Dict{Any, Any}}, Base.KeySet{Any, Base.Dict{Any, Any}}})
precompile(Tuple{typeof(Base.LineEdit.keymap_merge), Base.Dict{Char, Any}, Base.Dict{Any, Any}})
precompile(Tuple{typeof(Base.LineEdit.postprocess!), Base.Dict{Char, Any}})
precompile(Tuple{typeof(Base.LineEdit.keymap_unify), Array{Base.Dict{Any, Any}, 1}})
Expand Down
4 changes: 2 additions & 2 deletions base/replutil.jl
Expand Up @@ -4,10 +4,10 @@
show(io::IO, ::MIME"text/plain", x) = show(io, x)

# multiline show functions for types defined before multimedia.jl:
function show(io::IO, ::MIME"text/plain", iter::Union{KeyIterator,ValueIterator})
function show(io::IO, ::MIME"text/plain", iter::Union{KeySet,ValueIterator})
print(io, summary(iter))
isempty(iter) && return
print(io, ". ", isa(iter,KeyIterator) ? "Keys" : "Values", ":")
print(io, ". ", isa(iter,KeySet) ? "Keys" : "Values", ":")
limit::Bool = get(io, :limit, false)
if limit
sz = displaysize(io)
Expand Down
3 changes: 2 additions & 1 deletion base/set.jl
@@ -1,5 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

eltype(::Type{AbstractSet{T}}) where {T} = T

mutable struct Set{T} <: AbstractSet{T}
dict::Dict{T,Void}

Expand All @@ -23,7 +25,6 @@ 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}()

Expand Down
10 changes: 5 additions & 5 deletions test/replutil.jl
Expand Up @@ -624,33 +624,33 @@ end
@test String(take!(buf)) == "Base.ImmutableDict{$Int,$Int} with 1 entry: …"
show(io, MIME"text/plain"(), keys(d))
@test String(take!(buf)) ==
"Base.KeyIterator for a Base.ImmutableDict{$Int,$Int} with 1 entry. Keys: …"
"Base.KeySet for a Base.ImmutableDict{$Int,$Int} with 1 entry. Keys: …"

io = IOContext(io, :displaysize => (5, 80))
show(io, MIME"text/plain"(), d)
@test String(take!(buf)) == "Base.ImmutableDict{$Int,$Int} with 1 entry:\n 1 => 2"
show(io, MIME"text/plain"(), keys(d))
@test String(take!(buf)) ==
"Base.KeyIterator for a Base.ImmutableDict{$Int,$Int} with 1 entry. Keys:\n 1"
"Base.KeySet for a Base.ImmutableDict{$Int,$Int} with 1 entry. Keys:\n 1"
d = Base.ImmutableDict(d, 3=>4)
show(io, MIME"text/plain"(), d)
@test String(take!(buf)) == "Base.ImmutableDict{$Int,$Int} with 2 entries:\n ⋮ => ⋮"
show(io, MIME"text/plain"(), keys(d))
@test String(take!(buf)) ==
"Base.KeyIterator for a Base.ImmutableDict{$Int,$Int} with 2 entries. Keys:\n"
"Base.KeySet for a Base.ImmutableDict{$Int,$Int} with 2 entries. Keys:\n"

io = IOContext(io, :displaysize => (6, 80))
show(io, MIME"text/plain"(), d)
@test String(take!(buf)) ==
"Base.ImmutableDict{$Int,$Int} with 2 entries:\n 3 => 4\n 1 => 2"
show(io, MIME"text/plain"(), keys(d))
@test String(take!(buf)) ==
"Base.KeyIterator for a Base.ImmutableDict{$Int,$Int} with 2 entries. Keys:\n 3\n 1"
"Base.KeySet for a Base.ImmutableDict{$Int,$Int} with 2 entries. Keys:\n 3\n 1"
d = Base.ImmutableDict(d, 5=>6)
show(io, MIME"text/plain"(), d)
@test String(take!(buf)) ==
"Base.ImmutableDict{$Int,$Int} with 3 entries:\n 5 => 6\n ⋮ => ⋮"
show(io, MIME"text/plain"(), keys(d))
@test String(take!(buf)) ==
"Base.KeyIterator for a Base.ImmutableDict{$Int,$Int} with 3 entries. Keys:\n 5\n"
"Base.KeySet for a Base.ImmutableDict{$Int,$Int} with 3 entries. Keys:\n 5\n"
end