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

WIP/RFC: Adding EgalDict{K,V} (aka ObjectIdDict{K,V}) #24932

Closed
wants to merge 7 commits into from
Closed
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
56 changes: 29 additions & 27 deletions base/abstractdict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ eltype(::Type{AbstractDict{K,V}}) where {K,V} = Pair{K,V}

function isequal(l::AbstractDict, r::AbstractDict)
l === r && return true
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict) || isa(l,IdDict) != isa(r,IdDict)
return false
end
if length(l) != length(r) return false end
Expand All @@ -473,7 +473,7 @@ end

function ==(l::AbstractDict, r::AbstractDict)
l === r && return true
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict)
if isa(l,ObjectIdDict) != isa(r,ObjectIdDict) || isa(l,IdDict) != isa(r,IdDict)
return false
end
if length(l) != length(r) return false end
Expand Down Expand Up @@ -514,42 +514,44 @@ push!(t::AbstractDict, p::Pair, q::Pair, r::Pair...) = push!(push!(push!(t, p),
# hashing objects by identity

"""
ObjectIdDict([itr])
IdDict([itr])

`ObjectIdDict()` constructs a hash table where the keys are (always)
Internally used object-id dictionary, use [`ObjectIdDict`](@ref) instead.

`IdDict()` 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 <: AbstractDict{Any,Any}
mutable struct IdDict <: AbstractDict{Any,Any}
ht::Vector{Any}
ndel::Int
ObjectIdDict() = new(Vector{Any}(uninitialized, 32), 0)
IdDict() = new(Vector{Any}(uninitialized, 32), 0)

function ObjectIdDict(itr)
d = ObjectIdDict()
function IdDict(itr)
d = IdDict()
for (k,v) in itr; d[k] = v; end
d
end

function ObjectIdDict(pairs::Pair...)
d = ObjectIdDict()
function IdDict(pairs::Pair...)
d = IdDict()
for (k,v) in pairs; d[k] = v; end
d
end

ObjectIdDict(o::ObjectIdDict) = new(copy(o.ht))
IdDict(o::IdDict) = new(copy(o.ht))
end

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

function rehash!(t::ObjectIdDict, newsz = length(t.ht))
function rehash!(t::IdDict, newsz = length(t.ht))
t.ht = ccall(:jl_idtable_rehash, Any, (Any, Csize_t), t.ht, newsz)
t
end

function sizehint!(t::ObjectIdDict, newsz)
function sizehint!(t::IdDict, newsz)
newsz = _tablesz(newsz*2) # *2 for keys and values in same array
oldsz = length(t.ht)
# grow at least 25%
Expand All @@ -559,7 +561,7 @@ function sizehint!(t::ObjectIdDict, newsz)
rehash!(t, newsz)
end

function setindex!(t::ObjectIdDict, @nospecialize(v), @nospecialize(k))
function setindex!(t::IdDict, @nospecialize(v), @nospecialize(k))
if t.ndel >= ((3*length(t.ht))>>2)
rehash!(t, max(length(t.ht)>>1, 32))
t.ndel = 0
Expand All @@ -568,27 +570,27 @@ function setindex!(t::ObjectIdDict, @nospecialize(v), @nospecialize(k))
return t
end

get(t::ObjectIdDict, @nospecialize(key), @nospecialize(default)) =
get(t::IdDict, @nospecialize(key), @nospecialize(default)) =
ccall(:jl_eqtable_get, Any, (Any, Any, Any), t.ht, key, default)

function pop!(t::ObjectIdDict, @nospecialize(key), @nospecialize(default))
function pop!(t::IdDict, @nospecialize(key), @nospecialize(default))
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, @nospecialize(key))
function pop!(t::IdDict, @nospecialize(key))
val = pop!(t, key, secret_table_token)
val !== secret_table_token ? val : throw(KeyError(key))
end

function delete!(t::ObjectIdDict, @nospecialize(key))
function delete!(t::IdDict, @nospecialize(key))
pop!(t, key, secret_table_token)
t
end

function empty!(t::ObjectIdDict)
function empty!(t::IdDict)
resize!(t.ht, 32)
ccall(:memset, Ptr{Void}, (Ptr{Void}, Cint, Csize_t), t.ht, 0, sizeof(t.ht))
t.ndel = 0
Expand All @@ -597,22 +599,22 @@ 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))
start(t::IdDict) = _oidd_nextind(t.ht, 0)
done(t::IdDict, i) = (i == -1)
next(t::IdDict, i) = (Pair{Any,Any}(t.ht[i+1],t.ht[i+2]), _oidd_nextind(t.ht, i+2))

function length(d::ObjectIdDict)
function length(d::IdDict)
n = 0
for pair in d
n+=1
end
n
end

copy(o::ObjectIdDict) = ObjectIdDict(o)
copy(o::IdDict) = IdDict(o)

get!(o::ObjectIdDict, key, default) = (o[key] = get(o, key, default))
get!(o::IdDict, key, default) = (o[key] = get(o, key, default))

# For some AbstractDict types, it is safe to implement filter!
# by deleting keys during iteration.
filter!(f, d::ObjectIdDict) = filter_in_one_pass!(f, d)
filter!(f, d::IdDict) = filter_in_one_pass!(f, d)
2 changes: 1 addition & 1 deletion base/codevalidation.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is a part of Julia. License is MIT: https://julialang.org/license

# Expr head => argument count bounds
const VALID_EXPR_HEADS = ObjectIdDict(
const VALID_EXPR_HEADS = IdDict(
:call => 1:typemax(Int),
:invoke => 2:typemax(Int),
:static_parameter => 1:1,
Expand Down
Loading