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: add 2-argument get returning Union{Nothing,Some} #34821

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
10 changes: 10 additions & 0 deletions base/abstractdict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,16 @@ function hash(a::AbstractDict, h::UInt)
hash(hv, h)
end

function get(default::Callable, d::AbstractDict, key)
val = get(d, key)
val === nothing ? default() : something(val)
end

function get(d::AbstractDict, key, default)
val = get(d, key)
val === nothing ? default : something(val)
end

function getindex(t::AbstractDict, key)
v = get(t, key, secret_table_token)
if v === secret_table_token
Expand Down
1 change: 1 addition & 0 deletions base/compiler/compiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ include("array.jl")
include("abstractarray.jl")

# core structures
include("some.jl")
include("bitarray.jl")
include("bitset.jl")
include("abstractdict.jl")
Expand Down
20 changes: 10 additions & 10 deletions base/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -488,9 +488,9 @@ julia> get(d, "c", 3)
"""
get(collection, key, default)

function get(h::Dict{K,V}, key, default) where V where K
function get(h::Dict{K,V}, key) where V where K
index = ht_keyindex(h, key)
@inbounds return (index < 0) ? default : h.vals[index]::V
@inbounds return (index < 0) ? nothing : Some{V}(h.vals[index]::V)
end

"""
Expand All @@ -510,11 +510,6 @@ end
"""
get(::Function, collection, key)

function get(default::Callable, h::Dict{K,V}, key) where V where K
index = ht_keyindex(h, key)
@inbounds return (index < 0) ? default() : h.vals[index]::V
end

"""
haskey(collection, key) -> Bool

Expand Down Expand Up @@ -561,6 +556,11 @@ function getkey(h::Dict{K,V}, key, default) where V where K
@inbounds return (index<0) ? default : h.keys[index]::K
end

function getkey(h::Dict{K,V}, key) where V where K
index = ht_keyindex(h, key)
@inbounds return (index<0) ? nothing : Some{K}(h.keys[index]::K)
end

function _pop!(h::Dict, index)
@inbounds val = h.vals[index]
_delete!(h, index)
Expand Down Expand Up @@ -769,12 +769,12 @@ function getindex(dict::ImmutableDict, key)
end
throw(KeyError(key))
end
function get(dict::ImmutableDict, key, default)
function get(dict::ImmutableDict{K,V}, key) where {K,V}
while isdefined(dict, :parent)
dict.key == key && return dict.value
dict.key == key && return Some{V}(dict.value)
dict = dict.parent
end
return default
return nothing
end

# this actually defines reverse iteration (e.g. it should not be used for merge/copy/filter type operations)
Expand Down
1 change: 1 addition & 0 deletions base/env.jl
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const ENV = EnvDict()

getindex(::EnvDict, k::AbstractString) = access_env(k->throw(KeyError(k)), k)
get(::EnvDict, k::AbstractString, def) = access_env(k->def, k)
get(::EnvDict, k::AbstractString) = (v = get(ENV, k, nothing); v === nothing ? v : Some(v))
get(f::Callable, ::EnvDict, k::AbstractString) = access_env(k->f(), k)
in(k::AbstractString, ::KeySet{String, EnvDict}) = _hasenv(k)
pop!(::EnvDict, k::AbstractString) = (v = ENV[k]; _unsetenv(k); v)
Expand Down
55 changes: 29 additions & 26 deletions base/iddict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,36 +81,46 @@ function setindex!(d::IdDict{K,V}, @nospecialize(val), @nospecialize(key)) where
return d
end

function get(d::IdDict{K,V}, @nospecialize(key), @nospecialize(default)) where {K, V}
val = ccall(:jl_eqtable_get, Any, (Any, Any, Any), d.ht, key, default)
val === default ? default : val::V
function get(d::IdDict{K,V}, @nospecialize(key)) where {K, V}
found = RefValue{Cint}(0)
val = ccall(:jl_eqtable_get1, Any, (Any, Any, Ptr{Cint}), d.ht, key, found)
if found[] == 1
return Some{V}(val::V)
end
return nothing
end
function getindex(d::IdDict{K,V}, @nospecialize(key)) where {K, V}
val = get(d, key, secret_table_token)
val === secret_table_token && throw(KeyError(key))
return val::V
val = get(d, key)
val === nothing && throw(KeyError(key))
return something(val::Some{V})
end

function pop!(d::IdDict{K,V}, @nospecialize(key), @nospecialize(default)) where {K, V}
function _iddict_pop!(d::IdDict{K,V}, @nospecialize(key)) where {K, V}
found = RefValue{Cint}(0)
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any, Ptr{Cint}), d.ht, key, default, found)
val = ccall(:jl_eqtable_pop, Any, (Any, Any, Any, Ptr{Cint}), d.ht, key, nothing, found)
if found[] === Cint(0)
return default
return nothing
else
d.count -= 1
d.ndel += 1
return val::V
return Some{V}(val::V)
end
end

function pop!(d::IdDict{K,V}, @nospecialize(key), @nospecialize(default)) where {K, V}
val = _iddict_pop!(d, key)
val === nothing && return default
return something(val::Some{V})
end

function pop!(d::IdDict{K,V}, @nospecialize(key)) where {K, V}
val = pop!(d, key, secret_table_token)
val === secret_table_token && throw(KeyError(key))
return val::V
val = _iddict_pop!(d, key)
val === nothing && throw(KeyError(key))
return something(val::Some{V})
end

function delete!(d::IdDict{K}, @nospecialize(key)) where K
pop!(d, key, secret_table_token)
_iddict_pop!(d, key)
d
end

Expand All @@ -136,24 +146,17 @@ copy(d::IdDict) = typeof(d)(d)

get!(d::IdDict{K,V}, @nospecialize(key), @nospecialize(default)) where {K, V} = (d[key] = get(d, key, default))::V

function get(default::Callable, d::IdDict{K,V}, @nospecialize(key)) where {K, V}
val = get(d, key, secret_table_token)
if val === secret_table_token
val = default()
end
return val
end

function get!(default::Callable, d::IdDict{K,V}, @nospecialize(key)) where {K, V}
val = get(d, key, secret_table_token)
if val === secret_table_token
val = get(d, key)
if val === nothing
val = default()
setindex!(d, val, key)
return val
end
return val
return something(val::Some{V})
end

in(@nospecialize(k), v::KeySet{<:Any,<:IdDict}) = get(v.dict, k, secret_table_token) !== secret_table_token
in(@nospecialize(k), v::KeySet{<:Any,<:IdDict}) = get(v.dict, k) !== nothing

# For some AbstractDict types, it is safe to implement filter!
# by deleting keys during iteration.
Expand Down
3 changes: 1 addition & 2 deletions base/iterators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,7 @@ keys(v::Pairs) = v.itr
values(v::Pairs) = v.data
getindex(v::Pairs, key) = v.data[key]
setindex!(v::Pairs, value, key) = (v.data[key] = value; v)
get(v::Pairs, key, default) = get(v.data, key, default)
get(f::Base.Callable, v::Pairs, key) = get(f, v.data, key)
get(v::Pairs, key) = get(v.data, key)

# zip

Expand Down
16 changes: 12 additions & 4 deletions base/weakkeydict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,22 @@ end

function getkey(wkh::WeakKeyDict{K}, kk, default) where K
return lock(wkh) do
k = getkey(wkh.ht, kk, secret_table_token)
k === secret_table_token && return default
return k.value::K
k = getkey(wkh.ht, kk)
k === nothing && return default
return something(k).value::K
end
end

function getkey(wkh::WeakKeyDict{K}, kk) where K
return lock(wkh) do
k = getkey(wkh.ht, kk)
k === nothing && return nothing
return Some(something(k).value::K)
end
end

map!(f,iter::ValueIterator{<:WeakKeyDict})= map!(f, values(iter.dict.ht))
get(wkh::WeakKeyDict{K}, key, default) where {K} = lock(() -> get(wkh.ht, key, default), wkh)
get(wkh::WeakKeyDict{K}, key) where {K} = lock(() -> get(wkh.ht, key), wkh)
get(default::Callable, wkh::WeakKeyDict{K}, key) where {K} = lock(() -> get(default, wkh.ht, key), wkh)
function get!(wkh::WeakKeyDict{K}, key, default) where {K}
!isa(key, K) && throw(ArgumentError("$(limitrepr(key)) is not a valid key for type $K"))
Expand Down
11 changes: 11 additions & 0 deletions src/iddict.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ jl_value_t *jl_eqtable_get(jl_array_t *h, jl_value_t *key, jl_value_t *deflt)
return (bp == NULL) ? deflt : (jl_value_t *)*bp;
}

JL_DLLEXPORT
jl_value_t *jl_eqtable_get1(jl_array_t *h, jl_value_t *key, int *found)
{
void **bp = jl_table_peek_bp(h, key);
if (found)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (found)

*found = (bp != NULL);
if (bp == NULL)
return jl_nothing;
return (jl_value_t *)*bp;
}

JL_DLLEXPORT
jl_value_t *jl_eqtable_pop(jl_array_t *h, jl_value_t *key, jl_value_t *deflt, int *found)
{
Expand Down