diff --git a/REQUIRE b/REQUIRE index 859ad46..7e877ff 100644 --- a/REQUIRE +++ b/REQUIRE @@ -1 +1,2 @@ julia 0.7 +Nullables diff --git a/src/IntervalTrees.jl b/src/IntervalTrees.jl index 2747a42..84763a1 100644 --- a/src/IntervalTrees.jl +++ b/src/IntervalTrees.jl @@ -12,6 +12,7 @@ export value using Base: notnothing +using Nullables include("slice.jl") @@ -1215,7 +1216,7 @@ function firstintersection(t::InternalNode{K, V, B}, query::Interval{K}, lower::Union{Nothing, Interval{K}}) where {K, V, B} if isempty(t) || t.maxend < first(query) - return (nothing, 1) + return nothing end i = lower === nothing ? 1 : searchsortedfirst(t.keys, notnothing(lower)) @@ -1225,13 +1226,13 @@ function firstintersection(t::InternalNode{K, V, B}, break end if t.maxends[i] >= first(query) - w, k = firstintersection(t.children[i], query, lower) - w !== nothing && return notnothing(w), k + result = firstintersection(t.children[i], query, lower) + result !== nothing && return result end i += 1 end - return (nothing, 1) + return nothing end @@ -1239,7 +1240,7 @@ function firstintersection(t::LeafNode{K, V, B}, query::Interval{K}, lower::Union{Nothing, Interval{K}}) where {K, V, B} if isempty(t) || t.maxend < first(query) - return (nothing, 1) + return nothing end i = lower === nothing ? 1 : searchsortedfirst(t.keys, notnothing(lower)) @@ -1254,7 +1255,7 @@ function firstintersection(t::LeafNode{K, V, B}, query::Interval{K}, i += 1 end - return (nothing, 1) + return nothing end @@ -1404,9 +1405,9 @@ mutable struct IntersectionIterator{F, K, V1, B1, V2, B2} isdone::Bool # intersection state - u::Union{Nothing, LeafNode{K, V1, B1}} - v::Union{Nothing, LeafNode{K, V2, B2}} - w::Union{Nothing, LeafNode{K, V2, B2}} + u::Nullable{LeafNode{K, V1, B1}} + v::Nullable{LeafNode{K, V2, B2}} + w::Nullable{LeafNode{K, V2, B2}} i::Int j::Int k::Int @@ -1423,27 +1424,26 @@ function Base.iterate(it::IntersectionIterator, _=iterinitstate(it)) if it.isdone return nothing end + + u = get(it.u) + w = get(it.w) + value = (u.entries[it.i], w.entries[it.k]) + if it.successive - u = it.u - w = it.w - value = (u.entries[it.i], w.entries[it.k]) @nextleafkey(w, it.w, it.k) successive_nextintersection!(it) else - u = it.u - w = it.w - value = (u.entries[it.i], w.entries[it.k]) @nextleafkey(w, it.w, it.k) iterative_nextintersection!(it) end return value, nothing end -function iterinitstate(it::IntersectionIterator) +function iterinitstate(it::IntersectionIterator{F, K, V1, B1, V2, B2}) where {F,K,V1,B1,V2,B2} it.isdone = true if it.successive - it.u = isempty(it.t1) ? nothing : firstleaf(it.t1) - it.w = isempty(it.t2) ? nothing : firstleaf(it.t2) + it.u = isempty(it.t1) ? Nullable{LeafNode{K,V1,B1}}() : firstleaf(it.t1) + it.w = isempty(it.t2) ? Nullable{LeafNode{K,V2,B2}}() : firstleaf(it.t2) it.i, it.k = 1, 1 successive_nextintersection!(it) else @@ -1462,9 +1462,8 @@ function iterinitstate(it::IntersectionIterator) # The thing to keep in mind is that this is just like the merge operation in # mergesort, except that some backtracking is needed since intersection # isn't as simple as ordering. - - it.u = isempty(it.t1) ? nothing : firstleaf(it.t1) - it.v = isempty(it.t2) ? nothing : firstleaf(it.t2) + it.u = isempty(it.t1) ? Nullable{LeafNode{K,V1,B1}}() : firstleaf(it.t1) + it.v = isempty(it.t2) ? Nullable{LeafNode{K,V2,B2}}() : firstleaf(it.t2) it.w = it.v it.i, it.j, it.k = 1, 1, 1 iterative_nextintersection!(it) @@ -1475,7 +1474,10 @@ end function iterative_nextintersection!( it::IntersectionIterator{F, K, V1, B1, V2, B2}) where {F, K, V1, B1, V2, B2} - u, v, w, i, j, k = it.u, it.v, it.w, it.i, it.j, it.k + u = isnull(it.u) ? nothing : get(it.u) + v = isnull(it.v) ? nothing : get(it.v) + w = isnull(it.w) ? nothing : get(it.w) + i, j, k = it.i, it.j, it.k it.isdone = true @@ -1531,9 +1533,9 @@ function iterative_nextintersection!( w, k = v, j end - it.u = u - it.v = v - it.w = w + it.u = u === nothing ? Nullable{LeafNode{K,V1,B1}}() : Nullable(u) + it.v = v === nothing ? Nullable{LeafNode{K,V2,B2}}() : Nullable(v) + it.w = w === nothing ? Nullable{LeafNode{K,V2,B2}}() : Nullable(w) it.i = i it.j = j it.k = k @@ -1544,16 +1546,19 @@ end function successive_nextintersection!( it::IntersectionIterator{F, K, V1, B1, V2, B2}) where {F, K, V1, B1, V2, B2} - u, w, i, k = it.u, it.w, it.i, it.k + u = isnull(it.u) ? nothing : get(it.u) + w = isnull(it.w) ? nothing : get(it.w) + i, k =it.i, it.k it.isdone = true + # iterate over t1 intervals while true u === nothing && return unode = notnothing(u) ukey = unode.keys[i] - # find next intersection w + # find next intersection with ukey in t2 while w !== nothing wnode = notnothing(w) wkey = wnode.keys[k] @@ -1577,8 +1582,13 @@ function successive_nextintersection!( # extremely long intervals. if w !== nothing && w.maxend < first(ukey) wnode = notnothing(w) - w, k = firstintersection(it.t2.root, ukey, - wnode.keys[wnode.count]) + result = firstintersection( + it.t2.root, ukey, wnode.keys[wnode.count]) + if result === nothing + w = nothing + else + w, k = result + end end end else @@ -1600,11 +1610,16 @@ function successive_nextintersection!( unode = notnothing(u) ukey = unode.keys[i] - w, k = firstintersection(it.t2.root, ukey, nothing) + result = firstintersection(it.t2.root, ukey, nothing) + if result === nothing + w = nothing + else + w, k = result + end end - it.u = u - it.w = w + it.u = u === nothing ? Nullable{LeafNode{K,V1,B1}}() : Nullable(u) + it.w = w === nothing ? Nullable{LeafNode{K,V2,B2}}() : Nullable(w) it.i = i it.k = k return diff --git a/test/runtests.jl b/test/runtests.jl index 2eae58d..5d487e0 100755 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -328,7 +328,7 @@ end t = T([Interval(4,4)]) - @test !(IntervalTrees.firstintersection(t.root, Interval(4,4), Interval(2,2))[1] === nothing) + @test !(IntervalTrees.firstintersection(t.root, Interval(4,4), Interval(2,2)) === nothing) x = IntervalTrees.Intersection{Int, Interval{Int}, 4}() IntervalTrees.firstintersection!(t, Interval(4,4), Interval(2,2),