diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 200586213cc90..cbf6a321d8286 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -888,7 +888,7 @@ julia> empty([1.0, 2.0, 3.0], String) String[] ``` """ -empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}() +empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0) # like empty, but should return a mutable collection, a Vector by default emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}() diff --git a/test/abstractarray.jl b/test/abstractarray.jl index 8762440a2f25a..6552f0c2ccb96 100644 --- a/test/abstractarray.jl +++ b/test/abstractarray.jl @@ -5,6 +5,9 @@ using Random, LinearAlgebra isdefined(Main, :InfiniteArrays) || @eval Main include("testhelpers/InfiniteArrays.jl") using .Main.InfiniteArrays +isdefined(Main, :StructArrays) || @eval Main include("testhelpers/StructArrays.jl") +using .Main.StructArrays + A = rand(5,4,3) @testset "Bounds checking" begin @test checkbounds(Bool, A, 1, 1, 1) == true @@ -999,6 +1002,16 @@ end @test isempty(v) @test isempty(v2::Vector{Int}) @test isempty(v3::Vector{Float64}) + + S = StructArrays.StructArray{Complex{Int}}((v, v)) + for T in (Complex{Int}, ComplexF64) + S0 = empty(S, T) + @test S0 isa StructArrays.StructArray{T} + @test length(S0) == 0 + end + S0 = empty(S, String) + @test S0 isa Vector{String} + @test length(S0) == 0 end @testset "CartesianIndices" begin diff --git a/test/testhelpers/StructArrays.jl b/test/testhelpers/StructArrays.jl new file mode 100644 index 0000000000000..f03b07f4e60ad --- /dev/null +++ b/test/testhelpers/StructArrays.jl @@ -0,0 +1,39 @@ +module StructArrays + +struct StructArray{T,N,C <: Tuple{Vararg{AbstractArray{<:Any,N}}}} <: AbstractArray{T,N} + components :: C + + function StructArray{T,N,C}(components::C) where {T,N,C} + fieldcount(T) == length(components) || throw(ArgumentError("number of components incompatible with eltype")) + allequal(axes.(components)) || throw(ArgumentError("component arrays must have the same axes")) + new{T,N,C}(components) + end +end + +function StructArray{T}(components::Tuple{Vararg{AbstractArray{<:Any,N}}}) where {T,N} + StructArray{T,N,typeof(components)}(components) +end + +Base.size(S::StructArray) = size(S.components[1]) +Base.axes(S::StructArray) = axes(S.components[1]) +function Base.getindex(S::StructArray{T,N}, inds::Vararg{Int,N}) where {T,N} + vals = map(x -> x[inds...], S.components) + T(vals...) +end +function Base.setindex!(S::StructArray{T,N}, val, inds::Vararg{Int,N}) where {T,N} + vals = getfield.(Ref(convert(T, val)), fieldnames(T)) + for (A,v) in zip(S.components, vals) + A[inds...] = v + end + S +end + +isnonemptystructtype(::Type{T}) where {T} = isstructtype(T) && fieldcount(T) != 0 + +function Base.similar(S::StructArray, ::Type{T}, dims::Tuple{Int, Vararg{Int}}) where {T} + isnonemptystructtype(T) || return similar(S.components[1], T, dims) + arrs = similar.(S.components, fieldtypes(T), Ref(dims)) + StructArray{T}(arrs) +end + +end