Skip to content

Commit

Permalink
formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
haberdashPI committed Apr 3, 2024
1 parent bc39a49 commit b2dd98a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 62 deletions.
46 changes: 25 additions & 21 deletions src/WeakKeyIdDicts.jl
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct WeakRefForWeakDict
WeakRefForWeakDict(@nospecialize(v)) = new(WeakRef(v))
end

Base.:(==)(wr1::WeakRefForWeakDict, wr2::WeakRefForWeakDict) = wr1.w.value===wr2.w.value
Base.:(==)(wr1::WeakRefForWeakDict, wr2::WeakRefForWeakDict) = wr1.w.value === wr2.w.value
Base.hash(wr::WeakRefForWeakDict, h::UInt) = Base.hash_uint(3h - objectid(wr.w.value))

"""
Expand All @@ -50,21 +50,23 @@ mutable struct WeakKeyIdDict{K,V} <: AbstractDict{K,V}
dirty::Bool

# Constructors mirror Dict's
function WeakKeyIdDict{K,V}() where V where K
function WeakKeyIdDict{K,V}() where {V} where {K}
t = new(Dict{WeakRefForWeakDict,V}(), ReentrantLock(), identity, 0)
t.finalizer = k -> t.dirty = true
return t
end
end
function WeakKeyIdDict{K,V}(kv) where V where K
function WeakKeyIdDict{K,V}(kv) where {V} where {K}
h = WeakKeyIdDict{K,V}()
for (k,v) in kv
for (k, v) in kv
h[k] = v
end
return h
end
WeakKeyIdDict{K,V}(p::Pair) where V where K = setindex!(WeakKeyIdDict{K,V}(), p.second, p.first)
function WeakKeyIdDict{K,V}(ps::Pair...) where V where K
function WeakKeyIdDict{K,V}(p::Pair) where {V} where {K}
return setindex!(WeakKeyIdDict{K,V}(), p.second, p.first)
end
function WeakKeyIdDict{K,V}(ps::Pair...) where {V} where {K}
h = WeakKeyIdDict{K,V}()
sizehint!(h, length(ps))
for p in ps
Expand All @@ -77,16 +79,16 @@ WeakKeyIdDict() = WeakKeyIdDict{Any,Any}()
WeakKeyIdDict(kv::Tuple{}) = WeakKeyIdDict()
Base.copy(d::WeakKeyIdDict) = WeakKeyIdDict(d)

WeakKeyIdDict(ps::Pair{K,V}...) where {K,V} = WeakKeyIdDict{K,V}(ps)
WeakKeyIdDict(ps::Pair{K}...) where {K} = WeakKeyIdDict{K,Any}(ps)
WeakKeyIdDict(ps::(Pair{K,V} where K)...) where {V} = WeakKeyIdDict{Any,V}(ps)
WeakKeyIdDict(ps::Pair...) = WeakKeyIdDict{Any,Any}(ps)
WeakKeyIdDict(ps::Pair{K,V}...) where {K,V} = WeakKeyIdDict{K,V}(ps)
WeakKeyIdDict(ps::Pair{K}...) where {K} = WeakKeyIdDict{K,Any}(ps)
WeakKeyIdDict(ps::(Pair{K,V} where {K})...) where {V} = WeakKeyIdDict{Any,V}(ps)
WeakKeyIdDict(ps::Pair...) = WeakKeyIdDict{Any,Any}(ps)

function WeakKeyIdDict(kv)
try
Base.dict_with_eltype((K, V) -> WeakKeyIdDict{K, V}, kv, eltype(kv))
Base.dict_with_eltype((K, V) -> WeakKeyIdDict{K,V}, kv, eltype(kv))
catch
if !Base.isiterable(typeof(kv)) || !all(x->isa(x,Union{Tuple,Pair}),kv)
if !Base.isiterable(typeof(kv)) || !all(x -> isa(x, Union{Tuple,Pair}), kv)
throw(ArgumentError("WeakKeyIdDict(kv): kv needs to be an iterator of tuples or pairs"))
else
rethrow()
Expand All @@ -109,7 +111,7 @@ function _cleanup_locked(h::WeakKeyIdDict)
end

Base.sizehint!(d::WeakKeyIdDict, newsz) = sizehint!(d.ht, newsz)
Base.empty(d::WeakKeyIdDict, ::Type{K}, ::Type{V}) where {K, V} = WeakKeyIdDict{K, V}()
Base.empty(d::WeakKeyIdDict, ::Type{K}, ::Type{V}) where {K,V} = WeakKeyIdDict{K,V}()

Base.IteratorSize(::Type{<:WeakKeyIdDict}) = Base.SizeUnknown()

Expand All @@ -119,7 +121,7 @@ Base.unlock(wkh::WeakKeyIdDict) = unlock(wkh.lock)
Base.lock(f, wkh::WeakKeyIdDict) = lock(f, wkh.lock)
Base.trylock(f, wkh::WeakKeyIdDict) = trylock(f, wkh.lock)

Check warning on line 122 in src/WeakKeyIdDicts.jl

View check run for this annotation

Codecov / codecov/patch

src/WeakKeyIdDicts.jl#L122

Added line #L122 was not covered by tests

function Base.setindex!(wkh::WeakKeyIdDict{K}, v, key) where K
function Base.setindex!(wkh::WeakKeyIdDict{K}, v, key) where {K}
!isa(key, K) && throw(ArgumentError("$key is not a valid key for type $K"))
# 'nothing' is not valid both because 'finalizer' will reject it,
# and because we therefore use it as a sentinel value
Expand All @@ -133,7 +135,7 @@ function Base.setindex!(wkh::WeakKeyIdDict{K}, v, key) where K
else
k.w.value = key
end
wkh.ht[k] = v
return wkh.ht[k] = v
end
return wkh
end
Expand All @@ -160,7 +162,7 @@ function Base.get!(default::Base.Callable, wkh::WeakKeyIdDict{K}, key) where {K}
return v
end

function Base.getkey(wkh::WeakKeyIdDict{K}, kk, default) where K
function Base.getkey(wkh::WeakKeyIdDict{K}, kk, default) where {K}
k = lock(wkh) do
local k = getkey(wkh.ht, WeakRefForWeakDict(kk), nothing)
k === nothing && return nothing
Expand All @@ -169,7 +171,7 @@ function Base.getkey(wkh::WeakKeyIdDict{K}, kk, default) where K
return k === nothing ? default : k::K
end

Base.map!(f, iter::Base.ValueIterator{<:WeakKeyIdDict})= Base.map!(f, values(iter.dict.ht))
Base.map!(f, iter::Base.ValueIterator{<:WeakKeyIdDict}) = Base.map!(f, values(iter.dict.ht))

function Base.get(wkh::WeakKeyIdDict{K}, key, default) where {K}
key === nothing && throw(KeyError(nothing))
Expand Down Expand Up @@ -199,36 +201,38 @@ function Base.delete!(wkh::WeakKeyIdDict, key)
key === nothing && return wkh
lock(wkh) do
delete!(wkh.ht, WeakRefForWeakDict(key))
return
end
return wkh
end
function Base.empty!(wkh::WeakKeyIdDict)
lock(wkh) do
empty!(wkh.ht)
return
end
return wkh
end
function Base.haskey(wkh::WeakKeyIdDict{K}, key) where {K}
key === nothing && return false
lock(wkh) do
return lock(wkh) do
return haskey(wkh.ht, WeakRefForWeakDict(key))
end
end
function Base.getindex(wkh::WeakKeyIdDict{K}, key) where {K}
key === nothing && throw(KeyError(nothing))
lock(wkh) do
return lock(wkh) do
return getindex(wkh.ht, WeakRefForWeakDict(key))
end
end
Base.isempty(wkh::WeakKeyIdDict) = length(wkh) == 0
function Base.length(t::WeakKeyIdDict)
lock(t) do
return lock(t) do
_cleanup_locked(t)
return length(t.ht)
end
end

function Base.iterate(t::WeakKeyIdDict{K,V}, state...) where {K, V}
function Base.iterate(t::WeakKeyIdDict{K,V}, state...) where {K,V}
return lock(t) do
while true
y = iterate(t.ht, state...)
Expand Down
83 changes: 42 additions & 41 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,31 @@ include("set_up_tests.jl")
wkd[A] = 2
wkd[B] = 3
wkd[C] = 4
dd = convert(Dict{Any,Any},wkd)
dd = convert(Dict{Any,Any}, wkd)
@test WeakKeyIdDict(dd) == wkd
@test convert(WeakKeyIdDict{Any, Any}, dd) == wkd
@test convert(WeakKeyIdDict{Any,Any}, dd) == wkd
@test isa(WeakKeyIdDict(dd), WeakKeyIdDict{Any,Any})

# test many constructors without type parameters specified
@test WeakKeyIdDict(A=>2, B=>3, C=>4) == wkd
@test isa(WeakKeyIdDict(A=>2, B=>3, C=>4), WeakKeyIdDict{Vector{Int},Int})
@test WeakKeyIdDict(a=>i+1 for (i,a) in enumerate([A,B,C]) ) == wkd
@test WeakKeyIdDict([(A,2), (B,3), (C,4)]) == wkd
@test WeakKeyIdDict(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
@test WeakKeyIdDict(A => 2, B => 3, C => 4) == wkd
@test isa(WeakKeyIdDict(A => 2, B => 3, C => 4), WeakKeyIdDict{Vector{Int},Int})
@test WeakKeyIdDict(a => i + 1 for (i, a) in enumerate([A, B, C])) == wkd
@test WeakKeyIdDict([(A, 2), (B, 3), (C, 4)]) == wkd
@test WeakKeyIdDict(Pair(A, 2), Pair(B, 3), Pair(C, 4)) == wkd

# test many constructors with type parameters specified
@test WeakKeyIdDict{Vector{Int},Int}(A=>2, B=>3, C=>4) == wkd
@test isa(WeakKeyIdDict{Vector{Int},Int}(A=>2, B=>3, C=>4), WeakKeyIdDict{Vector{Int},Int})
@test WeakKeyIdDict{Vector{Int},Int}(a=>i+1 for (i,a) in enumerate([A,B,C]) ) == wkd
@test WeakKeyIdDict{Vector{Int},Int}([(A,2), (B,3), (C,4)]) == wkd
@test WeakKeyIdDict{Vector{Int},Int}(Pair(A,2), Pair(B,3), Pair(C,4)) == wkd
@test WeakKeyIdDict{Vector{Int},Int}(A => 2, B => 3, C => 4) == wkd
@test isa(WeakKeyIdDict{Vector{Int},Int}(A => 2, B => 3, C => 4),
WeakKeyIdDict{Vector{Int},Int})
@test WeakKeyIdDict{Vector{Int},Int}(a => i + 1 for (i, a) in enumerate([A, B, C])) ==
wkd
@test WeakKeyIdDict{Vector{Int},Int}([(A, 2), (B, 3), (C, 4)]) == wkd
@test WeakKeyIdDict{Vector{Int},Int}(Pair(A, 2), Pair(B, 3), Pair(C, 4)) == wkd

# test more constructors with mixed types
@test isa(WeakKeyIdDict(A=>2, B=>3, C=>"4"), WeakKeyIdDict{Vector{Int},Any})
@test isa(WeakKeyIdDict(A=>2, B=>3, "C"=>4), WeakKeyIdDict{Any,Int})
@test isa(WeakKeyIdDict(A=>2, B=>3, "C"=>"4"), WeakKeyIdDict{Any,Any})
@test isa(WeakKeyIdDict(A => 2, B => 3, C => "4"), WeakKeyIdDict{Vector{Int},Any})
@test isa(WeakKeyIdDict(A => 2, B => 3, "C" => 4), WeakKeyIdDict{Any,Int})
@test isa(WeakKeyIdDict(A => 2, B => 3, "C" => "4"), WeakKeyIdDict{Any,Any})

@test copy(wkd) == wkd

Expand All @@ -56,7 +58,7 @@ include("set_up_tests.jl")
@test !isempty(wkd)
@test 47 == pop!(wkd, C, 47)
@test getkey(wkd, C, 123) == 123
wkd = filter!( p -> p.first != B, wkd)
wkd = filter!(p -> p.first != B, wkd)
@test B keys(wkd)
@test 3 values(wkd)
@test length(wkd) == 1
Expand All @@ -66,30 +68,30 @@ include("set_up_tests.jl")
wkd[A] = 42
@test wkd[A] == 42

wkd = WeakKeyIdDict(A=>2, B=>3, C=>4)
wkd = WeakKeyIdDict(A => 2, B => 3, C => 4)
map!(x -> x + 1, values(wkd))
@test WeakKeyIdDict(A=>3, B=>4, C=>5) == wkd
@test WeakKeyIdDict(A => 3, B => 4, C => 5) == wkd

wkd = WeakKeyIdDict(A=>2, B=>3, C=>4)
@test delete!(wkd, A) == WeakKeyIdDict(B=>3, C=>4)
@test delete!(wkd, A) == WeakKeyIdDict(B=>3, C=>4) # deleting the same key twice works
@test delete!(wkd, C) == WeakKeyIdDict(B=>3)
wkd = WeakKeyIdDict(A => 2, B => 3, C => 4)
@test delete!(wkd, A) == WeakKeyIdDict(B => 3, C => 4)
@test delete!(wkd, A) == WeakKeyIdDict(B => 3, C => 4) # deleting the same key twice works
@test delete!(wkd, C) == WeakKeyIdDict(B => 3)
@test delete!(wkd, B) == WeakKeyIdDict()
# adding stuff back is OK
wkd[A] = 2
wkd[B] = 3
wkd[C] = 4
@test wkd == WeakKeyIdDict(A=>2, B=>3, C=>4)
@test wkd == WeakKeyIdDict(A => 2, B => 3, C => 4)

wkd = WeakKeyIdDict(A=>2)
wkd = WeakKeyIdDict(A => 2)
@test get(wkd, A, 17) == 2
@test get!(wkd, A, 17) == 2
@test get(wkd, B, 17) == 17
@test length(wkd) == 1
@test get!(wkd, B, 17) == 17
@test length(wkd) == 2

wkd = WeakKeyIdDict(A=>2)
wkd = WeakKeyIdDict(A => 2)
@test get(() -> 23, wkd, A) == 2
@test get!(() -> 23, wkd, A) == 2
@test get(() -> 23, wkd, B) == 23
Expand All @@ -110,38 +112,37 @@ include("set_up_tests.jl")
@test_throws ArgumentError WeakKeyIdDict([1, 2, 3])

# integers can't be arguments
@test_throws ErrorException WeakKeyIdDict([1=>2])
@test_throws ErrorException WeakKeyIdDict([1 => 2])

# WeakKeyIdDict does not convert keys
@test_throws ArgumentError WeakKeyIdDict{Int,Any}(5.0=>1)
@test_throws ArgumentError WeakKeyIdDict{Int,Any}(5.0 => 1)

# iterator
wkd = WeakKeyIdDict(A=>2, B=>3, C=>4)
@test Set(collect(wkd)) == Set([A=>2, B=>3, C=>4])
@test 2+3+4 == sum(v for (k,v) in wkd)
wkd = WeakKeyIdDict(A => 2, B => 3, C => 4)
@test Set(collect(wkd)) == Set([A => 2, B => 3, C => 4])
@test 2 + 3 + 4 == sum(v for (k, v) in wkd)

# WeakKeyIdDict hashes with object-id
AA = copy(A)
GC.@preserve A AA begin
wkd = WeakKeyIdDict(A=>1, AA=>2)
@test length(wkd)==2
wkd = WeakKeyIdDict(A => 1, AA => 2)
@test length(wkd) == 2
kk = collect(keys(wkd))
@test kk[1]==kk[2]
@test kk[1]!==kk[2]
@test kk[1] == kk[2]
@test kk[1] !== kk[2]
end

# WeakKeyIdDict compares to other dicts:
@test IdDict(A=>1)!=WeakKeyIdDict(A=>1)
@test Dict(A=>1)==WeakKeyIdDict(A=>1)
@test Dict(copy(A)=>1)!=WeakKeyIdDict(A=>1)

@test IdDict(A => 1) != WeakKeyIdDict(A => 1)
@test Dict(A => 1) == WeakKeyIdDict(A => 1)
@test Dict(copy(A) => 1) != WeakKeyIdDict(A => 1)
end

@testset "WeakKeyIdDict.lock" begin
A = [1]
B = [2]
C = [3]
wkd = WeakKeyIdDict(A=>2, B=>3, C=>4)
wkd = WeakKeyIdDict(A => 2, B => 3, C => 4)
@test !islocked(wkd)
lock(wkd)
@test islocked(wkd)
Expand All @@ -156,7 +157,7 @@ include("set_up_tests.jl")
d26939[big"1.0" + 1.1] = 1
GC.gc() # make sure this doesn't segfault

wkd = WeakKeyIdDict([42]=>2, [43]=>3, [44]=>4)
wkd = WeakKeyIdDict([42] => 2, [43] => 3, [44] => 4)
for k in keys(wkd)
delete!(wkd, k)
end
Expand All @@ -173,7 +174,7 @@ end
# this point... :-(
_tmp_key = [1]
wkd = WeakKeyIdDict(_tmp_key => 1)
let tmp = [ 42 ]
let tmp = [42]
@test length(wkd) == 1
wkd[tmp] = 2
@test length(wkd) == 2
Expand Down

0 comments on commit b2dd98a

Please sign in to comment.