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

Add empty and change similar(::Associative) #24390

Merged
merged 1 commit into from
Dec 3, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,13 @@ Deprecated or removed

* `linspace` and `logspace` now require an explicit number of elements to be supplied rather than defaulting to `50`.

* Introduced the `empty` function, the functional pair to `empty!` which returns a new,
empty container ([#24390]).

* `similar(::Associative)` has been deprecated in favor of `empty(::Associative)`, and
`similar(::Associative, ::Pair{K, V})` has been deprecated in favour of
`empty(::Associative, K, V)` ([#24390]).

Command-line option changes
---------------------------

Expand Down
18 changes: 18 additions & 0 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,24 @@ indices of `A`.
similar(f, shape::Tuple) = f(to_shape(shape))
similar(f, dims::DimOrInd...) = similar(f, dims)

"""
empty(v::AbstractVector, [eltype])

Create an empty vector similar to `v`, optionally changing the `eltype`.

# Examples

```jldoctest
julia> empty([1.0, 2.0, 3.0])
0-element Array{Float64,1}

julia> empty([1.0, 2.0, 3.0], String)
0-element Array{String,1}
```
"""
empty(a::AbstractVector) = empty(a, eltype(a))
empty(a::AbstractVector, ::Type{T}) where {T} = Vector{T}()

## from general iterable to any array

function copy!(dest::AbstractArray, src)
Expand Down
21 changes: 18 additions & 3 deletions base/associative.jl
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,23 @@ pairs(collection) = Generator(=>, keys(collection), values(collection))

pairs(a::Associative) = a

"""
empty(a::Associative, [index_type=keytype(a)], [value_type=valtype(a)])

Create an empty `Associative` container which can accept indices of type `index_type` and
values of type `value_type`. The second and third arguments are optional and default to the
input's `keytype` and `valtype`, respectively. (If only one of the two types is specified,
it is assumed to be the `value_type`, and the `index_type` we default to `keytype(a)`).

Custom `Associative` subtypes may choose which specific associative type is best suited to
return for the given index and value types, by specializing on the three-argument signature.
The default is to return an empty `Dict`.
"""
empty(a::Associative) = empty(a, keytype(a), valtype(a))
empty(a::Associative, ::Type{V}) where {V} = empty(a, keytype(a), V) # Note: this is the form which makes sense for `Vector`.

function copy(a::Associative)
b = similar(a)
b = empty(a)
for (k,v) in a
b[k] = v
end
Expand Down Expand Up @@ -418,7 +433,7 @@ Dict{Int64,String} with 1 entry:
"""
function filter(f, d::Associative)
# don't just do filter!(f, copy(d)): avoid making a whole copy of d
df = similar(d)
df = empty(d)
try
for pair in d
if f(pair)
Expand Down Expand Up @@ -527,7 +542,7 @@ mutable struct ObjectIdDict <: Associative{Any,Any}
ObjectIdDict(o::ObjectIdDict) = new(copy(o.ht))
end

similar(d::ObjectIdDict) = ObjectIdDict()
empty(d::ObjectIdDict, ::Type{Any}, ::Type{Any}) = ObjectIdDict()

function rehash!(t::ObjectIdDict, newsz = length(t.ht))
t.ht = ccall(:jl_idtable_rehash, Any, (Any, Csize_t), t.ht, newsz)
Expand Down
2 changes: 1 addition & 1 deletion base/deepcopy.jl
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function deepcopy_internal(x::Dict, stackdict::ObjectIdDict)
return (stackdict[x] = copy(x))
end

dest = similar(x)
dest = empty(x)
stackdict[x] = dest
for (k, v) in x
dest[deepcopy_internal(k, stackdict)] = deepcopy_internal(v, stackdict)
Expand Down
4 changes: 4 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2172,6 +2172,10 @@ end

@deprecate merge!(repo::LibGit2.GitRepo, args...; kwargs...) LibGit2.merge!(repo, args...; kwargs...)

# issue #24019
@deprecate similar(a::Associative) empty(a)
@deprecate similar(a::Associative, ::Type{Pair{K,V}}) where {K, V} empty(a, K, V)

# END 0.7 deprecations

# BEGIN 1.0 deprecations
Expand Down
19 changes: 8 additions & 11 deletions base/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ mutable struct Dict{K,V} <: Associative{K,V}
new(copy(d.slots), copy(d.keys), copy(d.vals), d.ndel, d.count, d.age,
d.idxfloor, d.maxprobe)
end
function Dict{K, V}(slots, keys, vals, ndel, count, age, idxfloor, maxprobe) where {K, V}
new(slots, keys, vals, ndel, count, age, idxfloor, maxprobe)
end
end
function Dict{K,V}(kv) where V where K
h = Dict{K,V}()
Expand Down Expand Up @@ -166,7 +169,7 @@ end
# this is a special case due to (1) allowing both Pairs and Tuples as elements,
# and (2) Pair being invariant. a bit annoying.
function grow_to!(dest::Associative, itr)
out = grow_to!(similar(dest, Pair{Union{},Union{}}), itr, start(itr))
out = grow_to!(empty(dest, Union{}, Union{}), itr, start(itr))
return isempty(out) ? dest : out
end

Expand All @@ -176,7 +179,7 @@ function grow_to!(dest::Associative{K,V}, itr, st) where V where K
if isa(k,K) && isa(v,V)
dest[k] = v
else
new = similar(dest, Pair{typejoin(K,typeof(k)), typejoin(V,typeof(v))})
new = empty(dest, typejoin(K,typeof(k)), typejoin(V,typeof(v)))
copy!(new, dest)
new[k] = v
return grow_to!(new, itr, st)
Expand All @@ -185,8 +188,7 @@ function grow_to!(dest::Associative{K,V}, itr, st) where V where K
return dest
end

similar(d::Dict{K,V}) where {K,V} = Dict{K,V}()
similar(d::Dict, ::Type{Pair{K,V}}) where {K,V} = Dict{K,V}()
empty(a::Associative, ::Type{K}, ::Type{V}) where {K, V} = Dict{K, V}()

# conversion between Dict types
function convert(::Type{Dict{K,V}},d::Associative) where V where K
Expand Down Expand Up @@ -794,12 +796,7 @@ next(::ImmutableDict{K,V}, t) where {K,V} = (Pair{K,V}(t.key, t.value), t.parent
done(::ImmutableDict, t) = !isdefined(t, :parent)
length(t::ImmutableDict) = count(x->true, t)
isempty(t::ImmutableDict) = done(t, start(t))
function similar(t::ImmutableDict)
while isdefined(t, :parent)
t = t.parent
end
return t
end
empty(::ImmutableDict, ::Type{K}, ::Type{V}) where {K, V} = ImmutableDict{K,V}()

_similar_for(c::Dict, ::Type{P}, itr, isz) where {P<:Pair} = similar(c, P)
_similar_for(c::Dict, ::Type{Pair{K,V}}, itr, isz) where {K, V} = empty(c, K, V)
_similar_for(c::Associative, T, itr, isz) = throw(ArgumentError("for Associatives, similar requires an element type of Pair;\n if calling map, consider a comprehension instead"))
2 changes: 0 additions & 2 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ variables.
"""
const ENV = EnvDict()

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)
Expand Down
1 change: 1 addition & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ export
deleteat!,
eltype,
empty!,
empty,
endof,
filter!,
filter,
Expand Down
4 changes: 2 additions & 2 deletions base/pkg/query.jl
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,9 @@ end

# Specialized copy for the avail argument below because the deepcopy is slow
function availcopy(avail)
new_avail = similar(avail)
new_avail = empty(avail)
for (pkg, vers_avail) in avail
new_vers_avail = similar(vers_avail)
new_vers_avail = empty(vers_avail)
for (version, pkg_avail) in vers_avail
new_vers_avail[version] = copy(pkg_avail)
end
Expand Down
7 changes: 7 additions & 0 deletions base/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,10 @@ any(x::Tuple{}) = false
any(x::Tuple{Bool}) = x[1]
any(x::Tuple{Bool, Bool}) = x[1]|x[2]
any(x::Tuple{Bool, Bool, Bool}) = x[1]|x[2]|x[3]

"""
empty(x::Tuple)

Returns an empty tuple, `()`.
"""
empty(x::Tuple) = ()
3 changes: 1 addition & 2 deletions base/weakkeydict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,7 @@ function WeakKeyDict(kv)
end
end

similar(d::WeakKeyDict{K,V}) where {K,V} = WeakKeyDict{K,V}()
similar(d::WeakKeyDict, ::Type{Pair{K,V}}) where {K,V} = WeakKeyDict{K,V}()
empty(d::WeakKeyDict, ::Type{K}, ::Type{V}) where {K, V} = WeakKeyDict{K, V}()

# conversion between Dict types
function convert(::Type{WeakKeyDict{K,V}},d::Associative) where V where K
Expand Down
14 changes: 13 additions & 1 deletion test/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -870,10 +870,22 @@ end
Base.convert(::Type{Array{T,n}}, a::Array{T,n}) where {T<:Number,n} = a
Base.convert(::Type{Array{T,n}}, a::Array) where {T<:Number,n} =
copy!(Array{T,n}(uninitialized, size(a)), a)
@test isa(similar(Dict(:a=>1, :b=>2.0), Pair{Union{},Union{}}), Dict{Union{}, Union{}})
@test isa(empty(Dict(:a=>1, :b=>2.0), Union{}, Union{}), Dict{Union{}, Union{}})
end

@testset "zero-dimensional copy" begin
Z = Array{Int,0}(uninitialized); Z[] = 17
@test Z == collect(Z) == copy(Z)
end

@testset "empty" begin
@test isempty([])
v = [1, 2, 3]
v2 = empty(v)
v3 = empty(v, Float64)
@test !isempty(v)
empty!(v)
@test isempty(v)
@test isempty(v2::Vector{Int})
@test isempty(v3::Vector{Float64})
end
10 changes: 5 additions & 5 deletions test/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ end
a[1] = a
a[a] = 2

sa = similar(a)
sa = empty(a)
@test isempty(sa)
@test isa(sa, ObjectIdDict)

Expand Down Expand Up @@ -515,8 +515,8 @@ import Base.ImmutableDict
@test get(d, k1, :default) === :default
@test d1["key1"] === v1
@test d4["key1"] === v2
@test similar(d3) === d
@test similar(d) === d
@test empty(d3) === d
@test empty(d) === d

@test_throws KeyError d[k1]
@test_throws KeyError d1["key2"]
Expand Down Expand Up @@ -657,8 +657,8 @@ Dict(1 => rand(2,3), 'c' => "asdf") # just make sure this does not trigger a dep
@test !isempty(wkd)

wkd = empty!(wkd)
@test wkd == similar(wkd)
@test typeof(wkd) == typeof(similar(wkd))
@test wkd == empty(wkd)
@test typeof(wkd) == typeof(empty(wkd))
@test length(wkd) == 0
@test isempty(wkd)
@test isa(wkd, WeakKeyDict)
Expand Down
2 changes: 2 additions & 0 deletions test/tuple.jl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ end
@test Tuple{Int,Vararg{Any}}.ninitialized == 1
@test Tuple{Any,Any,Vararg{Any}}.ninitialized == 2
end

@test empty((1, 2.0, "c")) === ()
end

@testset "size" begin
Expand Down