Skip to content

Commit 5eb85d5

Browse files
committed
Add specialized Base.typed_vcat and improve append! for VectorOfArrays
1 parent 9d760da commit 5eb85d5

File tree

2 files changed

+80
-16
lines changed

2 files changed

+80
-16
lines changed

src/vector_of_arrays.jl

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -263,26 +263,38 @@ Base.length(A::VectorOfArrays) = length(A.kernel_size)
263263
end
264264

265265

266-
function Base.append!(A::VectorOfArrays{T,N}, B::VectorOfArrays{U,N}) where {T,N,U}
267-
if !isempty(B)
268-
# Implementation supports A === B
269-
270-
A_ep = A.elem_ptr
271-
B_ep = B.elem_ptr
272-
idxs_B = firstindex(B_ep):(lastindex(B_ep) - 1)
273-
delta_ep_idx = lastindex(A_ep) + 1 - firstindex(B_ep)
274-
delta_ep = last(A_ep) - first(B_ep)
275-
resize!(A_ep, length(eachindex(A_ep)) + length(idxs_B))
276-
@assert checkbounds(Bool, B_ep, idxs_B)
277-
@assert checkbounds(Bool, A_ep, broadcast(+, idxs_B, delta_ep_idx))
278-
@inbounds @simd for i_B in idxs_B
279-
A_ep[i_B + delta_ep_idx] = B_ep[i_B + 1] + delta_ep
266+
function append_elemptr!(A::AbstractVector{<:Integer}, B::AbstractVector{<:Integer})
267+
idxs_A = LinearIndices(A)
268+
idxs_B = LinearIndices(B)
269+
length_B = length(idxs_B)
270+
271+
A_from = last(idxs_A) + 1
272+
A_to = A_from - 1 + length_B - 1
273+
resize!(A, length(first(idxs_A):A_to))
274+
275+
B_from = first(idxs_B) + 1
276+
B_to = last(idxs_B)
277+
278+
A_idxs_offs = A_from - B_from
279+
280+
checkindex(Bool, eachindex(B), B_from:B_to)
281+
checkindex(Bool, eachindex(A), (B_from:B_to) .+ A_idxs_offs)
282+
@inbounds begin
283+
value_offset = A[A_from - 1] - B[B_from - 1]
284+
@simd for i in B_from:B_to
285+
A[i + A_idxs_offs] = B[i] + value_offset
280286
end
287+
end
288+
289+
A
290+
end
291+
281292

293+
function Base.append!(A::VectorOfArrays{T,N}, B::VectorOfArrays{U,N}) where {T,N,U}
294+
if !isempty(B)
282295
append!(A.data, B.data)
296+
append_elemptr!(A.elem_ptr, B.elem_ptr)
283297
append!(A.kernel_size, B.kernel_size)
284-
285-
simple_consistency_checks(A)
286298
end
287299
A
288300
end
@@ -310,6 +322,23 @@ function Base.append!(A::VectorOfArrays{T,N}, B::AbstractVector{<:AbstractArray{
310322
end
311323

312324

325+
Base.vcat(V::VectorOfArrays) = V
326+
327+
function Base.vcat(Vs::(VectorOfArrays{U,N} where U)...) where {N}
328+
data = vcat(map(x -> x.data, Vs)...)
329+
330+
elem_ptr = similar(Vs[1].elem_ptr, 1)
331+
elem_ptr[1] = firstindex(data)
332+
@inbounds for i in eachindex(Vs)
333+
append_elemptr!(elem_ptr, Vs[i].elem_ptr)
334+
end
335+
336+
kernel_size = vcat(map(x -> x.kernel_size, Vs)...)
337+
338+
VectorOfArrays(data, elem_ptr, kernel_size, no_consistency_checks)
339+
end
340+
341+
313342
Base.@propagate_inbounds function Base.unsafe_view(A::VectorOfArrays, idxs::AbstractUnitRange{<:Integer})
314343
from = first(idxs)
315344
to = last(idxs)

test/vector_of_arrays.jl

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,20 @@ using Test
55

66
using UnsafeArrays
77

8+
using ArraysOfArrays: full_consistency_checks, append_elemptr!
9+
810

911
@testset "vector_of_arrays" begin
1012
ref_AoA1(T::Type, n::Integer) = n == 0 ? [Array{T}(undef, 5)][1:0] : [rand(T, rand(1:9)) for i in 1:n]
1113
ref_AoA2(T::Type, n::Integer) = n == 0 ? [Array{T}(undef, 4, 2)][1:0] : [rand(T, rand(1:4), rand(1:4)) for i in 1:n]
1214
ref_AoA3(T::Type, n::Integer) = n == 0 ? [Array{T}(undef, 3, 2, 4)][1:0] : [rand(T, rand(1:3), rand(1:3), rand(1:3)) for i in 1:n]
1315

16+
@testset "element pointer handling" begin
17+
A = [2, 4, 5, 9]; B = [3, 6, 8]
18+
@test @inferred(append_elemptr!(deepcopy(A), B)) == [2, 4, 5, 9, 12, 14]
19+
@test @inferred(append_elemptr!([2], [5])) == [2]
20+
end
21+
1422

1523
@testset "ctors" begin
1624
A1 = ref_AoA1(Float32, 5)
@@ -65,6 +73,33 @@ using UnsafeArrays
6573
end
6674

6775

76+
@testset "append! and vcat" begin
77+
A1 = ref_AoA3(Float32, 3); A2 = ref_AoA3(Float32, 0)
78+
A3 = ref_AoA3(Float32, 4); A4 = ref_AoA3(Float64, 2)
79+
80+
B1 = VectorOfArrays(A1); B2 = VectorOfArrays(A2);
81+
B3 = VectorOfArrays(A3); B4 = VectorOfArrays(A4);
82+
83+
@test @inferred(vcat(B1)) === B1
84+
full_consistency_checks(vcat(B1))
85+
86+
@test @inferred(vcat(B1, B2)) isa VectorOfArrays
87+
@test vcat(B1, B2) == vcat(A1, A2)
88+
@test eltype(vcat(B1, B2)) == Array{Float32,3}
89+
full_consistency_checks(vcat(B1, B2))
90+
91+
@test @inferred(vcat(B1, B3)) isa VectorOfArrays
92+
@test vcat(B1, B3) == vcat(A1, A3)
93+
@test eltype(vcat(B1, B3)) == Array{Float32,3}
94+
full_consistency_checks(vcat(B1, B3))
95+
96+
@test @inferred(vcat(B1, B2, B3, B4)) isa VectorOfArrays
97+
@test vcat(B1, B2, B3, B4) == vcat(A1, A2, A3, A4)
98+
@test eltype(vcat(B1, B2, B3, B4)) == Array{Float64,3}
99+
full_consistency_checks(vcat(B1, B2, B3, B4))
100+
end
101+
102+
68103
@testset "examples" begin
69104
VA = VectorOfArrays{Float64, 2}()
70105

0 commit comments

Comments
 (0)