diff --git a/src/SentinelArrays.jl b/src/SentinelArrays.jl index 956df64..e7b0919 100644 --- a/src/SentinelArrays.jl +++ b/src/SentinelArrays.jl @@ -58,6 +58,9 @@ mutable struct SentinelArray{T, N, S, V, A <: AbstractArray{T, N}} <: AbstractAr end Base.parent(A::SentinelArray) = A.data +function Base.unaliascopy(A::SentinelArray) + return SentinelArray(Base.unaliascopy(parent(A)), A.sentinel, A.value) +end # users of pointer should be careful because it's the raw storage data, which doesn't respect the sentinel semantics Base.pointer(A::SentinelArray) = pointer(parent(A)) diff --git a/src/chainedvector.jl b/src/chainedvector.jl index c85f4b5..4a02a7e 100644 --- a/src/chainedvector.jl +++ b/src/chainedvector.jl @@ -477,7 +477,7 @@ function Base.copy(A::ChainedVector{T}) where {T} end function Base.unaliascopy(x::ChainedVector{T, A}) where {T, A} - arrays = map(copy, x.arrays) + arrays = map(Base.unaliascopy, x.arrays) return ChainedVector{T, A}(arrays, copy(x.inds)) end @@ -630,6 +630,7 @@ Base.@propagate_inbounds function Base.insert!(A::ChainedVector{T, AT}, i::Integ end function Base.vcat(A::ChainedVector{T, AT}, arrays::ChainedVector{T, AT}...) where {T, AT <: AbstractVector{T}} + isempty(arrays) && return Base.unaliascopy(A) newarrays = vcat(A.arrays, map(x->x.arrays, arrays)...) n = length(A.inds) inds = Vector{Int}(undef, n + sum(x->length(x.inds), arrays)) diff --git a/test/chainedvector.jl b/test/chainedvector.jl index ef7cbfd..76e22c0 100644 --- a/test/chainedvector.jl +++ b/test/chainedvector.jl @@ -1,3 +1,19 @@ +function test_unaliased_vcat(x, replacement) + before = collect(Iterators.map(identity, x)) + y = @inferred vcat(x) + @test isequal(y, x) + @test typeof(y) === typeof(x) + @test y !== x + @test y.arrays !== x.arrays + @test y.inds !== x.inds + if !isempty(y) + y[1] = replacement + @test isequal(collect(Iterators.map(identity, x)), before) + end + empty!(y) + @test isequal(collect(Iterators.map(identity, x)), before) +end + @testset "ChainedVector" begin x = ChainedVector([[1,2,3], [4,5,6], [7,8,9,10]]) @@ -58,6 +74,15 @@ x = ChainedVector([[1,2,3], [4,5,6], [7,8,9,10]]) y = ChainedVector([[11,12,13], [14,15,16], [17,18,19,20]]) + @testset "single-input vcat" begin + test_unaliased_vcat(ChainedVector(Vector{Int}[]), 1) + test_unaliased_vcat(ChainedVector([[1]]), 2) + test_unaliased_vcat(ChainedVector(AbstractVector[[1], Float32[2]]), 3.0f0) + test_unaliased_vcat(ChainedVector([Union{Missing, Int}[1, missing]]), 2) + test_unaliased_vcat(ChainedVector([SentinelArray(Union{Missing, Int}[1, missing])]), 2) + test_unaliased_vcat(ChainedVector([ChainedVector([[1]]), ChainedVector([[2]])]), 3) + end + z = vcat(x, y) @test length(z) == 20 @test z == 1:20