From 90586127782fcef21a20f435a6100420a624586c Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 14 Mar 2025 15:15:53 -0500 Subject: [PATCH 1/2] add `setindex!` specialization for VectorOfArray{StructArray} --- ext/RecursiveArrayToolsStructArraysExt.jl | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/ext/RecursiveArrayToolsStructArraysExt.jl b/ext/RecursiveArrayToolsStructArraysExt.jl index b4a5d07c..80c8b71f 100644 --- a/ext/RecursiveArrayToolsStructArraysExt.jl +++ b/ext/RecursiveArrayToolsStructArraysExt.jl @@ -3,4 +3,25 @@ module RecursiveArrayToolsStructArraysExt import RecursiveArrayTools, StructArrays RecursiveArrayTools.rewrap(::StructArrays.StructArray, u) = StructArrays.StructArray(u) -end \ No newline at end of file +using RecursiveArrayTools: VectorOfArray +using StructArrays: StructArray + +const VectorOfStructArray{T, N} = VectorOfArray{T, N, <:StructArray} + +# Since `StructArray` lazily materializes struct entries, the general `setindex!(x, val, I)` +# operation `VA.u[I[end]][Base.front(I)...]` will only update a lazily materialized struct +# entry of `u`, but will not actually mutate `x::StructArray`. See the StructArray documentation +# for more details: +# +# https://juliaarrays.github.io/StructArrays.jl/stable/counterintuitive/#Modifying-a-field-of-a-struct-element +# +# To avoid this, we can materialize a struct entry, modify it, and then use `setindex!` +# with the modified struct entry. +function Base.setindex!(VA::VectorOfStructArray{T, N}, v, + I::Int...) where {T, N} + u_I = VA.u[I[end]] + u_I[Base.front(I)...] = v + return VA.u[I[end]] = u_I +end + +end From 107fe3c419b44fd8fa102809ad4baf3c84c4f757 Mon Sep 17 00:00:00 2001 From: Jesse Chan Date: Fri, 14 Mar 2025 15:15:58 -0500 Subject: [PATCH 2/2] add tests --- test/basic_indexing.jl | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/basic_indexing.jl b/test/basic_indexing.jl index a71100b3..37c24857 100644 --- a/test/basic_indexing.jl +++ b/test/basic_indexing.jl @@ -262,3 +262,12 @@ num_allocs = @allocations foo!(u_matrix) # issue 354 @test VectorOfArray(ones(1))[:] == ones(1) + +# check VectorOfArray indexing for a StructArray of mutable structs +using StructArrays +using StaticArrays: MVector +x = VectorOfArray(StructArray{MVector{1, Float64}}(ntuple(_ -> [1.0, 2.0], 1))) + +# check VectorOfArray assignment +x[1, 1] = 10 +@test x[1, 1] == 10