diff --git a/Project.toml b/Project.toml index efb4354cc..6db8c3913 100644 --- a/Project.toml +++ b/Project.toml @@ -4,6 +4,7 @@ version = "0.12.0" [deps] InteractiveUtils = "b77e0a4c-d291-57a0-90e8-8db25a27a240" +OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" @@ -13,3 +14,6 @@ Serialization = "9e88b42a-f829-5b0c-bbe9-9e923198166b" [targets] test = ["Test", "Primes", "Random", "Serialization"] + +[compat] +OrderedCollections = "1.0.1" diff --git a/REQUIRE b/REQUIRE index 859ad4616..2d93685dd 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1 +1,2 @@ julia 0.7 +OrderedCollections 1.0.1 diff --git a/src/DataStructures.jl b/src/DataStructures.jl index bfdf2d388..ea49a4f95 100644 --- a/src/DataStructures.jl +++ b/src/DataStructures.jl @@ -16,7 +16,8 @@ module DataStructures eachindex, keytype, valtype import Base: iterate - using InteractiveUtils: methodswith + using OrderedCollections + import OrderedCollections: filter, filter!, isordered export complement, complement! @@ -67,10 +68,8 @@ module DataStructures include("disjoint_set.jl") include("heaps.jl") - include("dict_support.jl") - include("ordered_dict.jl") - include("ordered_set.jl") include("default_dict.jl") + include("dict_support.jl") include("trie.jl") include("int_set.jl") @@ -88,8 +87,6 @@ module DataStructures include("tokens2.jl") include("container_loops.jl") - include("dict_sorting.jl") - export CircularBuffer, capacity, diff --git a/src/dict_sorting.jl b/src/dict_sorting.jl deleted file mode 100644 index b08dd9e75..000000000 --- a/src/dict_sorting.jl +++ /dev/null @@ -1,25 +0,0 @@ -# Sort for dicts -import Base: sort, sort! - -function sort!(d::OrderedDict; byvalue::Bool=false, args...) - if d.ndel > 0 - rehash!(d) - end - - if byvalue - p = sortperm(d.vals; args...) - else - p = sortperm(d.keys; args...) - end - d.keys = d.keys[p] - d.vals = d.vals[p] - rehash!(d) - return d -end - -sort(d::OrderedDict; args...) = sort!(copy(d); args...) -sort(d::Dict; args...) = sort!(OrderedDict(d); args...) -## Uncomment these after #224 is merged -# sort!(d::DefaultOrderedDict; args...) = (sort!(d.d.d; args...); d) -# sort(d::DefaultDict; args...) = DefaultOrderedDict(d.d.default, sort(d.d.d; args...)) -# sort(d::DefaultOrderedDict; args...) = DefaultOrderedDict(d.d.default, sort!(copy(d.d.d); args...)) diff --git a/src/dict_support.jl b/src/dict_support.jl index 29fdf335a..6a95ff1fd 100644 --- a/src/dict_support.jl +++ b/src/dict_support.jl @@ -1,9 +1,6 @@ # support functions -# _tablesz and hashindex are defined in Base, but are not exported, -# so they are redefined here. -_tablesz(x::Integer) = x < 16 ? 16 : one(x)<<((sizeof(x)<<3)-leading_zeros(x-1)) -hashindex(key, sz) = (reinterpret(Int,(hash(key))) & (sz-1)) + 1 +using InteractiveUtils: methodswith function not_iterator_of_pairs(kv) return any(x->isempty(methodswith(typeof(kv), x, true)), diff --git a/src/ordered_dict.jl b/src/ordered_dict.jl deleted file mode 100644 index 74d05c717..000000000 --- a/src/ordered_dict.jl +++ /dev/null @@ -1,437 +0,0 @@ -# OrderedDict - -import Base: haskey, get, get!, getkey, delete!, push!, pop!, empty!, - setindex!, getindex, length, isempty, - keys, values, setdiff, setdiff!, - union, union!, intersect, filter, filter!, - hash, eltype, ValueIterator, convert, copy, - merge, empty - -""" - OrderedDict - -`OrderedDict`s are simply dictionaries whose entries have a particular order. The order -refers to insertion order, which allows deterministic iteration over the dictionary or set. -""" -mutable struct OrderedDict{K,V} <: AbstractDict{K,V} - slots::Array{Int32,1} - keys::Array{K,1} - vals::Array{V,1} - ndel::Int - dirty::Bool - - function OrderedDict{K,V}() where {K,V} - new{K,V}(zeros(Int32,16), Vector{K}(), Vector{V}(), 0, false) - end - function OrderedDict{K,V}(kv) where {K,V} - h = OrderedDict{K,V}() - for (k,v) in kv - h[k] = v - end - return h - end - OrderedDict{K,V}(p::Pair) where {K,V} = setindex!(OrderedDict{K,V}(), p.second, p.first) - function OrderedDict{K,V}(ps::Pair...) where {K,V} - h = OrderedDict{K,V}() - sizehint!(h, length(ps)) - for p in ps - h[p.first] = p.second - end - return h - end - function OrderedDict{K,V}(d::OrderedDict{K,V}) where {K,V} - if d.ndel > 0 - rehash!(d) - end - @assert d.ndel == 0 - new{K,V}(copy(d.slots), copy(d.keys), copy(d.vals), 0) - end -end -OrderedDict() = OrderedDict{Any,Any}() -OrderedDict(kv::Tuple{}) = OrderedDict() -copy(d::OrderedDict) = OrderedDict(d) - - -# TODO: this can probably be simplified using `eltype` as a THT (Tim Holy trait) -# OrderedDict{K,V}(kv::Tuple{Vararg{Tuple{K,V}}}) = OrderedDict{K,V}(kv) -# OrderedDict{K }(kv::Tuple{Vararg{Tuple{K,Any}}}) = OrderedDict{K,Any}(kv) -# OrderedDict{V }(kv::Tuple{Vararg{Tuple{Any,V}}}) = OrderedDict{Any,V}(kv) -OrderedDict(kv::Tuple{Vararg{Pair{K,V}}}) where {K,V} = OrderedDict{K,V}(kv) -OrderedDict(kv::Tuple{Vararg{Pair{K}}}) where {K} = OrderedDict{K,Any}(kv) -OrderedDict(kv::Tuple{Vararg{Pair{K,V} where K}}) where {V} = OrderedDict{Any,V}(kv) -OrderedDict(kv::Tuple{Vararg{Pair}}) = OrderedDict{Any,Any}(kv) - -OrderedDict(kv::AbstractArray{Tuple{K,V}}) where {K,V} = OrderedDict{K,V}(kv) -OrderedDict(kv::AbstractArray{Pair{K,V}}) where {K,V} = OrderedDict{K,V}(kv) -OrderedDict(kv::AbstractDict{K,V}) where {K,V} = OrderedDict{K,V}(kv) - -OrderedDict(ps::Pair{K,V}...) where {K,V} = OrderedDict{K,V}(ps) -OrderedDict(ps::Pair{K}...,) where {K} = OrderedDict{K,Any}(ps) -OrderedDict(ps::(Pair{K,V} where K)...,) where {V} = OrderedDict{Any,V}(ps) -OrderedDict(ps::Pair...) = OrderedDict{Any,Any}(ps) - -function OrderedDict(kv) - try - dict_with_eltype(kv, eltype(kv)) - catch e - if any(x->isempty(methods(x, (typeof(kv),))), [iterate]) || - !all(x->isa(x,Union{Tuple,Pair}),kv) - throw(ArgumentError("Dict(kv): kv needs to be an iterator of tuples or pairs")) - else - rethrow(e) - end - end -end - -dict_with_eltype(kv, ::Type{Tuple{K,V}}) where {K,V} = OrderedDict{K,V}(kv) -dict_with_eltype(kv, ::Type{Pair{K,V}}) where {K,V} = OrderedDict{K,V}(kv) -dict_with_eltype(kv, t) = OrderedDict{Any,Any}(kv) - -empty(d::OrderedDict{K,V}) where {K,V} = OrderedDict{K,V}() -@deprecate similar(d::OrderedDict) empty(d) - -length(d::OrderedDict) = length(d.keys) - d.ndel -isempty(d::OrderedDict) = (length(d)==0) - -""" - isordered(::Type) - -Property of associative containers, that is `true` if the container type has a -defined order (such as `OrderedDict` and `SortedDict`), and `false` otherwise. -""" -isordered(::Type{T}) where {T<:AbstractDict} = false -isordered(::Type{T}) where {T<:OrderedDict} = true - -# conversion between OrderedDict types -function convert(::Type{OrderedDict{K,V}}, d::AbstractDict) where {K,V} - if !isordered(typeof(d)) - Base.depwarn("Conversion to OrderedDict is deprecated for unordered associative containers (in this case, $(typeof(d))). Use an ordered or sorted associative type, such as SortedDict and OrderedDict.", :convert) - end - h = OrderedDict{K,V}() - for (k,v) in d - ck = convert(K,k) - if !haskey(h,ck) - h[ck] = convert(V,v) - else - error("key collision during dictionary conversion") - end - end - return h -end -convert(::Type{OrderedDict{K,V}},d::OrderedDict{K,V}) where {K,V} = d - -function rehash!(h::OrderedDict{K,V}, newsz = length(h.slots)) where {K,V} - olds = h.slots - keys = h.keys - vals = h.vals - sz = length(olds) - newsz = _tablesz(newsz) - h.dirty = true - count0 = length(h) - if count0 == 0 - resize!(h.slots, newsz) - fill!(h.slots, 0) - resize!(h.keys, 0) - resize!(h.vals, 0) - h.ndel = 0 - return h - end - - slots = zeros(Int32,newsz) - - if h.ndel > 0 - ndel0 = h.ndel - ptrs = !isbitstype(K) - to = 1 - # TODO: to get the best performance we need to avoid reallocating these. - # This algorithm actually works in place, unless the dict is modified - # due to GC during this process. - newkeys = similar(keys, count0) - newvals = similar(vals, count0) - @inbounds for from = 1:length(keys) - if !ptrs || isassigned(keys, from) - k = keys[from] - hashk = hash(k)%Int - isdeleted = false - if !ptrs - iter = 0 - maxprobe = max(16, sz>>6) - index = (hashk & (sz-1)) + 1 - while iter <= maxprobe - si = olds[index] - #si == 0 && break # shouldn't happen - si == from && break - si == -from && (isdeleted=true; break) - index = (index & (sz-1)) + 1 - iter += 1 - end - end - if !isdeleted - index = (hashk & (newsz-1)) + 1 - while slots[index] != 0 - index = (index & (newsz-1)) + 1 - end - slots[index] = to - newkeys[to] = k - newvals[to] = vals[from] - to += 1 - end - if h.ndel != ndel0 - # if items are removed by finalizers, retry - return rehash!(h, newsz) - end - end - end - h.keys = newkeys - h.vals = newvals - h.ndel = 0 - else - @inbounds for i = 1:count0 - k = keys[i] - index = hashindex(k, newsz) - while slots[index] != 0 - index = (index & (newsz-1)) + 1 - end - slots[index] = i - if h.ndel > 0 - # if items are removed by finalizers, retry - return rehash!(h, newsz) - end - end - end - - h.slots = slots - return h -end - -function sizehint!(d::OrderedDict, newsz) - slotsz = (newsz*3)>>1 - oldsz = length(d.slots) - if slotsz <= oldsz - # todo: shrink - # be careful: rehash!() assumes everything fits. it was only designed - # for growing. - return d - end - # grow at least 25% - slotsz = max(slotsz, (oldsz*5)>>2) - rehash!(d, slotsz) -end - -function empty!(h::OrderedDict{K,V}) where {K,V} - fill!(h.slots, 0) - empty!(h.keys) - empty!(h.vals) - h.ndel = 0 - h.dirty = true - return h -end - -# get the index where a key is stored, or -1 if not present -function ht_keyindex(h::OrderedDict{K,V}, key, direct) where {K,V} - slots = h.slots - sz = length(slots) - iter = 0 - maxprobe = max(16, sz>>6) - index = hashindex(key, sz) - keys = h.keys - - @inbounds while iter <= maxprobe - si = slots[index] - si == 0 && break - if si > 0 && isequal(key, keys[si]) - return ifelse(direct, oftype(index, si), index) - end - - index = (index & (sz-1)) + 1 - iter+=1 - end - - return -1 -end - -# get the index where a key is stored, or -pos if not present -# and the key would be inserted at pos -# This version is for use by setindex! and get! -function ht_keyindex2(h::OrderedDict{K,V}, key) where {K,V} - slots = h.slots - sz = length(slots) - iter = 0 - maxprobe = max(16, sz>>6) - index = hashindex(key, sz) - keys = h.keys - - @inbounds while iter <= maxprobe - si = slots[index] - if si == 0 - return -index - elseif si > 0 && isequal(key, keys[si]) - return oftype(index, si) - end - - index = (index & (sz-1)) + 1 - iter+=1 - end - - rehash!(h, length(h) > 64000 ? sz*2 : sz*4) - - return ht_keyindex2(h, key) -end - -function _setindex!(h::OrderedDict, v, key, index) - hk, hv = h.keys, h.vals - #push!(h.keys, key) - ccall(:jl_array_grow_end, Cvoid, (Any, UInt), hk, 1) - nk = length(hk) - @inbounds hk[nk] = key - #push!(h.vals, v) - ccall(:jl_array_grow_end, Cvoid, (Any, UInt), hv, 1) - @inbounds hv[nk] = v - @inbounds h.slots[index] = nk - h.dirty = true - - sz = length(h.slots) - cnt = nk - h.ndel - # Rehash now if necessary - if h.ndel >= ((3*nk)>>2) || cnt*3 > sz*2 - # > 3/4 deleted or > 2/3 full - rehash!(h, cnt > 64000 ? cnt*2 : cnt*4) - end -end - -function setindex!(h::OrderedDict{K,V}, v0, key0) where {K,V} - key = convert(K,key0) - if !isequal(key,key0) - throw(ArgumentError("$key0 is not a valid key for type $K")) - end - v = convert(V, v0) - - index = ht_keyindex2(h, key) - - if index > 0 - @inbounds h.keys[index] = key - @inbounds h.vals[index] = v - else - _setindex!(h, v, key, -index) - end - - return h -end - -function get!(h::OrderedDict{K,V}, key0, default) where {K,V} - key = convert(K,key0) - if !isequal(key,key0) - throw(ArgumentError("$key0 is not a valid key for type $K")) - end - - index = ht_keyindex2(h, key) - - index > 0 && return h.vals[index] - - v = convert(V, default) - _setindex!(h, v, key, -index) - return v -end - -function get!(default::Base.Callable, h::OrderedDict{K,V}, key0) where {K,V} - key = convert(K,key0) - if !isequal(key,key0) - throw(ArgumentError("$key0 is not a valid key for type $K")) - end - - index = ht_keyindex2(h, key) - - index > 0 && return h.vals[index] - - h.dirty = false - v = convert(V, default()) - if h.dirty - index = ht_keyindex2(h, key) - end - if index > 0 - h.keys[index] = key - h.vals[index] = v - else - _setindex!(h, v, key, -index) - end - return v -end - -function getindex(h::OrderedDict{K,V}, key) where {K,V} - index = ht_keyindex(h, key, true) - return (index<0) ? throw(KeyError(key)) : h.vals[index]::V -end - -function get(h::OrderedDict{K,V}, key, default) where {K,V} - index = ht_keyindex(h, key, true) - return (index<0) ? default : h.vals[index]::V -end - -function get(default::Base.Callable, h::OrderedDict{K,V}, key) where {K,V} - index = ht_keyindex(h, key, true) - return (index<0) ? default() : h.vals[index]::V -end - -haskey(h::OrderedDict, key) = (ht_keyindex(h, key, true) >= 0) -in(key, v::Base.KeySet{K,T}) where {K,T<:OrderedDict{K}} = (ht_keyindex(v.dict, key, true) >= 0) - -function getkey(h::OrderedDict{K,V}, key, default) where {K,V} - index = ht_keyindex(h, key, true) - return (index<0) ? default : h.keys[index]::K -end - -function _pop!(h::OrderedDict, index) - @inbounds val = h.vals[h.slots[index]] - _delete!(h, index) - return val -end - -function pop!(h::OrderedDict) - h.ndel > 0 && rehash!(h) - key = h.keys[end] - index = ht_keyindex(h, key, false) - key => _pop!(h, index) -end - -function pop!(h::OrderedDict, key) - index = ht_keyindex(h, key, false) - index > 0 ? _pop!(h, index) : throw(KeyError(key)) -end - -function pop!(h::OrderedDict, key, default) - index = ht_keyindex(h, key, false) - index > 0 ? _pop!(h, index) : default -end - -function _delete!(h::OrderedDict, index) - @inbounds ki = h.slots[index] - @inbounds h.slots[index] = -ki - ccall(:jl_arrayunset, Cvoid, (Any, UInt), h.keys, ki-1) - ccall(:jl_arrayunset, Cvoid, (Any, UInt), h.vals, ki-1) - h.ndel += 1 - h.dirty = true - h -end - -function delete!(h::OrderedDict, key) - index = ht_keyindex(h, key, false) - if index > 0; _delete!(h, index); end - h -end - -function iterate(t::OrderedDict, i = (t.ndel > 0 && rehash!(t); 1)) - i > length(t.keys) ? nothing : (Pair(t.keys[i],t.vals[i]), i+1) -end - -function iterate(v::ValueIterator{T}, i::Int) where {T<:OrderedDict} - i > length(v.dict.vals) ? nothing : (v.dict.vals[i], i+1) -end - -function merge(d::OrderedDict, others::AbstractDict...) - K, V = keytype(d), valtype(d) - for other in others - K = promote_type(K, keytype(other)) - V = promote_type(V, valtype(other)) - end - merge!(OrderedDict{K,V}(), d, others...) -end diff --git a/src/ordered_set.jl b/src/ordered_set.jl deleted file mode 100644 index e700e8c7e..000000000 --- a/src/ordered_set.jl +++ /dev/null @@ -1,112 +0,0 @@ -# ordered sets - -# This was largely copied and modified from Base - -# TODO: Most of these functions should be removed once AbstractSet is introduced there -# (see https://github.com/JuliaLang/julia/issues/5533) - -struct OrderedSet{T} - dict::OrderedDict{T,Nothing} - - OrderedSet{T}() where {T} = new{T}(OrderedDict{T,Nothing}()) - OrderedSet{T}(xs) where {T} = union!(new{T}(OrderedDict{T,Nothing}()), xs) -end -OrderedSet() = OrderedSet{Any}() -OrderedSet(xs) = OrderedSet{eltype(xs)}(xs) - - -show(io::IO, s::OrderedSet) = (show(io, typeof(s)); print(io, "("); !isempty(s) && Base.show_comma_array(io, s,'[',']'); print(io, ")")) - -@delegate OrderedSet.dict [isempty, length] - -sizehint!(s::OrderedSet, sz::Integer) = (sizehint!(s.dict, sz); s) -eltype(s::OrderedSet{T}) where {T} = T - -in(x, s::OrderedSet) = haskey(s.dict, x) - -push!(s::OrderedSet, x) = (s.dict[x] = nothing; s) -pop!(s::OrderedSet, x) = (pop!(s.dict, x); x) -pop!(s::OrderedSet, x, deflt) = pop!(s.dict, x, deflt) == deflt ? deflt : x -delete!(s::OrderedSet, x) = (delete!(s.dict, x); s) - -getindex(x::OrderedSet,i::Int) = x.dict.keys[i] -lastindex(x::OrderedSet) = lastindex(x.dict.keys) -Base.nextind(::OrderedSet, i::Int) = i + 1 # Needed on 0.7 to mimic array indexing. -Base.keys(s::OrderedSet) = 1:length(s) - -union!(s::OrderedSet, xs) = (for x in xs; push!(s,x); end; s) -setdiff!(s::OrderedSet, xs) = (for x in xs; delete!(s,x); end; s) -setdiff!(s::Set, xs::OrderedSet) = (for x in xs; delete!(s,x); end; s) - -empty(s::OrderedSet{T}) where {T} = OrderedSet{T}() -@deprecate similar(s::OrderedSet) empty(s) - -copy(s::OrderedSet) = union!(empty(s), s) - -empty!(s::OrderedSet{T}) where {T} = (empty!(s.dict); s) - -function iterate(s::OrderedSet) - state = iterate(s.dict) - state === nothing && return nothing - s, i = state - s[1], i -end -# NOTE: manually optimized to take advantage of OrderedDict representation -iterate(s::OrderedSet, i) = i > length(s.dict.keys) ? nothing : (s.dict.keys[i], i+1) - -pop!(s::OrderedSet) = pop!(s.dict)[1] - -union(s::OrderedSet) = copy(s) -function union(s::OrderedSet, sets...) - u = OrderedSet{Base.promote_eltype(s, sets...)}() - union!(u,s) - for t in sets - union!(u,t) - end - return u -end - -intersect(s::OrderedSet) = copy(s) -function intersect(s::OrderedSet, sets...) - i = copy(s) - for x in s - for t in sets - if !in(x,t) - delete!(i,x) - break - end - end - end - return i -end - -function setdiff(a::OrderedSet, b) - d = empty(a) - for x in a - if !(x in b) - push!(d, x) - end - end - d -end - -==(l::OrderedSet, r::OrderedSet) = (length(l) == length(r)) && (l <= r) -<(l::OrderedSet, r::OrderedSet) = (length(l) < length(r)) && (l <= r) -<=(l::OrderedSet, r::OrderedSet) = issubset(l, r) - -function filter!(f::Function, s::OrderedSet) - for x in s - if !f(x) - delete!(s, x) - end - end - return s -end -filter(f::Function, s::OrderedSet) = filter!(f, copy(s)) - -const orderedset_seed = UInt === UInt64 ? 0x2114638a942a91a5 : 0xd86bdbf1 -function hash(s::OrderedSet, h::UInt) - h = hash(orderedset_seed, h) - s.dict.ndel > 0 && rehash!(s.dict) - hash(s.dict.keys, h) -end diff --git a/test/runtests.jl b/test/runtests.jl index c854e2bab..c18f267c8 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -19,8 +19,6 @@ tests = ["int_set", "binheap", "mutable_binheap", "default_dict", - "ordered_dict", - "ordered_set", "trie", "list", "multi_dict", diff --git a/test/test_ordered_dict.jl b/test/test_ordered_dict.jl deleted file mode 100644 index c4169bb90..000000000 --- a/test/test_ordered_dict.jl +++ /dev/null @@ -1,376 +0,0 @@ -using DataStructures, Test - -@testset "OrderedDict" begin - - @testset "Constructors" begin - @test isa(OrderedDict(), OrderedDict{Any,Any}) - @test isa(OrderedDict([(1,2.0)]), OrderedDict{Int,Float64}) - @test isa(OrderedDict([("a",1),("b",2)]), OrderedDict{String,Int}) - @test isa(OrderedDict(Pair(1, 1.0)), OrderedDict{Int,Float64}) - @test isa(OrderedDict(Pair(1, 1.0), Pair(2, 2.0)), OrderedDict{Int,Float64}) - @test isa(OrderedDict(Pair(1, 1.0), Pair(2, 2.0), Pair(3, 3.0)), OrderedDict{Int,Float64}) - end - - @testset "empty dictionary" begin - d = OrderedDict{Char, Int}() - @test length(d) == 0 - @test isempty(d) - @test_throws KeyError d['c'] == 1 - d['c'] = 1 - @test !isempty(d) - @test_throws KeyError d[0.01] - @test isempty(empty(d)) - empty!(d) - @test isempty(d) - - # access, modification - for c in 'a':'z' - d[c] = c - 'a' + 1 - end - - @test (d['a'] += 1) == 2 - @test 'a' in keys(d) - @test haskey(d, 'a') - @test get(d, 'B', 0) == 0 - @test !('B' in keys(d)) - @test !haskey(d, 'B') - @test pop!(d, 'a') == 2 - - @test collect(keys(d)) == collect('b':'z') - @test collect(values(d)) == collect(2:26) - @test collect(d) == [Pair(a,i) for (a,i) in zip('b':'z', 2:26)] - end - - @testset "Issue #60" begin - od60 = OrderedDict{Int,Int}() - od60[1] = 2 - - ranges = [2:5, 6:9, 10:13] - for range in ranges - for i = range - od60[i] = i+1 - end - for i = range - delete!( od60, i ) - end - end - od60[14]=15 - - @test od60[14] == 15 - end - - - ############################## - # Copied and modified from Base/test/dict.jl - - # OrderedDict - - @testset "OrderedDict{Int,Int}" begin - h = OrderedDict{Int,Int}() - for i=1:10000 - h[i] = i+1 - end - - @test collect(h) == [Pair(x,y) for (x,y) in zip(1:10000, 2:10001)] - - for i=1:2:10000 - delete!(h, i) - end - for i=1:2:10000 - h[i] = i+1 - end - - for i=1:10000 - @test h[i]==i+1 - end - - for i=1:10000 - delete!(h, i) - end - @test isempty(h) - - h[77] = 100 - @test h[77]==100 - - for i=1:10000 - h[i] = i+1 - end - - for i=1:2:10000 - delete!(h, i) - end - - for i=10001:20000 - h[i] = i+1 - end - - for i=2:2:10000 - @test h[i]==i+1 - end - - for i=10000:20000 - @test h[i]==i+1 - end - end - - @testset "OrderedDict{Any,Any}" begin - h = OrderedDict{Any,Any}([("a", 3)]) - @test h["a"] == 3 - h["a","b"] = 4 - @test h["a","b"] == h[("a","b")] == 4 - h["a","b","c"] = 4 - @test h["a","b","c"] == h[("a","b","c")] == 4 - end - - @testset "KeyError" begin - z = OrderedDict() - get_KeyError = false - try - z["a"] - catch _e123_ - get_KeyError = isa(_e123_, KeyError) - end - @test get_KeyError - end - - @testset "filter" begin - _d = OrderedDict([("a", 0)]) - v = [k for k in filter(x->length(x)==1, collect(keys(_d)))] - @test isa(v, Vector{String}) - end - - @testset "from tuple/vector/pairs/tuple of pair 1" begin - d = OrderedDict(((1, 2), (3, 4))) - d2 = OrderedDict([(1, 2), (3, 4)]) - d3 = OrderedDict(1 => 2, 3 => 4) - d4 = OrderedDict((1 => 2, 3 => 4)) - - @test d[1] === 2 - @test d[3] === 4 - - @test d == d2 == d3 == d4 - @test isa(d, OrderedDict{Int,Int}) - @test isa(d2, OrderedDict{Int,Int}) - @test isa(d3, OrderedDict{Int,Int}) - @test isa(d4, OrderedDict{Int,Int}) - end - - @testset "from tuple/vector/pairs/tuple of pair 2" begin - d = OrderedDict(((1, 2), (3, "b"))) - d2 = OrderedDict([(1, 2), (3, "b")]) - d3 = OrderedDict(1 => 2, 3 => "b") - d4 = OrderedDict((1 => 2, 3 => "b")) - - @test d2[1] === 2 - @test d2[3] == "b" - - ## TODO: tuple of tuples doesn't work for mixed tuple types - # @test d == d2 == d3 == d4 - # @test isa(d, OrderedDict{Int,Any}) - @test d2 == d3 == d4 - @test isa(d2, OrderedDict{Int,Any}) - @test isa(d3, OrderedDict{Int,Any}) - @test isa(d4, OrderedDict{Int,Any}) - end - - @testset "from tuple/vector/pairs/tuple of pair 3" begin - d = OrderedDict(((1, 2), ("a", 4))) - d2 = OrderedDict([(1, 2), ("a", 4)]) - d3 = OrderedDict(1 => 2, "a" => 4) - d4 = OrderedDict((1 => 2, "a" => 4)) - - @test d2[1] === 2 - @test d2["a"] === 4 - - ## TODO: tuple of tuples doesn't work for mixed tuple types - # @test d == d2 == d3 == d4 - @test d2 == d3 == d4 - # @test isa(d, OrderedDict{Any,Int}) - @test isa(d2, OrderedDict{Any,Int}) - @test isa(d3, OrderedDict{Any,Int}) - @test isa(d4, OrderedDict{Any,Int}) - end - - @testset "from tuple/vector/pairs/tuple of pair 4" begin - d = OrderedDict(((1, 2), ("a", "b"))) - d2 = OrderedDict([(1, 2), ("a", "b")]) - d3 = OrderedDict(1 => 2, "a" => "b") - d4 = OrderedDict((1 => 2, "a" => "b")) - - @test d[1] === 2 - @test d["a"] == "b" - - @test d == d2 == d3 == d4 - @test isa(d, OrderedDict{Any,Any}) - @test isa(d2, OrderedDict{Any,Any}) - @test isa(d3, OrderedDict{Any,Any}) - @test isa(d4, OrderedDict{Any,Any}) - end - - @testset "first" begin - @test_throws ArgumentError first(OrderedDict()) - @test first(OrderedDict([(:f, 2)])) == Pair(:f,2) - end - - @testset "Issue #1821" begin - d = OrderedDict{String, Vector{Int}}() - d["a"] = [1, 2] - @test_throws MethodError d["b"] = 1 - @test isa(repr(d), AbstractString) # check that printable without error - end - - @testset "Issue #2344" begin - bestkey(d, key) = key - bestkey(d::AbstractDict{K,V}, key) where {K<:AbstractString,V} = string(key) - bar(x) = bestkey(x, :y) - @test bar(OrderedDict([(:x, [1,2,5])])) == :y - @test bar(OrderedDict([("x", [1,2,5])])) == "y" - end - - @testset "isequal" begin - @test isequal(OrderedDict(), OrderedDict()) - @test isequal(OrderedDict([(1, 1)]), OrderedDict([(1, 1)])) - @test !isequal(OrderedDict([(1, 1)]), OrderedDict()) - @test !isequal(OrderedDict([(1, 1)]), OrderedDict([(1, 2)])) - @test !isequal(OrderedDict([(1, 1)]), OrderedDict([(2, 1)])) - - @test isequal(OrderedDict(), sizehint!(OrderedDict(),96)) - - # Here is what currently happens when dictionaries of different types - # are compared. This is not necessarily desirable. These tests are - # descriptive rather than proscriptive. - @test !isequal(OrderedDict([(1, 2)]), OrderedDict([("dog", "bone")])) - @test isequal(OrderedDict{Int,Int}(), OrderedDict{AbstractString,AbstractString}()) - end - - @testset "data_in" begin - # Generate some data to populate dicts to be compared - data_in = [ (rand(1:1000), randstring(2)) for _ in 1:1001 ] - - # Populate the first dict - d1 = OrderedDict{Int, String}() - for (k,v) in data_in - d1[k] = v - end - data_in = collect(d1) - # shuffle the data - for i in 1:length(data_in) - j = rand(1:length(data_in)) - data_in[i], data_in[j] = data_in[j], data_in[i] - end - # Inserting data in different (shuffled) order should result in - # equivalent dict. - d2 = OrderedDict{Int, AbstractString}() - for (k,v) in data_in - d2[k] = v - end - - @test isequal(d1, d2) - d3 = copy(d2) - d4 = copy(d2) - # Removing an item gives different dict - delete!(d1, data_in[rand(1:length(data_in))][1]) - @test !isequal(d1, d2) - # Changing a value gives different dict - d3[data_in[rand(1:length(data_in))][1]] = randstring(3) - !isequal(d1, d3) - # Adding a pair gives different dict - d4[1001] = randstring(3) - @test !isequal(d1, d4) - end - - @testset "get!" begin - # get! (get with default values assigned to the given location) - f(x) = x^2 - d = OrderedDict(8 => 19) - - @test get!(d, 8, 5) == 19 - @test get!(d, 19, 2) == 2 - - @test get!(d, 42) do # d is updated with f(2) - f(2) - end == 4 - - @test get!(d, 42) do # d is not updated - f(200) - end == 4 - - @test get(d, 13) do # d is not updated - f(4) - end == 16 - - @test d == OrderedDict(8=>19, 19=>2, 42=>4) - end - - @testset "Issue #5886" begin - d5886 = OrderedDict() - for k5886 in 1:11 - d5886[k5886] = 1 - end - for k5886 in keys(d5886) - # undefined ref if not fixed - d5886[k5886] += 1 - end - end - - @testset "Issue #216" begin - @test DataStructures.isordered(OrderedDict{Int, String}) - @test !DataStructures.isordered(Dict{Int, String}) - end - - @testset "Test merging" begin - a = OrderedDict("foo" => 0.0, "bar" => 42.0) - b = OrderedDict("フー" => 17, "バー" => 4711) - @test isa(merge(a, b), OrderedDict{String,Float64}) - end - - @testset "Issue #9295" begin - d = OrderedDict() - @test push!(d, 'a'=> 1) === d - @test d['a'] == 1 - @test push!(d, 'b' => 2, 'c' => 3) === d - @test d['b'] == 2 - @test d['c'] == 3 - @test push!(d, 'd' => 4, 'e' => 5, 'f' => 6) === d - @test d['d'] == 4 - @test d['e'] == 5 - @test d['f'] == 6 - @test length(d) == 6 - end - - @testset "Serialization" begin - s = IOBuffer() - od = OrderedDict{Char,Int64}() - for c in 'a':'e' - od[c] = c-'a'+1 - end - serialize(s, od) - seek(s, 0) - dd = deserialize(s) - @test isa(dd, DataStructures.OrderedDict{Char,Int64}) - @test dd == od - close(s) - end - - @testset "Issue #148" begin - d148 = OrderedDict( - :gps => [], - :direction => 1:8, - :weather => 1:10 - ) - - d148_2 = OrderedDict( - :time => 1:10, - :features => OrderedDict( - :gps => 1:5, - :direction => 1:8, - :weather => 1:10 - ) - ) - end - - @testset "Issue #400" begin - @test filter(p->first(p) > 1, OrderedDict(1=>2, 3=>4)) isa OrderedDict - end - -end # @teestset OrderedDict diff --git a/test/test_ordered_set.jl b/test/test_ordered_set.jl deleted file mode 100644 index f114e12f6..000000000 --- a/test/test_ordered_set.jl +++ /dev/null @@ -1,264 +0,0 @@ -@testset "OrderedSet" begin - - @testset "Constructors" begin - @test isa(OrderedSet(), OrderedSet{Any}) - @test isa(OrderedSet([1,2,3]), OrderedSet{Int}) - @test isa(OrderedSet{Int}([3]), OrderedSet{Int}) - data_in = (1, "banana", ()) - s = OrderedSet(data_in) - data_out = collect(s) - @test isa(data_out, Array{Any,1}) - @test tuple(data_out...) === data_in - @test tuple(data_in...) === tuple(s...) - @test length(data_out) == length(data_in) - end - - @testset "hash" begin - s1 = OrderedSet{String}(["bar", "foo"]) - s2 = OrderedSet{String}(["foo", "bar"]) - s3 = OrderedSet{String}(["baz"]) - @test hash(s1) != hash(s2) - @test hash(s1) != hash(s3) - end - - @testset "isequal" begin - @test isequal(OrderedSet(), OrderedSet()) - @test !isequal(OrderedSet(), OrderedSet([1])) - @test isequal(OrderedSet{Any}(Any[1,2]), OrderedSet{Int}([1,2])) - @test !isequal(OrderedSet{Any}(Any[1,2]), OrderedSet{Int}([1,2,3])) - - @test isequal(OrderedSet{Int}(), OrderedSet{AbstractString}()) - @test !isequal(OrderedSet{Int}(), OrderedSet{AbstractString}([""])) - @test !isequal(OrderedSet{AbstractString}(), OrderedSet{Int}([0])) - @test !isequal(OrderedSet{Int}([1]), OrderedSet{AbstractString}()) - @test isequal(OrderedSet{Any}([1,2,3]), OrderedSet{Int}([1,2,3])) - @test isequal(OrderedSet{Int}([1,2,3]), OrderedSet{Any}([1,2,3])) - @test !isequal(OrderedSet{Any}([1,2,3]), OrderedSet{Int}([1,2,3,4])) - @test !isequal(OrderedSet{Int}([1,2,3]), OrderedSet{Any}([1,2,3,4])) - @test !isequal(OrderedSet{Any}([1,2,3,4]), OrderedSet{Int}([1,2,3])) - @test !isequal(OrderedSet{Int}([1,2,3,4]), OrderedSet{Any}([1,2,3])) - end - - @testset "eltype, empty" begin - s1 = empty(OrderedSet([1,"hello"])) - @test isequal(s1, OrderedSet()) - @test eltype(s1) === Any - s2 = empty(OrderedSet{Float32}([2.0f0,3.0f0,4.0f0])) - @test isequal(s2, OrderedSet()) - @test eltype(s2) === Float32 - end - - @testset "show" begin - @test endswith(sprint(show, OrderedSet()), "OrderedSet{Any}()") - @test endswith(sprint(show, OrderedSet(['a'])), "OrderedSet{Char}(['a'])") - end - - @testset "Core Functionality" begin - s = OrderedSet(); push!(s,1); push!(s,2); push!(s,3) - @test !isempty(s) - @test in(1,s) - @test in(2,s) - @test length(s) == 3 - push!(s,1); push!(s,2); push!(s,3) - @test length(s) == 3 - @test pop!(s,1) == 1 - @test !in(1,s) - @test in(2,s) - @test length(s) == 2 - @test_throws KeyError pop!(s,1) - @test pop!(s,1,:foo) == :foo - @test length(delete!(s,2)) == 1 - @test !in(1,s) - @test !in(2,s) - @test pop!(s) == 3 - @test length(s) == 0 - @test isempty(s) - end - - @testset "copy" begin - data_in = (1,2,9,8,4) - s = OrderedSet(data_in) - c = copy(s) - @test isequal(s,c) - v = pop!(s) - @test !in(v,s) - @test in(v,c) - push!(s,100) - push!(c,200) - @test !in(100,c) - @test !in(200,s) - end - - @testset "sizehint!, empty" begin - s = OrderedSet([1]) - @test isequal(sizehint!(s, 10), OrderedSet([1])) - @test isequal(empty!(s), OrderedSet()) - # TODO: rehash - end - - @testset "iterate" begin - for data_in in ((7,8,4,5), - ("hello", 23, 2.7, (), [], (1,8))) - s = OrderedSet(data_in) - - s_new = OrderedSet() - for el in s - push!(s_new, el) - end - @test isequal(s, s_new) - - t = tuple(s...) - - @test t === data_in - @test length(t) == length(s) - for (e,f) in zip(t,s) - @test e === f - end - end - end - - @testset "union" begin - @test isequal(union(OrderedSet([1])),OrderedSet([1])) - s = ∪(OrderedSet([1,2]), OrderedSet([3,4])) - @test isequal(s, OrderedSet([1,2,3,4])) - s = union(OrderedSet([5,6,7,8]), OrderedSet([7,8,9])) - @test isequal(s, OrderedSet([5,6,7,8,9])) - s = OrderedSet([1,3,5,7]) - union!(s,(2,3,4,5)) - # TODO: order is not the same, so isequal should return false... - @test isequal(s,OrderedSet([1,2,3,4,5,7])) - end - - @testset "intersect" begin - @test isequal(intersect(OrderedSet([1])),OrderedSet([1])) - s = ∩(OrderedSet([1,2]), OrderedSet([3,4])) - @test isequal(s, OrderedSet()) - s = intersect(OrderedSet([5,6,7,8]), OrderedSet([7,8,9])) - @test isequal(s, OrderedSet([7,8])) - @test isequal(intersect(OrderedSet([2,3,1]), OrderedSet([4,2,3]), OrderedSet([5,4,3,2])), OrderedSet([2,3])) - end - - @testset "indexing" begin - s = OrderedSet([1,3,5,7]) - @test s[1] == 1 - @test s[2] == 3 - @test s[end] == 7 - end - - @testset "find" begin - s = OrderedSet([1,3,5,7]) - @test findfirst(isequal(1), s) == 1 - @test findfirst(isequal(7), s) == 4 - if VERSION >= v"0.7.0-DEV.3399" - @test findfirst(isequal(2), s) == nothing - else - @test findfirst(isequal(2), s) == 0 - end - end - - @testset "setdiff" begin - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet()), OrderedSet([1,2,3])) - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet([1])), OrderedSet([2,3])) - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet([1,2])), OrderedSet([3])) - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet([1,2,3])), OrderedSet()) - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet([4])), OrderedSet([1,2,3])) - @test isequal(setdiff(OrderedSet([1,2,3]), OrderedSet([4,1])), OrderedSet([2,3])) - s = OrderedSet([1,3,5,7]) - setdiff!(s,(3,5)) - @test isequal(s,OrderedSet([1,7])) - s = OrderedSet([1,2,3,4]) - setdiff!(s, OrderedSet([2,4,5,6])) - @test isequal(s,OrderedSet([1,3])) - end - - @testset "ordering" begin - @test OrderedSet() < OrderedSet([1]) - @test OrderedSet([1]) < OrderedSet([1,2]) - @test !(OrderedSet([3]) < OrderedSet([1,2])) - @test !(OrderedSet([3]) > OrderedSet([1,2])) - @test OrderedSet([1,2,3]) > OrderedSet([1,2]) - @test !(OrderedSet([3]) <= OrderedSet([1,2])) - @test !(OrderedSet([3]) >= OrderedSet([1,2])) - @test OrderedSet([1]) <= OrderedSet([1,2]) - @test OrderedSet([1,2]) <= OrderedSet([1,2]) - @test OrderedSet([1,2]) >= OrderedSet([1,2]) - @test OrderedSet([1,2,3]) >= OrderedSet([1,2]) - @test !(OrderedSet([1,2,3]) >= OrderedSet([1,2,4])) - @test !(OrderedSet([1,2,3]) <= OrderedSet([1,2,4])) - end - - @testset "issubset, symdiff" begin - for (l,r) in ((OrderedSet([1,2]), OrderedSet([3,4])), - (OrderedSet([5,6,7,8]), OrderedSet([7,8,9])), - (OrderedSet([1,2]), OrderedSet([3,4])), - (OrderedSet([5,6,7,8]), OrderedSet([7,8,9])), - (OrderedSet([1,2,3]), OrderedSet()), - (OrderedSet([1,2,3]), OrderedSet([1])), - (OrderedSet([1,2,3]), OrderedSet([1,2])), - (OrderedSet([1,2,3]), OrderedSet([1,2,3])), - (OrderedSet([1,2,3]), OrderedSet([4])), - (OrderedSet([1,2,3]), OrderedSet([4,1]))) - @test issubset(intersect(l,r), l) - @test issubset(intersect(l,r), r) - @test issubset(l, union(l,r)) - @test issubset(r, union(l,r)) - @test isequal(union(intersect(l,r),symdiff(l,r)), union(l,r)) - end - @test ⊆(OrderedSet([1]), OrderedSet([1,2])) - - ## TODO: not implemented for OrderedSets - #@test ⊊(OrderedSet([1]), OrderedSet([1,2])) - #@test !⊊(OrderedSet([1]), OrderedSet([1])) - #@test ⊈(OrderedSet([1]), OrderedSet([2])) - - # TODO: returns false! - # == is not properly defined for OrderedSets - #@test symdiff(OrderedSet([1,2,3,4]), OrderedSet([2,4,5,6])) == OrderedSet([1,3,5,6]) - - if VERSION >= v"0.7.0-DEV.3127" - # in Julia 0.7 symdiff always returns an array - @test isequal(symdiff(OrderedSet([1,2,3,4]), OrderedSet([2,4,5,6])), [1,3,5,6]) - else - @test isequal(symdiff(OrderedSet([1,2,3,4]), OrderedSet([2,4,5,6])), OrderedSet([1,3,5,6])) - end - - end - - @testset "filter" begin - s = OrderedSet([1,2,3,4]) - @test isequal(filter(isodd,s), OrderedSet([1,3])) - filter!(isodd, s) - @test isequal(s, OrderedSet([1,3])) - end - - @testset "first" begin - @test_throws ArgumentError first(OrderedSet()) - @test first(OrderedSet([2])) == 2 - end - - @testset "empty set" begin - d = OrderedSet{Char}() - @test length(d) == 0 - @test isempty(d) - @test !('c' in d) - push!(d, 'c') - @test !isempty(d) - empty!(d) - @test isempty(d) - end - - @testset "access, modification" begin - d = OrderedSet{Char}() - - for c in 'a':'z' - push!(d, c) - end - - for c in 'a':'z' - @test c in d - end - - @test collect(d) == collect('a':'z') - end - -end # @testset OrderedSet