Skip to content

Commit

Permalink
Add a count field to IdDict
Browse files Browse the repository at this point in the history
To provide an efficient `length` method.

Fixes JuliaLang#26043
  • Loading branch information
Keno authored and Keno Fischer committed Feb 24, 2018
1 parent 6239b63 commit e9a17a6
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 55 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ CORE_SRCS := $(addprefix $(JULIAHOME)/, \
base/reduce.jl \
base/reflection.jl \
base/traits.jl \
base/refpointer.jl \
base/tuple.jl)
COMPILER_SRCS = $(sort $(shell find $(JULIAHOME)/base/compiler -name \*.jl))
BASE_SRCS := $(sort $(shell find $(JULIAHOME)/base -name \*.jl) $(shell find $(BUILDROOT)/base -name \*.jl))
Expand Down
27 changes: 13 additions & 14 deletions base/abstractdict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -541,8 +541,9 @@ See [`Dict`](@ref) for further help.
"""
mutable struct IdDict{K,V} <: AbstractDict{K,V}
ht::Vector{Any}
count::Int
ndel::Int
IdDict{K,V}() where {K, V} = new{K,V}(Vector{Any}(uninitialized, 32), 0)
IdDict{K,V}() where {K, V} = new{K,V}(Vector{Any}(uninitialized, 32), 0, 0)

function IdDict{K,V}(itr) where {K, V}
d = IdDict{K,V}()
Expand All @@ -557,7 +558,7 @@ mutable struct IdDict{K,V} <: AbstractDict{K,V}
d
end

IdDict{K,V}(d::IdDict{K,V}) where {K, V} = new{K,V}(copy(d.ht))
IdDict{K,V}(d::IdDict{K,V}) where {K, V} = new{K,V}(copy(d.ht), d.count, d.ndel)
end

IdDict() = IdDict{Any,Any}()
Expand Down Expand Up @@ -605,7 +606,9 @@ function setindex!(d::IdDict{K,V}, @nospecialize(val), @nospecialize(key)) where
rehash!(d, max(length(d.ht)>>1, 32))
d.ndel = 0
end
d.ht = ccall(:jl_eqtable_put, Array{Any,1}, (Any, Any, Any), d.ht, key, val)
inserted = RefValue{Cint}(0)
d.ht = ccall(:jl_eqtable_put, Array{Any,1}, (Any, Any, Any, Ptr{Cint}), d.ht, key, val, inserted)
d.count += inserted[]
return d
end

Expand All @@ -620,12 +623,13 @@ function getindex(d::IdDict{K,V}, @nospecialize(key)) where {K, V}
end

function pop!(d::IdDict{K,V}, @nospecialize(key), @nospecialize(default)) where {K, V}
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any), d.ht, key, default)
# TODO: this can underestimate `ndel`
if val === default
found = RefValue{Cint}(0)
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any, Ptr{Cint}), d.ht, key, default, found)
if found[] === Cint(0)
return default
else
(d.ndel += 1)
d.count -= 1
d.ndel += 1
return val::V
end
end
Expand All @@ -645,6 +649,7 @@ function empty!(d::IdDict)
resize!(d.ht, 32)
ccall(:memset, Ptr{Cvoid}, (Ptr{Cvoid}, Cint, Csize_t), d.ht, 0, sizeof(d.ht))
d.ndel = 0
d.count = 0
return d
end

Expand All @@ -654,13 +659,7 @@ start(d::IdDict) = _oidd_nextind(d.ht, 0)
done(d::IdDict, i) = (i == -1)
next(d::IdDict{K,V}, i) where {K, V} = (Pair{K,V}(d.ht[i+1], d.ht[i+2]), _oidd_nextind(d.ht, i+2))

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

copy(d::IdDict) = IdDict(d)

Expand Down
3 changes: 3 additions & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ include("number.jl")
include("int.jl")
include("operators.jl")
include("pointer.jl")
include("refpointer.jl")

# checked arithmetic
const checked_add = +
const checked_sub = -

Expand Down
67 changes: 35 additions & 32 deletions base/refpointer.jl
Original file line number Diff line number Diff line change
Expand Up @@ -98,38 +98,6 @@ function unsafe_convert(P::Type{Ptr{Any}}, b::RefArray{Any})
end
unsafe_convert(::Type{Ptr{Cvoid}}, b::RefArray{T}) where {T} = convert(Ptr{Cvoid}, unsafe_convert(Ptr{T}, b))

###
if is_primary_base_module
Ref(x::Any) = RefValue(x)
Ref{T}() where {T} = RefValue{T}() # Ref{T}()
Ref{T}(x) where {T} = RefValue{T}(x) # Ref{T}(x)

Ref(x::Ref, i::Integer) = (i != 1 && error("Ref only has one element"); x)
Ref(x::Ptr{T}, i::Integer) where {T} = x + (i - 1) * Core.sizeof(T)

# convert Arrays to pointer arrays for ccall
function Ref{P}(a::Array{<:Union{Ptr,Cwstring,Cstring}}) where P<:Union{Ptr,Cwstring,Cstring}
return RefArray(a) # effectively a no-op
end
function Ref{P}(a::Array{T}) where P<:Union{Ptr,Cwstring,Cstring} where T
if (!isbits(T) && T <: eltype(P))
# this Array already has the right memory layout for the requested Ref
return RefArray(a,1,false) # root something, so that this function is type-stable
else
ptrs = Vector{P}(uninitialized, length(a)+1)
roots = Vector{Any}(uninitialized, length(a))
for i = 1:length(a)
root = cconvert(P, a[i])
ptrs[i] = unsafe_convert(P, root)::P
roots[i] = root
end
ptrs[length(a)+1] = C_NULL
return RefArray(ptrs,1,roots)
end
end
Ref(x::AbstractArray, i::Integer) = RefArray(x, i)
end

cconvert(::Type{Ptr{P}}, a::Array{<:Ptr}) where {P<:Ptr} = a
cconvert(::Type{Ref{P}}, a::Array{<:Ptr}) where {P<:Ptr} = a
cconvert(::Type{Ptr{P}}, a::Array) where {P<:Union{Ptr,Cwstring,Cstring}} = Ref{P}(a)
Expand All @@ -144,3 +112,38 @@ setindex!(b::RefValue, x) = (b.x = x; b)
setindex!(b::RefArray, x) = (b.x[b.i] = x; b)

###

# Base-only constructors on the shared abstract Ref type
if nameof(@__MODULE__) === :Base && is_primary_base_module

Ref(x::Any) = RefValue(x)
Ref{T}() where {T} = RefValue{T}() # Ref{T}()
Ref{T}(x) where {T} = RefValue{T}(x) # Ref{T}(x)
convert(::Type{Ref{T}}, x) where {T} = RefValue{T}(x)

Ref(x::Ref, i::Integer) = (i != 1 && error("Ref only has one element"); x)
Ref(x::Ptr{T}, i::Integer) where {T} = x + (i - 1) * Core.sizeof(T)

Ref(x::AbstractArray, i::Integer) = RefArray(x, i)

# convert Arrays to pointer arrays for ccall
function Ref{P}(a::Array{<:Union{Ptr,Cwstring,Cstring}}) where P<:Union{Ptr,Cwstring,Cstring}
return RefArray(a) # effectively a no-op
end
function Ref{P}(a::Array{T}) where P<:Union{Ptr,Cwstring,Cstring} where T
if (!isbits(T) && T <: eltype(P))
# this Array already has the right memory layout for the requested Ref
return RefArray(a,1,false) # root something, so that this function is type-stable
else
ptrs = Vector{P}(uninitialized, length(a)+1)
roots = Vector{Any}(uninitialized, length(a))
for i = 1:length(a)
root = cconvert(P, a[i])
ptrs[i] = unsafe_convert(P, root)::P
roots[i] = root
end
end
Ref(x::AbstractArray, i::Integer) = RefArray(x, i)
end

end
2 changes: 1 addition & 1 deletion src/gf.c
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ static void foreach_mtable_in_module(
{
size_t i;
void **table = m->bindings.table;
jl_eqtable_put(visited, m, jl_true);
jl_eqtable_put(visited, m, jl_true, NULL);
for (i = 1; i < m->bindings.size; i += 2) {
if (table[i] != HT_NOTFOUND) {
jl_binding_t *b = (jl_binding_t*)table[i];
Expand Down
2 changes: 1 addition & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1342,7 +1342,7 @@ STATIC_INLINE jl_function_t *jl_get_function(jl_module_t *m, const char *name)
int jl_is_submodule(jl_module_t *child, jl_module_t *parent);

// eq hash tables
JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val);
JL_DLLEXPORT jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val, int *inserted);
JL_DLLEXPORT jl_value_t *jl_eqtable_get(jl_array_t *h, void *key,
jl_value_t *deflt);

Expand Down
24 changes: 17 additions & 7 deletions src/table.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#define keyhash(k) jl_object_id(k)
#define h2index(hv,sz) (size_t)(((hv) & ((sz)-1))*2)

static void **jl_table_lookup_bp(jl_array_t **pa, void *key);
static void **jl_table_lookup_bp(jl_array_t **pa, void *key, int *inserted);

JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz)
{
Expand All @@ -23,7 +23,7 @@ JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz)
JL_GC_PUSH1(&newa);
for(i=0; i < sz; i+=2) {
if (ol[i+1] != NULL) {
(*jl_table_lookup_bp(&newa, ol[i])) = ol[i+1];
(*jl_table_lookup_bp(&newa, ol[i], NULL)) = ol[i+1];
jl_gc_wb(newa, ol[i+1]);
// it is however necessary here because allocation
// can (and will) occur in a recursive call inside table_lookup_bp
Expand All @@ -37,7 +37,7 @@ JL_DLLEXPORT jl_array_t *jl_idtable_rehash(jl_array_t *a, size_t newsz)
return newa;
}

static void **jl_table_lookup_bp(jl_array_t **pa, void *key)
static void **jl_table_lookup_bp(jl_array_t **pa, void *key, int *inserted)
{
// pa points to a **rooted** gc frame slot
uint_t hv;
Expand All @@ -48,6 +48,9 @@ static void **jl_table_lookup_bp(jl_array_t **pa, void *key)
size_t maxprobe = max_probe(sz);
void **tab = (void**)a->data;

if (inserted)
*inserted = 0;

hv = keyhash((jl_value_t*)key);
retry_bp:
iter = 0;
Expand All @@ -58,6 +61,8 @@ static void **jl_table_lookup_bp(jl_array_t **pa, void *key)
do {
if (tab[index+1] == NULL) {
tab[index] = key;
if (inserted)
*inserted = 1;
jl_gc_wb(a, key);
return &tab[index+1];
}
Expand Down Expand Up @@ -124,11 +129,11 @@ static void **jl_table_peek_bp(jl_array_t *a, void *key)
}

JL_DLLEXPORT
jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val)
jl_array_t *jl_eqtable_put(jl_array_t *h, void *key, void *val, int *inserted)
{
JL_GC_PUSH1(&h);
// &h may be assigned to in jl_idtable_rehash so it need to be rooted
void **bp = jl_table_lookup_bp(&h, key);
void **bp = jl_table_lookup_bp(&h, key, inserted);
*bp = val;
jl_gc_wb(h, val);
JL_GC_POP();
Expand All @@ -145,11 +150,16 @@ jl_value_t *jl_eqtable_get(jl_array_t *h, void *key, jl_value_t *deflt)
}

JL_DLLEXPORT
jl_value_t *jl_eqtable_pop(jl_array_t *h, void *key, jl_value_t *deflt)
jl_value_t *jl_eqtable_pop(jl_array_t *h, void *key, jl_value_t *deflt, int *found)
{
void **bp = jl_table_peek_bp(h, key);
if (bp == NULL || *bp == NULL)
if (bp == NULL || *bp == NULL) {
if (found)
*found = 0;
return deflt;
}
if (found)
*found = 1;
jl_value_t *val = (jl_value_t*)*bp;
*(bp-1) = jl_nothing; // clear the key
*bp = NULL;
Expand Down

0 comments on commit e9a17a6

Please sign in to comment.