From e15c3bcca104dbc97ecf4a145a27174c6afcb294 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Fri, 14 Aug 2020 01:09:19 -0600 Subject: [PATCH] Fix iteration issue when chains have zero-length Fixes #27. The issue here is that `iterate` for `ChainedVector` was assuming that underlying array chains wouldn't have zero-length. If a user is doing a lot of filtering/deleting, however, it might be the case that certain chunks end up with zero-length (though we do try to prune those out when possible, so I'm still a little unsure how we get in this state). Nevertheless, this assumption is a bit optimistic, and we can do better by just checking if the next chunk is zero-length when iterating and moving on to the next chunk if so. --- src/chainedvector.jl | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/chainedvector.jl b/src/chainedvector.jl index 7b6beb2..ef6b4e4 100644 --- a/src/chainedvector.jl +++ b/src/chainedvector.jl @@ -50,18 +50,29 @@ end # efficient iteration @inline function Base.iterate(A::ChainedVector) length(A) == 0 && return nothing - i = 2 + i = 1 chunk = 1 chunk_i = 1 chunk_len = A.inds[1] - if i > chunk_len + while i > chunk_len chunk += 1 - chunk_i = 1 - @inbounds chunk_len = A.inds[min(length(A.inds), chunk)] + @inbounds chunk_len = A.inds[chunk] + i <= chunk_len && break + end + x = A.arrays[chunk][1] + # find next valid index + i += 1 + if i > chunk_len + while true + chunk += 1 + chunk > length(A.inds) && break + @inbounds chunk_len = A.inds[chunk] + i <= chunk_len && break + end else chunk_i += 1 end - return A.arrays[1][1], (i, chunk, chunk_i, chunk_len, length(A)) + return x, (i, chunk, chunk_i, chunk_len, length(A)) end @inline function Base.iterate(A::ChainedVector, (i, chunk, chunk_i, chunk_len, len)) @@ -69,9 +80,13 @@ end @inbounds x = A.arrays[chunk][chunk_i] i += 1 if i > chunk_len - chunk += 1 chunk_i = 1 - @inbounds chunk_len = A.inds[min(length(A.inds), chunk)] + while true + chunk += 1 + chunk > length(A.inds) && break + @inbounds chunk_len = A.inds[chunk] + i <= chunk_len && break + end else chunk_i += 1 end