From 0aca40ea83d2833c1389984ef56c14f022fd9622 Mon Sep 17 00:00:00 2001 From: Mauro Werder Date: Fri, 20 Jun 2014 16:45:20 +0100 Subject: [PATCH] Removed the WeakObjectIdDict and rebased. --- base/dict.jl | 417 ----------------------------------------------- base/help.jl | 10 +- base/metadata.jl | 8 +- test/help.jl | 2 +- test/metadata.jl | 2 + 5 files changed, 14 insertions(+), 425 deletions(-) diff --git a/base/dict.jl b/base/dict.jl index a3b098172adec..5381a97770d6c 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -754,420 +754,3 @@ function next{K}(t::WeakKeyDict{K}, i) ((kv[1].value::K,kv[2]), i) end length(t::WeakKeyDict) = length(t.ht) - -############################ -# Hacky weak object-id dict copy-pasted-adapted from Dict -# -# WeakObjectIdDict -# -# TODO: -# - take care of hash collisions when tidying up WeakRef(nothing) - -type WeakObjectIdDict{K,V} <: Associative{K,V} - slots::Array{Uint8,1} - keys::Array{WeakRef,1} - vals::Array{V,1} - ndel::Int - count::Int - deleter::Function - - function WeakObjectIdDict() - n = 16 - new(zeros(Uint8,n), Array(WeakRef,n), Array(V,n), 0, 0, identity) - end - function WeakObjectIdDict(ks, vs) - # TODO: eventually replace with a call to WeakObjectIdDict(zip(ks,vs)) - n = min(length(ks), length(vs)) - h = WeakObjectIdDict{K,V}() - for i=1:n - h[ks[i]] = vs[i] - end - return h - end - function WeakObjectIdDict(kv) - h = WeakObjectIdDict{K,V}() - for (k,v) in kv - h[k] = v - end - return h - end -end -WeakObjectIdDict() = WeakObjectIdDict{Any,Any}() - -WeakObjectIdDict{K,V}(ks::AbstractArray{K}, vs::AbstractArray{V}) = WeakObjectIdDict{K,V}(ks,vs) -WeakObjectIdDict(ks, vs) = WeakObjectIdDict{Any,Any}(ks, vs) - -# # conversion between WeakObjectIdDict types -# function convert{K,V}(::Type{WeakObjectIdDict{K,V}},d::WeakObjectIdDict) -# h = WeakObjectIdDict{K,V}() -# for (k,v) in d -# ck = convert(K,k) -# if !haskey(h,ck) -# h[ck] = convert(V,v) -# else -# error("key collision during dictionary conversion") -# end -# end -# return h -# end -# convert{K,V}(::Type{WeakObjectIdDict{K,V}},d::WeakObjectIdDict{K,V}) = d - -# syntax entry points -WeakObjectIdDict{K,V}(ks::(K...), vs::(V...)) = WeakObjectIdDict{K ,V }(ks, vs) -WeakObjectIdDict{K }(ks::(K...), vs::Tuple ) = WeakObjectIdDict{K ,Any}(ks, vs) -WeakObjectIdDict{V }(ks::Tuple , vs::(V...)) = WeakObjectIdDict{Any,V }(ks, vs) - -WeakObjectIdDict{K,V}(kv::AbstractArray{(K,V)}) = WeakObjectIdDict{K,V}(kv) -WeakObjectIdDict{K,V}(kv::Associative{K,V}) = WeakObjectIdDict{K,V}(kv) - -similar{K,V}(d::WeakObjectIdDict{K,V}) = (K=>V)[] - -function serialize(s, t::WeakObjectIdDict) - serialize_type(s, typeof(t)) - write(s, int32(length(t))) - for (k,v) in t - serialize(s, k) - serialize(s, v) - end -end - -function deserialize{K,V}(s, T::Type{WeakObjectIdDict{K,V}}) - n = read(s, Int32) - t = T(); sizehint(t, n) - for i = 1:n - k = deserialize(s) - v = deserialize(s) - t[k] = v - end - return t -end - -# use these functions to access the h.keys array. Does conversion to -# and from WeakRef. -gkey(h::WeakObjectIdDict, ind) = h.keys[ind].value - -skey!(h::WeakObjectIdDict, val, ind) = (h.keys[ind] = WeakRef(val)) -skey!(ar::Array{WeakRef,1}, val, ind) = (ar[ind] = WeakRef(val)) - -numslots(h::WeakObjectIdDict) = length(h.slots) - -hashindex(::WeakObjectIdDict, key, sz) = (int(hash(object_id(key))) & (sz-1)) + 1 - -isslotempty(h::WeakObjectIdDict, i::Int) = h.slots[i] == 0x0 -isslotfilled(h::WeakObjectIdDict, i::Int) = h.slots[i] == 0x1 -isslotmissing(h::WeakObjectIdDict, i::Int) = h.slots[i] == 0x2 - -function rehash{K,V}(h::WeakObjectIdDict{K,V}, newsz) - olds = h.slots - oldv = h.vals - sz = length(olds) - newsz = _tablesz(newsz) - indexnothing_old = hashindex(h, nothing, sz) - wnothing = WeakRef(nothing) - # check whether nothing is a key - if haskey(h, nothing) - error("Rehashing for a WeakObjectIdDict with 'nothing' as key is not yet implemented") - end - - if h.count == 0 - resize!(h.slots, newsz) - fill!(h.slots, 0x0) - resize!(h.keys, newsz) - resize!(h.vals, newsz) - h.ndel = 0 - return h - end - - slots = zeros(Uint8,newsz) - keys = Array(WeakRef, newsz) - vals = Array(V, newsz) - count0 = h.count - count = 0 - - for i = 1:sz - if olds[i] == 0x1 - k = gkey(h, i) - if k==wnothing #&& i!=indexnothing_old # TODO: do something about hash collisions! - # a gc'ed immutable was here - continue - end - v = oldv[i] - index = hashindex(h, k, newsz) - while slots[index] != 0 - index = (index & (newsz-1)) + 1 - end - slots[index] = 0x1 - skey!(keys, k, index) - vals[index] = v - count += 1 - - if h.count != count0 - # if items are removed by finalizers, retry - return rehash(h, newsz) - end - end - end - h.slots = slots - h.keys = keys - h.vals = vals - h.count = count - h.ndel = 0 - - return h -end - -function sizehint(d::WeakObjectIdDict, newsz) - oldsz = length(d.slots) - if newsz <= oldsz - # todo: shrink - # be careful: rehash() assumes everything fits. it was only designed - # for growing. - return d - end - # grow at least 25% - newsz = max(newsz, (oldsz*5)>>2) - rehash(d, newsz) -end - -function empty!{K,V}(h::WeakObjectIdDict{K,V}) - fill!(h.slots, 0x0) - sz = length(h.slots) - h.keys = Array(WeakRef, sz) - h.vals = Array(V, sz) - h.ndel = 0 - h.count = 0 - return h -end - -# get the index where a key is stored, or -1 if not present -function ht_keyindex{K,V}(h::WeakObjectIdDict{K,V}, key) - sz = numslots(h) - iter = 0 - maxprobe = max(16, sz>>6) - index = hashindex(h, key, sz) - - while true - if isslotempty(h,index) - break - end - if !isslotmissing(h,index) && isequal(key, gkey(h, index)) - return index - end - - index = (index & (sz-1)) + 1 # is this equal to modulo index+=1? - iter+=1 - iter > maxprobe && break - end - - return -1 -end - -# get the index where a key is stored, or -pos if not present -# and the key would be inserted at pos -# This version is for use by setindex! and get! -function ht_keyindex2{K,V}(h::WeakObjectIdDict{K,V}, key) - sz = numslots(h) - iter = 0 - maxprobe = max(16, sz>>6) - index = hashindex(h, key, sz) - avail = 0 - keys = h.keys - - while true - if isslotempty(h,index) - avail < 0 && return avail - return -index - end - - if isslotmissing(h,index) - if avail == 0 - # found an available slot, but need to keep scanning - # in case "key" already exists in a later collided slot. - avail = -index - end - elseif isequal(key, gkey(h, index)) - return index - end - - index = (index & (sz-1)) + 1 - iter+=1 - iter > maxprobe && break - end - - avail < 0 && return avail - - rehash(h, h.count > 64000 ? sz*2 : sz*4) - - return ht_keyindex2(h, key) -end - -function _setindex!(h::WeakObjectIdDict, v, key, index) - h.slots[index] = 0x1 - skey!(h, key, index) - h.vals[index] = v - h.count += 1 - - sz = numslots(h) - # Rehash now if necessary - if h.ndel >= ((3*sz)>>2) || h.count*3 > sz*2 - # > 3/4 deleted or > 2/3 full - rehash(h, h.count > 64000 ? h.count*2 : h.count*4) - end -end - -function weak_key_delete!(t::WeakObjectIdDict, k) - # when a weak key is finalized, remove from dictionary if it is still there - wk = getkey(t, k, secret_table_token) # gkey returns the WeakRef.value - if !is(wk,secret_table_token) && is(wk, k) - delete!(t, k) - end -end - -function setindex!{K,V}(h::WeakObjectIdDict{K,V}, v0, key0) - assert(isa(key0, K)) - if ~isimmutable(key0) - if is(h.deleter, identity) - h.deleter = x->weak_key_delete!(h, x) - end - finalizer(key0, h.deleter) - end - - v = convert(V, v0) - - index = ht_keyindex2(h, key0) - - if index > 0 - skey!(h, key0, index) - h.vals[index] = v - else - _setindex!(h, v, key0, -index) - end - - return h -end - -function get!{K,V}(h::WeakObjectIdDict{K,V}, key0, default) - assert(isa(key0, K)) - if ~isimmutable(key0) - if is(h.deleter, identity) - h.deleter = x->weak_key_delete!(h, x) - end - finalizer(key0, h.deleter) - end - - index = ht_keyindex2(h, key0) - - index > 0 && return h.vals[index] - - v = convert(V, default) - _setindex!(h, v, key0, -index) - return v -end - -function get!{K,V}(default::Function, h::WeakObjectIdDict{K,V}, key0) - assert(isa(key0, K)) - if ~isimmutable(key0) - if is(h.deleter, identity) - h.deleter = x->weak_key_delete!(h, x) - end - finalizer(key0, h.deleter) - end - - index = ht_keyindex2(h, key0) - - index > 0 && return h.vals[index] - - v = convert(V, default()) - _setindex!(h, v, key0, -index) - return v -end - -# NOTE: this macro is specific to WeakObjectIdDict, not Associative, and should -# therefore not be exported as-is: it's for internal use only. -macro get!(h, key0, default) - quote - K, V = eltype($(esc(h))) - assert( isa($(esc(key0)), K) ) - idx = ht_keyindex2($(esc(h)), $(esc(key0))) - if idx < 0 - idx = -idx - v = convert(V, $(esc(default))) - _setindex!($(esc(h)), v, $(esc(key0)), idx) - else - @inbounds v = $(esc(h)).vals[idx] - end - v - end -end - -function getindex{K,V}(h::WeakObjectIdDict{K,V}, key) - index = ht_keyindex(h, key) - return (index<0) ? throw(KeyError(key)) : h.vals[index]::V -end - -function get{K,V}(h::WeakObjectIdDict{K,V}, key, deflt) - index = ht_keyindex(h, key) - return (index<0) ? deflt : h.vals[index]::V -end - -function get{K,V}(deflt::Function, h::WeakObjectIdDict{K,V}, key) - index = ht_keyindex(h, key) - return (index<0) ? deflt() : h.vals[index]::V -end - -haskey(h::WeakObjectIdDict, key) = (ht_keyindex(h, key) >= 0) -in{T<:WeakObjectIdDict}(key, v::KeyIterator{T}) = (ht_keyindex(v.dict, key) >= 0) - -function getkey{K,V}(h::WeakObjectIdDict{K,V}, key, deflt) - index = ht_keyindex(h, key) - return (index<0) ? deflt : h.keys[index].value -end - -function _pop!(h::WeakObjectIdDict, index) - val = h.vals[index] - _delete!(h, index) - return val -end - -function pop!(h::WeakObjectIdDict, key) - index = ht_keyindex(h, key) - index > 0 ? _pop!(h, index) : throw(KeyError(key)) -end - -function pop!(h::WeakObjectIdDict, key, default) - index = ht_keyindex(h, key) - index > 0 ? _pop!(h, index) : default -end - -function _delete!(h::WeakObjectIdDict, index) - h.slots[index] = 0x2 - ccall(:jl_arrayunset, Void, (Any, Uint), h.keys, index-1) - ccall(:jl_arrayunset, Void, (Any, Uint), h.vals, index-1) - h.ndel += 1 - h.count -= 1 - h -end - -function delete!(h::WeakObjectIdDict, key) - index = ht_keyindex(h, key) - if index > 0; _delete!(h, index); end - h -end - -function skip_deleted(h::WeakObjectIdDict, i) - L = length(h.slots) - while i<=L && !isslotfilled(h,i) - i += 1 - end - return i -end - -start(t::WeakObjectIdDict) = skip_deleted(t, 1) -done(t::WeakObjectIdDict, i) = done(t.vals, i) -next(t::WeakObjectIdDict, i) = ((getkey(t,i), t.vals[i]), skip_deleted(t,i+1)) - -isempty(t::WeakObjectIdDict) = (t.count == 0) -length(t::WeakObjectIdDict) = t.count - -next{T<:WeakObjectIdDict}(v::KeyIterator{T}, i) = (v.dict.keys[i], skip_deleted(v.dict,i+1)) -next{T<:WeakObjectIdDict}(v::ValueIterator{T}, i) = (v.dict.vals[i], skip_deleted(v.dict,i+1)) diff --git a/base/help.jl b/base/help.jl index fb64cfb2cac2e..e04b34468cd4c 100644 --- a/base/help.jl +++ b/base/help.jl @@ -12,10 +12,10 @@ import Base.WeakObjectIdDict # :mod : module which contains this object/concept/keyword (if applicable) type HelpEntry desc::String # description - mod::Union(Module,String,Nothing) # module of entry. This is useful for type instances + mod::Union(Module,String) # module of entry. This is useful for type instances # for which figuring out the defining module is hard. - HelpEntry() = new("", nothing) - HelpEntry(desc) = new(desc, nothing) + HelpEntry() = new("", "") + HelpEntry(desc) = new(desc, "") HelpEntry(desc, mod) = new(desc, mod) end @@ -126,7 +126,7 @@ end # user-created help ## -function doc(obj, docstr::String; mod=nothing, string_into_meta=false) +function doc(obj, docstr::String; mod="", string_into_meta=false) # the module cannot be set automatically with this function, use the macro instead setdoc!(obj, HelpEntry(docstr, mod); string_into_meta=string_into_meta) end @@ -206,7 +206,7 @@ end function _decor_help_desc(obj, mod, desc::String) # adds information about module, signature and such. Probably needs updating. func = string(obj) - if !isequal(mod,nothing) + if !isequal(mod,"") mfunc = string(mod) * "." * func else mfunc = string(obj) diff --git a/base/metadata.jl b/base/metadata.jl index a141d53418a08..6e10235086010 100644 --- a/base/metadata.jl +++ b/base/metadata.jl @@ -12,10 +12,14 @@ typealias MetaData Dict{Any,Any} # The Dict for META: -typealias MetaDict WeakObjectIdDict{Any, MetaData} + +#typealias MetaDict WeakObjectIdDict{Any, MetaData} # not in base but see PR https://github.com/JuliaLang/julia/pull/7348 #typealias MetaDict WeakKeyDict{Any, MetaData} # Problem: does not work for immutables #typealias MetaDict Dict{Any, MetaData} # Problem: if a mutable changes the hash changes -#typealias MetaDict ObjectIdDict # Problem: does not free references +typealias MetaDict ObjectIdDict # Problem: does not free references + +## when using ObjectIdDict add a get! method to ObjectIdDict +get!(od::ObjectIdDict, key, default) = haskey(od,key) ? od[key] : od[key] = default META = MetaDict() # this holds all the metadata diff --git a/test/help.jl b/test/help.jl index 79a9273cdf0a4..850469e12b375 100644 --- a/test/help.jl +++ b/test/help.jl @@ -87,7 +87,7 @@ b = Dict() st = randstring(5); st2 = randstring(5) doc(b, st) @test getdoc(b).desc==st -@test getdoc(b).mod==nothing +@test getdoc(b).mod=="" @test hasmeta(b) doc(b, st; mod=Base) @test getdoc(b).desc==st diff --git a/test/metadata.jl b/test/metadata.jl index 78481ea729f54..c194b2f72920f 100644 --- a/test/metadata.jl +++ b/test/metadata.jl @@ -65,6 +65,8 @@ totest = { ## empty: testkey = 5 for te in totest + # @show te + # @show getmeta(te) @test_throws KeyError getmeta(te) @test isequal(getmeta(te, testkey, nothing), nothing) end