From 74e984d2af07297dbc549605f507568d3fcbe10a Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Thu, 24 Oct 2024 09:59:22 -0600 Subject: [PATCH 1/2] Improve getindex performance on ChainedVector with UnitRanges --- src/chainedvector.jl | 27 ++++++++++++++++++++++++++- test/chainedvector.jl | 11 +++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/chainedvector.jl b/src/chainedvector.jl index 86d58d0..6b9c289 100644 --- a/src/chainedvector.jl +++ b/src/chainedvector.jl @@ -177,7 +177,6 @@ Base.@propagate_inbounds function Base.getindex(x::ChainedVector{T, A}, inds::Ab arrays = x.arrays for i = 1:len @inbounds ind2 = inds[i] - # @boundscheck checkbounds(x, ind2) chunk, chunklen, j = linearindex(x, chunk, chunklen, j, ind, ind2) @inbounds res[i] = arrays[chunk][j] ind = ind2 @@ -185,6 +184,32 @@ Base.@propagate_inbounds function Base.getindex(x::ChainedVector{T, A}, inds::Ab return res end +Base.@propagate_inbounds function Base.getindex(x::ChainedVector{T, A}, inds::UnitRange{Int}) where {T, A} + isempty(inds) && return similar(x, 0) + len = length(inds) + res = similar(x.arrays[1], len) + chunk = j = ind = 1 + chunklen = length(x.arrays[1]) + arrays = x.arrays + # linearindex first item + chunk, chunklen, j = linearindex(x, chunk, chunklen, j, ind, inds[1]) + @inbounds arraychunk = arrays[chunk] + i = 1 + # now we can copy entire chunks and avoid further linear indexing + while true + N = min(len, chunklen - j + 1) + unsafe_copyto!(res, i, arraychunk, j, N) + len -= N + len == 0 && break + i += N + chunk += 1 + chunklen = length(arrays[chunk]) + j = 1 + arraychunk = arrays[chunk] + end + return res +end + Base.@propagate_inbounds function Base.isassigned(A::ChainedVector, i::Integer) @boundscheck checkbounds(A, i) chunk, ix = index(A, i) diff --git a/test/chainedvector.jl b/test/chainedvector.jl index 391ed76..8999da4 100644 --- a/test/chainedvector.jl +++ b/test/chainedvector.jl @@ -734,3 +734,14 @@ end @test deleteat!(v2, m2) == deleteat!(s2, m2) end end + +@testset "getindex with UnitRange" begin + x = ChainedVector([collect(1:i) for i = 10:100]) + @test isempty(x[1:0]) + @test x[1:1] == [1] + @test x[1:end] == x + y = collect(x) + for i = 1:length(x), j = 1:length(x) + @test x[i:j] == y[i:j] + end +end From 97b6005b51498751c1621f8c4278f1b8cf426ac7 Mon Sep 17 00:00:00 2001 From: Jacob Quinn Date: Thu, 24 Oct 2024 11:28:10 -0600 Subject: [PATCH 2/2] Update src/chainedvector.jl Co-authored-by: Jerry Ling --- src/chainedvector.jl | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/chainedvector.jl b/src/chainedvector.jl index 6b9c289..4d5557d 100644 --- a/src/chainedvector.jl +++ b/src/chainedvector.jl @@ -187,10 +187,11 @@ end Base.@propagate_inbounds function Base.getindex(x::ChainedVector{T, A}, inds::UnitRange{Int}) where {T, A} isempty(inds) && return similar(x, 0) len = length(inds) - res = similar(x.arrays[1], len) - chunk = j = ind = 1 - chunklen = length(x.arrays[1]) arrays = x.arrays + res = similar(arrays[1], len) + chunk = j = ind = 1 + chunklen = length(arrays[1]) + # linearindex first item chunk, chunklen, j = linearindex(x, chunk, chunklen, j, ind, inds[1]) @inbounds arraychunk = arrays[chunk]