From 809facfeb88f4c3b2c909b89e9e61c127099b70d Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Fri, 26 May 2023 12:25:34 +0530 Subject: [PATCH 1/4] use similar in empty --- base/abstractarray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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}() From cad1d2e8d823760760cb036bb0f5935f0bb6d7ab Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Fri, 15 Dec 2023 10:30:44 +0530 Subject: [PATCH 2/4] Add StructArrays test-helper and test against it --- base/abstractarray.jl | 5 ++-- test/abstractarray.jl | 13 +++++++++++ test/testhelpers/StructArrays.jl | 39 ++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 test/testhelpers/StructArrays.jl diff --git a/base/abstractarray.jl b/base/abstractarray.jl index cbf6a321d8286..1415404569052 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -890,8 +890,9 @@ String[] """ 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}() +# like empty, but should return a mutable collection +emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0) +# return a Vector by default for non-array types emptymutable(itr, ::Type{U}) where {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..89dad0b036f77 --- /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 From 7950c9d37c35fd479f2c3cee934540f2d1db364d Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Fri, 15 Dec 2023 10:37:15 +0530 Subject: [PATCH 3/4] change tabs to spaces --- test/testhelpers/StructArrays.jl | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/test/testhelpers/StructArrays.jl b/test/testhelpers/StructArrays.jl index 89dad0b036f77..f03b07f4e60ad 100644 --- a/test/testhelpers/StructArrays.jl +++ b/test/testhelpers/StructArrays.jl @@ -1,39 +1,39 @@ module StructArrays struct StructArray{T,N,C <: Tuple{Vararg{AbstractArray{<:Any,N}}}} <: AbstractArray{T,N} - components :: C + 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 + 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) + 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...) + 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 + 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) + isnonemptystructtype(T) || return similar(S.components[1], T, dims) + arrs = similar.(S.components, fieldtypes(T), Ref(dims)) + StructArray{T}(arrs) end end From 999a14062309517ed3d8c39a2070707715dfba84 Mon Sep 17 00:00:00 2001 From: Jishnu Bhattacharya Date: Mon, 18 Dec 2023 19:42:05 +0530 Subject: [PATCH 4/4] Revert emptymutable --- base/abstractarray.jl | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 1415404569052..cbf6a321d8286 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -890,9 +890,8 @@ String[] """ empty(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0) -# like empty, but should return a mutable collection -emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = similar(a, U, 0) -# return a Vector by default for non-array types +# like empty, but should return a mutable collection, a Vector by default +emptymutable(a::AbstractVector{T}, ::Type{U}=T) where {T,U} = Vector{U}() emptymutable(itr, ::Type{U}) where {U} = Vector{U}() """