@@ -342,3 +342,82 @@ julia> s
342342 Foo (44 , " d" 
343343 Foo (55 , " e" 
344344``` 
345+ 
346+ ## Advanced: StructArrays versus struct-of-arrays layout in higher-dimensional array  
347+ 
348+ Regular arrays of structs can sometimes be reinterpreted as arrays of primitive values with an added
349+ initial dimension.
350+ 
351+ ``` julia 
352+ julia>  v =  [1.0 + 3im , 2.0 - im]
353+ 2 - element Vector{ComplexF64}: 
354+  1.0  +  3.0im 
355+  2.0  -  1.0im 
356+ 
357+ julia>  reinterpret (reshape, Float64, v)
358+ 2 × 2  reinterpret (reshape, Float64, :: Vector{ComplexF64} ) with eltype Float64: 
359+  1.0    2.0 
360+  3.0   - 1.0 
361+ ``` 
362+ 
363+ However, the situation is more complex for the ` StructArray `  format, where ` s = StructArray(v) `  is
364+ stored as two separate ` Vector{Float64} ` . ` reinterpret `  on ` StructArray `  returns an
365+ "array-of-structs" layout, as the reinterpretation works element-wise:
366+ 
367+ ``` julia 
368+ julia>  s =  StructArray ([1.0 + 3im , 2.0 - im])
369+ 2 - element StructArray (:: Vector{Float64} , :: Vector{Float64} ) with eltype ComplexF64: 
370+  1.0  +  1.0im 
371+  2.0  -  1.0im 
372+ 
373+ julia>  reinterpret (reshape, Float64, s) #  The actual memory is `([1.0, 2.0], [3.0, -1.0])`
374+ 2 × 2  reinterpret (reshape, Float64, StructArray (:: Vector{Float64} , :: Vector{Float64} )) with eltype Float64: 
375+  1.0    2.0 
376+  3.0   - 1.0 
377+ ``` 
378+ 
379+ If you already have a ` StructArray ` , the easiest way is to get the higher-dimensional
380+ "struct-of-arrays" layout is to directly stack the components in memory order:
381+ 
382+ ``` julia 
383+ julia>  using  StackViews #  lazily cat/stack arrays in a new tailing dimension
384+ 
385+ julia>  StackView (StructArrays. components (s)... )
386+ 2 × 2  StackView{Float64, 2 , 2 , Tuple{Vector{Float64}, Vector{Float64}}}: 
387+  1.0    3.0 
388+  2.0   - 1.0 
389+ ``` 
390+ 
391+ StructArrays also provides ` dims `  keyword to reinterpret a given memory block without creating new
392+ memory:
393+ 
394+ ``` julia 
395+ julia>  v =  Float64[1  3 ; 2  - 1 ]
396+ 2 × 2  Matrix{Float64}: 
397+  1.0    3.0 
398+  2.0   - 1.0 
399+ 
400+ julia>  s =  StructArray {ComplexF64} (v, dims= 1 )
401+ 2 - element StructArray (view (:: Matrix{Float64} , 1 , :), view (:: Matrix{Float64} , 2 , :)) with eltype ComplexF64: 
402+  1.0  +  2.0im 
403+  3.0  -  1.0im 
404+ 
405+ julia>  s =  StructArray {ComplexF64} (v, dims= 2 )
406+ 2 - element StructArray (view (:: Matrix{Float64} , :, 1 ), view (:: Matrix{Float64} , :, 2 )) with eltype ComplexF64: 
407+  1.0  +  3.0im 
408+  2.0  -  1.0im 
409+ 
410+ julia>  s[1 ] =  0 + 0im ; s #  `s` is a reinterpretation view and doesn't copy memory
411+ 2 - element StructArray (view (:: Matrix{Float64} , :, 1 ), view (:: Matrix{Float64} , :, 2 )) with eltype ComplexF64: 
412+  0.0  +  0.0im 
413+  2.0  -  1.0im 
414+ 
415+ julia>  v #  thus `v` will be modified as well
416+ 2 × 2  Matrix{Float64}: 
417+  0.0    0.0 
418+  2.0   - 1.0 
419+ ``` 
420+ 
421+ For column-major arrays, reinterpreting along the last dimension (` dims=ndims(v) ` ) makes every
422+ component of ` s `  a view of contiguous memory and thus is more efficient. In the previous example,
423+ when ` dims=2 `  we have ` s.re == [1.0, 2.0] ` , which reflects the first column of ` v ` .
0 commit comments