fix incorrect folder name for julia-0.6.x
Former-commit-id: ef2c7401e0876f22d2f7762d182cfbcd5a7d9c70
This commit is contained in:
477
julia-0.6.3/share/julia/base/associative.jl
Normal file
477
julia-0.6.3/share/julia/base/associative.jl
Normal file
@@ -0,0 +1,477 @@
|
||||
# This file is a part of Julia. License is MIT: https://julialang.org/license
|
||||
|
||||
# generic operations on associative collections
|
||||
|
||||
const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__
|
||||
|
||||
haskey(d::Associative, k) = in(k,keys(d))
|
||||
|
||||
function in(p::Pair, a::Associative, valcmp=(==))
|
||||
v = get(a,p[1],secret_table_token)
|
||||
if v !== secret_table_token
|
||||
valcmp(v, p[2]) && return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function in(p, a::Associative)
|
||||
error("""Associative collections only contain Pairs;
|
||||
Either look for e.g. A=>B instead, or use the `keys` or `values`
|
||||
function if you are looking for a key or value respectively.""")
|
||||
end
|
||||
|
||||
function summary(t::Associative)
|
||||
n = length(t)
|
||||
return string(typeof(t), " with ", n, (n==1 ? " entry" : " entries"))
|
||||
end
|
||||
|
||||
struct KeyIterator{T<:Associative}
|
||||
dict::T
|
||||
end
|
||||
struct ValueIterator{T<:Associative}
|
||||
dict::T
|
||||
end
|
||||
|
||||
summary{T<:Union{KeyIterator,ValueIterator}}(iter::T) =
|
||||
string(T.name, " for a ", summary(iter.dict))
|
||||
|
||||
show(io::IO, iter::Union{KeyIterator,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
|
||||
_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)
|
||||
|
||||
function next(v::KeyIterator, state)
|
||||
n = next(v.dict, state)
|
||||
n[1][1], n[2]
|
||||
end
|
||||
|
||||
function next(v::ValueIterator, state)
|
||||
n = next(v.dict, state)
|
||||
n[1][2], n[2]
|
||||
end
|
||||
|
||||
in(k, v::KeyIterator) = get(v.dict, k, secret_table_token) !== secret_table_token
|
||||
|
||||
|
||||
"""
|
||||
keys(a::Associative)
|
||||
|
||||
Return an iterator over all keys in a collection.
|
||||
`collect(keys(a))` returns an array of keys.
|
||||
Since the keys are stored internally in a hash table,
|
||||
the order in which they are returned may vary.
|
||||
But `keys(a)` and `values(a)` both iterate `a` and
|
||||
return the elements in the same order.
|
||||
|
||||
```jldoctest
|
||||
julia> a = Dict('a'=>2, 'b'=>3)
|
||||
Dict{Char,Int64} with 2 entries:
|
||||
'b' => 3
|
||||
'a' => 2
|
||||
|
||||
julia> collect(keys(a))
|
||||
2-element Array{Char,1}:
|
||||
'b'
|
||||
'a'
|
||||
```
|
||||
"""
|
||||
keys(a::Associative) = KeyIterator(a)
|
||||
eachindex(a::Associative) = KeyIterator(a)
|
||||
|
||||
"""
|
||||
values(a::Associative)
|
||||
|
||||
Return an iterator over all values in a collection.
|
||||
`collect(values(a))` returns an array of values.
|
||||
Since the values are stored internally in a hash table,
|
||||
the order in which they are returned may vary.
|
||||
But `keys(a)` and `values(a)` both iterate `a` and
|
||||
return the elements in the same order.
|
||||
|
||||
```jldoctest
|
||||
julia> a = Dict('a'=>2, 'b'=>3)
|
||||
Dict{Char,Int64} with 2 entries:
|
||||
'b' => 3
|
||||
'a' => 2
|
||||
|
||||
julia> collect(values(a))
|
||||
2-element Array{Int64,1}:
|
||||
3
|
||||
2
|
||||
```
|
||||
"""
|
||||
values(a::Associative) = ValueIterator(a)
|
||||
|
||||
function copy(a::Associative)
|
||||
b = similar(a)
|
||||
for (k,v) in a
|
||||
b[k] = v
|
||||
end
|
||||
return b
|
||||
end
|
||||
|
||||
"""
|
||||
merge!(d::Associative, others::Associative...)
|
||||
|
||||
Update collection with pairs from the other collections.
|
||||
See also [`merge`](@ref).
|
||||
|
||||
```jldoctest
|
||||
julia> d1 = Dict(1 => 2, 3 => 4);
|
||||
|
||||
julia> d2 = Dict(1 => 4, 4 => 5);
|
||||
|
||||
julia> merge!(d1, d2);
|
||||
|
||||
julia> d1
|
||||
Dict{Int64,Int64} with 3 entries:
|
||||
4 => 5
|
||||
3 => 4
|
||||
1 => 4
|
||||
```
|
||||
"""
|
||||
function merge!(d::Associative, others::Associative...)
|
||||
for other in others
|
||||
for (k,v) in other
|
||||
d[k] = v
|
||||
end
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
"""
|
||||
merge!(combine, d::Associative, others::Associative...)
|
||||
|
||||
Update collection with pairs from the other collections.
|
||||
Values with the same key will be combined using the
|
||||
combiner function.
|
||||
|
||||
```jldoctest
|
||||
julia> d1 = Dict(1 => 2, 3 => 4);
|
||||
|
||||
julia> d2 = Dict(1 => 4, 4 => 5);
|
||||
|
||||
julia> merge!(+, d1, d2);
|
||||
|
||||
julia> d1
|
||||
Dict{Int64,Int64} with 3 entries:
|
||||
4 => 5
|
||||
3 => 4
|
||||
1 => 6
|
||||
|
||||
julia> merge!(-, d1, d1);
|
||||
|
||||
julia> d1
|
||||
Dict{Int64,Int64} with 3 entries:
|
||||
4 => 0
|
||||
3 => 0
|
||||
1 => 0
|
||||
```
|
||||
"""
|
||||
function merge!(combine::Function, d::Associative, others::Associative...)
|
||||
for other in others
|
||||
for (k,v) in other
|
||||
d[k] = haskey(d, k) ? combine(d[k], v) : v
|
||||
end
|
||||
end
|
||||
return d
|
||||
end
|
||||
|
||||
# very similar to `merge!`, but accepts any iterable and extends code
|
||||
# that would otherwise only use `copy!` with arrays.
|
||||
function copy!(dest::Union{Associative,AbstractSet}, src)
|
||||
for x in src
|
||||
push!(dest, x)
|
||||
end
|
||||
return dest
|
||||
end
|
||||
|
||||
"""
|
||||
keytype(type)
|
||||
|
||||
Get the key type of an associative collection type. Behaves similarly to [`eltype`](@ref).
|
||||
|
||||
```jldoctest
|
||||
julia> keytype(Dict(Int32(1) => "foo"))
|
||||
Int32
|
||||
```
|
||||
"""
|
||||
keytype(::Type{Associative{K,V}}) where {K,V} = K
|
||||
keytype(a::Associative) = keytype(typeof(a))
|
||||
keytype(::Type{A}) where {A<:Associative} = keytype(supertype(A))
|
||||
|
||||
"""
|
||||
valtype(type)
|
||||
|
||||
Get the value type of an associative collection type. Behaves similarly to [`eltype`](@ref).
|
||||
|
||||
```jldoctest
|
||||
julia> valtype(Dict(Int32(1) => "foo"))
|
||||
String
|
||||
```
|
||||
"""
|
||||
valtype(::Type{Associative{K,V}}) where {K,V} = V
|
||||
valtype{A<:Associative}(::Type{A}) = valtype(supertype(A))
|
||||
valtype(a::Associative) = valtype(typeof(a))
|
||||
|
||||
"""
|
||||
merge(d::Associative, others::Associative...)
|
||||
|
||||
Construct a merged collection from the given collections. If necessary, the
|
||||
types of the resulting collection will be promoted to accommodate the types of
|
||||
the merged collections. If the same key is present in another collection, the
|
||||
value for that key will be the value it has in the last collection listed.
|
||||
|
||||
```jldoctest
|
||||
julia> a = Dict("foo" => 0.0, "bar" => 42.0)
|
||||
Dict{String,Float64} with 2 entries:
|
||||
"bar" => 42.0
|
||||
"foo" => 0.0
|
||||
|
||||
julia> b = Dict("baz" => 17, "bar" => 4711)
|
||||
Dict{String,Int64} with 2 entries:
|
||||
"bar" => 4711
|
||||
"baz" => 17
|
||||
|
||||
julia> merge(a, b)
|
||||
Dict{String,Float64} with 3 entries:
|
||||
"bar" => 4711.0
|
||||
"baz" => 17.0
|
||||
"foo" => 0.0
|
||||
|
||||
julia> merge(b, a)
|
||||
Dict{String,Float64} with 3 entries:
|
||||
"bar" => 42.0
|
||||
"baz" => 17.0
|
||||
"foo" => 0.0
|
||||
```
|
||||
"""
|
||||
merge(d::Associative, others::Associative...) =
|
||||
merge!(emptymergedict(d, others...), d, others...)
|
||||
|
||||
"""
|
||||
merge(combine, d::Associative, others::Associative...)
|
||||
|
||||
Construct a merged collection from the given collections. If necessary, the
|
||||
types of the resulting collection will be promoted to accommodate the types of
|
||||
the merged collections. Values with the same key will be combined using the
|
||||
combiner function.
|
||||
|
||||
```jldoctest
|
||||
julia> a = Dict("foo" => 0.0, "bar" => 42.0)
|
||||
Dict{String,Float64} with 2 entries:
|
||||
"bar" => 42.0
|
||||
"foo" => 0.0
|
||||
|
||||
julia> b = Dict("baz" => 17, "bar" => 4711)
|
||||
Dict{String,Int64} with 2 entries:
|
||||
"bar" => 4711
|
||||
"baz" => 17
|
||||
|
||||
julia> merge(+, a, b)
|
||||
Dict{String,Float64} with 3 entries:
|
||||
"bar" => 4753.0
|
||||
"baz" => 17.0
|
||||
"foo" => 0.0
|
||||
```
|
||||
"""
|
||||
merge(combine::Function, d::Associative, others::Associative...) =
|
||||
merge!(combine, emptymergedict(d, others...), d, others...)
|
||||
|
||||
promoteK(K) = K
|
||||
promoteV(V) = V
|
||||
promoteK(K, d, ds...) = promoteK(promote_type(K, keytype(d)), ds...)
|
||||
promoteV(V, d, ds...) = promoteV(promote_type(V, valtype(d)), ds...)
|
||||
function emptymergedict(d::Associative, others::Associative...)
|
||||
K = promoteK(keytype(d), others...)
|
||||
V = promoteV(valtype(d), others...)
|
||||
Dict{K,V}()
|
||||
end
|
||||
|
||||
function filter!(f, d::Associative)
|
||||
badkeys = Vector{keytype(d)}(0)
|
||||
for (k,v) in d
|
||||
# don't delete!(d, k) here, since associative types
|
||||
# may not support mutation during iteration
|
||||
f(k,v) || push!(badkeys, k)
|
||||
end
|
||||
for k in badkeys
|
||||
delete!(d, k)
|
||||
end
|
||||
return d
|
||||
end
|
||||
function filter(f, d::Associative)
|
||||
# don't just do filter!(f, copy(d)): avoid making a whole copy of d
|
||||
df = similar(d)
|
||||
for (k,v) in d
|
||||
if f(k,v)
|
||||
df[k] = v
|
||||
end
|
||||
end
|
||||
return df
|
||||
end
|
||||
|
||||
eltype(::Type{Associative{K,V}}) where {K,V} = Pair{K,V}
|
||||
|
||||
function isequal(l::Associative, r::Associative)
|
||||
l === r && return true
|
||||
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
|
||||
return false
|
||||
end
|
||||
if length(l) != length(r) return false end
|
||||
for pair in l
|
||||
if !in(pair, r, isequal)
|
||||
return false
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
function ==(l::Associative, r::Associative)
|
||||
l === r && return true
|
||||
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
|
||||
return false
|
||||
end
|
||||
if length(l) != length(r) return false end
|
||||
for pair in l
|
||||
if !in(pair, r, ==)
|
||||
return false
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
const hasha_seed = UInt === UInt64 ? 0x6d35bb51952d5539 : 0x952d5539
|
||||
function hash(a::Associative, h::UInt)
|
||||
hv = hasha_seed
|
||||
for (k,v) in a
|
||||
hv ⊻= hash(k, hash(v))
|
||||
end
|
||||
hash(hv, h)
|
||||
end
|
||||
|
||||
function getindex(t::Associative, key)
|
||||
v = get(t, key, secret_table_token)
|
||||
if v === secret_table_token
|
||||
throw(KeyError(key))
|
||||
end
|
||||
return v
|
||||
end
|
||||
|
||||
# t[k1,k2,ks...] is syntactic sugar for t[(k1,k2,ks...)]. (Note
|
||||
# that we need to avoid dispatch loops if setindex!(t,v,k) is not defined.)
|
||||
getindex(t::Associative, k1, k2, ks...) = getindex(t, tuple(k1,k2,ks...))
|
||||
setindex!(t::Associative, v, k1, k2, ks...) = setindex!(t, v, tuple(k1,k2,ks...))
|
||||
|
||||
push!(t::Associative, p::Pair) = setindex!(t, p.second, p.first)
|
||||
push!(t::Associative, p::Pair, q::Pair) = push!(push!(t, p), q)
|
||||
push!(t::Associative, p::Pair, q::Pair, r::Pair...) = push!(push!(push!(t, p), q), r...)
|
||||
|
||||
# hashing objects by identity
|
||||
|
||||
"""
|
||||
ObjectIdDict([itr])
|
||||
|
||||
`ObjectIdDict()` constructs a hash table where the keys are (always)
|
||||
object identities. Unlike `Dict` it is not parameterized on its key
|
||||
and value type and thus its `eltype` is always `Pair{Any,Any}`.
|
||||
|
||||
See [`Dict`](@ref) for further help.
|
||||
"""
|
||||
mutable struct ObjectIdDict <: Associative{Any,Any}
|
||||
ht::Vector{Any}
|
||||
ndel::Int
|
||||
ObjectIdDict() = new(Vector{Any}(32), 0)
|
||||
|
||||
function ObjectIdDict(itr)
|
||||
d = ObjectIdDict()
|
||||
for (k,v) in itr; d[k] = v; end
|
||||
d
|
||||
end
|
||||
|
||||
function ObjectIdDict(pairs::Pair...)
|
||||
d = ObjectIdDict()
|
||||
for (k,v) in pairs; d[k] = v; end
|
||||
d
|
||||
end
|
||||
|
||||
ObjectIdDict(o::ObjectIdDict) = new(copy(o.ht))
|
||||
end
|
||||
|
||||
similar(d::ObjectIdDict) = ObjectIdDict()
|
||||
|
||||
function rehash!(t::ObjectIdDict, newsz = length(t.ht))
|
||||
t.ht = ccall(:jl_idtable_rehash, Any, (Any, Csize_t), t.ht, newsz)
|
||||
t
|
||||
end
|
||||
|
||||
function sizehint!(t::ObjectIdDict, newsz)
|
||||
newsz = _tablesz(newsz*2) # *2 for keys and values in same array
|
||||
oldsz = length(t.ht)
|
||||
# grow at least 25%
|
||||
if newsz < (oldsz*5)>>2
|
||||
return t
|
||||
end
|
||||
rehash!(t, newsz)
|
||||
end
|
||||
|
||||
function setindex!(t::ObjectIdDict, v::ANY, k::ANY)
|
||||
if t.ndel >= ((3*length(t.ht))>>2)
|
||||
rehash!(t, max(length(t.ht)>>1, 32))
|
||||
t.ndel = 0
|
||||
end
|
||||
t.ht = ccall(:jl_eqtable_put, Array{Any,1}, (Any, Any, Any), t.ht, k, v)
|
||||
return t
|
||||
end
|
||||
|
||||
get(t::ObjectIdDict, key::ANY, default::ANY) =
|
||||
ccall(:jl_eqtable_get, Any, (Any, Any, Any), t.ht, key, default)
|
||||
|
||||
function pop!(t::ObjectIdDict, key::ANY, default::ANY)
|
||||
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any), t.ht, key, default)
|
||||
# TODO: this can underestimate `ndel`
|
||||
val === default || (t.ndel += 1)
|
||||
return val
|
||||
end
|
||||
|
||||
function pop!(t::ObjectIdDict, key::ANY)
|
||||
val = pop!(t, key, secret_table_token)
|
||||
val !== secret_table_token ? val : throw(KeyError(key))
|
||||
end
|
||||
|
||||
function delete!(t::ObjectIdDict, key::ANY)
|
||||
pop!(t, key, secret_table_token)
|
||||
t
|
||||
end
|
||||
|
||||
function empty!(t::ObjectIdDict)
|
||||
resize!(t.ht, 32)
|
||||
ccall(:memset, Ptr{Void}, (Ptr{Void}, Cint, Csize_t), t.ht, 0, sizeof(t.ht))
|
||||
t.ndel = 0
|
||||
return t
|
||||
end
|
||||
|
||||
_oidd_nextind(a, i) = reinterpret(Int,ccall(:jl_eqtable_nextind, Csize_t, (Any, Csize_t), a, i))
|
||||
|
||||
start(t::ObjectIdDict) = _oidd_nextind(t.ht, 0)
|
||||
done(t::ObjectIdDict, i) = (i == -1)
|
||||
next(t::ObjectIdDict, i) = (Pair{Any,Any}(t.ht[i+1],t.ht[i+2]), _oidd_nextind(t.ht, i+2))
|
||||
|
||||
function length(d::ObjectIdDict)
|
||||
n = 0
|
||||
for pair in d
|
||||
n+=1
|
||||
end
|
||||
n
|
||||
end
|
||||
|
||||
copy(o::ObjectIdDict) = ObjectIdDict(o)
|
||||
|
||||
get!(o::ObjectIdDict, key, default) = (o[key] = get(o, key, default))
|
||||
Reference in New Issue
Block a user