From c66ed3e082a0e6405c08257df783cc023f756718 Mon Sep 17 00:00:00 2001 From: Andy Ferris Date: Sun, 12 Nov 2017 23:21:52 +1000 Subject: [PATCH] Change `KeyIterator` to `KeySet`. `keys(::Associative)` now returns an `AbstractSet`. --- NEWS.md | 3 +++ base/associative.jl | 26 +++++++++++++------------- base/dict.jl | 4 ++-- base/env.jl | 2 +- base/precompile.jl | 4 ++-- base/replutil.jl | 4 ++-- base/set.jl | 3 ++- test/replutil.jl | 10 +++++----- 8 files changed, 30 insertions(+), 26 deletions(-) diff --git a/NEWS.md b/NEWS.md index ca0345653b530..118cfc1eacac2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -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 ----------------------------- diff --git a/base/associative.jl b/base/associative.jl index 3e04c6adacf01..f0941c20b83ae 100644 --- a/base/associative.jl +++ b/base/associative.jl @@ -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) @@ -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 @@ -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) @@ -100,7 +100,7 @@ julia> collect(keys(a)) 'a' ``` """ -keys(a::Associative) = KeyIterator(a) +keys(a::Associative) = KeySet(a) """ values(a::Associative) diff --git a/base/dict.jl b/base/dict.jl index 67f8fbfd98d34..fd1df606e5ae8 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -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) @@ -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) diff --git a/base/env.jl b/base/env.jl index 718c500257665..d9b3727e6a39e 100644 --- a/base/env.jl +++ b/base/env.jl @@ -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) diff --git a/base/precompile.jl b/base/precompile.jl index 2ccd832138828..2dd68519fc2d7 100644 --- a/base/precompile.jl +++ b/base/precompile.jl @@ -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}) @@ -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}}) diff --git a/base/replutil.jl b/base/replutil.jl index 7373367414e35..a9b8a15ba7745 100644 --- a/base/replutil.jl +++ b/base/replutil.jl @@ -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) diff --git a/base/set.jl b/base/set.jl index a50f1fbc187dc..9712c7e8be232 100644 --- a/base/set.jl +++ b/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} @@ -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}() diff --git a/test/replutil.jl b/test/replutil.jl index c942ab5fcbc77..133631c4ac9d0 100644 --- a/test/replutil.jl +++ b/test/replutil.jl @@ -624,20 +624,20 @@ 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) @@ -645,12 +645,12 @@ end "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