From 0e012208626e052688c6c9e4f76c05cc5c03ba2a Mon Sep 17 00:00:00 2001 From: "David J. C. Beach" Date: Tue, 23 Aug 2016 19:54:30 -0600 Subject: [PATCH] Added implementation of get(coll, key) -> Nullable. This returns a Nullable value corresponding to the key (or null). Includes specialization for various dictionary types. (Fix bug in priority queue test.) Fixes #13055 --- base/collections.jl | 5 +++++ base/dict.jl | 16 ++++++++++++++++ base/docs/helpdb/Base.jl | 8 ++++++++ base/weakkeydict.jl | 1 + doc/stdlib/collections.rst | 6 ++++++ test/dict.jl | 8 ++++++++ test/priorityqueue.jl | 18 ++++++++++++++++++ 7 files changed, 62 insertions(+) diff --git a/base/collections.jl b/base/collections.jl index caeebf673fa86..71112fb84acd1 100644 --- a/base/collections.jl +++ b/base/collections.jl @@ -323,6 +323,11 @@ function get{K,V}(pq::PriorityQueue{K,V}, key, deflt) i == 0 ? deflt : pq.xs[i].second end +function get{K,V}(pq::PriorityQueue{K,V}, key) + i = get(pq.index, key, 0) + i == 0 ? Nullable{V}() : Nullable{V}(pq.xs[i].second) +end + # Change the priority of an existing element, or equeue it if it isn't present. function setindex!{K,V}(pq::PriorityQueue{K, V}, value, key) diff --git a/base/dict.jl b/base/dict.jl index d66b93377c7f8..4d56741d6d008 100644 --- a/base/dict.jl +++ b/base/dict.jl @@ -6,6 +6,8 @@ const secret_table_token = :__c782dbf1cf4d6a2e5e3865d7e95634f2e09b5902__ haskey(d::Associative, k) = in(k,keys(d)) +get{K,V}(d::Associative{K,V}, k) = haskey(d, k) ? Nullable{V}(d[k]::V) : Nullable{V}() + function in(p::Pair, a::Associative, valcmp=(==)) v = get(a,p[1],secret_table_token) if !is(v, secret_table_token) @@ -698,6 +700,11 @@ function get{K,V}(default::Callable, h::Dict{K,V}, key) return (index < 0) ? default() : h.vals[index]::V end +function get{K,V}(h::Dict{K,V}, key) + index = ht_keyindex(h, key) + return (index<0) ? Nullable{V}() : Nullable{V}(h.vals[index]::V) +end + haskey(h::Dict, key) = (ht_keyindex(h, key) >= 0) in{T<:Dict}(key, v::KeyIterator{T}) = (ht_keyindex(v.dict, key) >= 0) @@ -828,6 +835,7 @@ function getindex(dict::ImmutableDict, key) end throw(KeyError(key)) end + function get(dict::ImmutableDict, key, default) while isdefined(dict, :parent) dict.key == key && return dict.value @@ -836,6 +844,14 @@ function get(dict::ImmutableDict, key, default) return default end +function get{K,V}(dict::ImmutableDict{K,V}, key) + while isdefined(dict, :parent) + dict.key == key && return Nullable{V}(dict.value::V) + dict = dict.parent + end + Nullable{V}() +end + # this actually defines reverse iteration (e.g. it should not be used for merge/copy/filter type operations) start(t::ImmutableDict) = t next{K,V}(::ImmutableDict{K,V}, t) = (Pair{K,V}(t.key, t.value), t.parent) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index b1e51b084e6d2..2d2a77c1ade42 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -4014,6 +4014,14 @@ end """ get +""" + get(collection, key) -> Nullable + +Return the value stored for the given key as `Nullable(value)`, +or if no mapping for the key is present, return null. +""" +get(collection, key) + """ .!=(x, y) .≠(x,y) diff --git a/base/weakkeydict.jl b/base/weakkeydict.jl index 6485c83af38e4..facdba24f40c3 100644 --- a/base/weakkeydict.jl +++ b/base/weakkeydict.jl @@ -40,6 +40,7 @@ end get{K}(wkh::WeakKeyDict{K}, key, default) = lock(() -> get(wkh.ht, key, default), wkh) get{K}(default::Callable, wkh::WeakKeyDict{K}, key) = lock(() -> get(default, wkh.ht, key), wkh) +get{K}(wkh::WeakKeyDict{K}, key) = lock(() -> get(wkh.ht, key), wkh) get!{K}(wkh::WeakKeyDict{K}, key, default) = lock(() -> get!(wkh.ht, key, default), wkh) get!{K}(default::Callable, wkh::WeakKeyDict{K}, key) = lock(() -> get!(default, wkh.ht, key), wkh) pop!{K}(wkh::WeakKeyDict{K}, key) = lock(() -> pop!(wkh.ht, key), wkh) diff --git a/doc/stdlib/collections.rst b/doc/stdlib/collections.rst index 3c2eac2380a99..44f7073ef124a 100644 --- a/doc/stdlib/collections.rst +++ b/doc/stdlib/collections.rst @@ -987,6 +987,12 @@ Given a dictionary ``D``, the syntax ``D[x]`` returns the value of key ``x`` (if Determine whether a collection has a mapping for a given key. +.. function:: get(collection, key) -> Nullable + + .. Docstring generated from Julia source + + Return the value stored for the given key as ``Nullable(value)``\ , or if no mapping for the key is present, return null. + .. function:: get(collection, key, default) .. Docstring generated from Julia source diff --git a/test/dict.jl b/test/dict.jl index 45dcbbe998c8d..44d4339619ba7 100644 --- a/test/dict.jl +++ b/test/dict.jl @@ -256,6 +256,10 @@ let f(x) = x^2, d = Dict(8=>19) f(4) end == 16 + # get (returning Nullable) + @test get(get(d, 8)) == 19 + @test isnull(get(d, 13)) + @test d == Dict(8=>19, 19=>2, 42=>4) end @@ -448,6 +452,10 @@ let d = ImmutableDict{String, String}(), @test in(k2 => 1.0, dnum, is) @test !in(k2 => 1, dnum, <) @test in(k2 => 0, dnum, <) + @test get(d1, "key1") === Nullable{String}(v1) + @test get(d4, "key1") === Nullable{String}(v2) + @test get(d4, "foo") === Nullable{String}() + @test get(d, k1) === Nullable{String}() @test get(d1, "key1", :default) === v1 @test get(d4, "key1", :default) === v2 @test get(d4, "foo", :default) === :default diff --git a/test/priorityqueue.jl b/test/priorityqueue.jl index 326f1c686e287..40181459a51bd 100644 --- a/test/priorityqueue.jl +++ b/test/priorityqueue.jl @@ -107,3 +107,21 @@ for priority in values(priorities) heappush!(xs, priority) end @test issorted([heappop!(xs) for _ in length(priorities)]) + + +# test length, in, haskey, get +let + pq = PriorityQueue(Dict( + i => i+5 for i in 1:5 + )) + @test length(pq) == 5 + + for i in 1:5 + @test haskey(pq, i) + @test (i=>i+5) in pq + @test get(pq, i, 0) == i + 5 + @test get(get(pq, i)) == i+5 + end + @test get(pq, 10, 0) == 0 + @test isnull(get(pq, 10)) +end