@@ -18,6 +18,38 @@ function union_eachblockstoredindex(as::AbstractArray...)
1818 return ∪ (map (eachblockstoredindex, as)... )
1919end
2020
21+ # Get a view of a block assuming it is stored.
22+ function viewblock_stored (a:: AbstractArray{<:Any,N} , I:: Vararg{Block{1},N} ) where {N}
23+ return blocks (a)[Int .(I)... ]
24+ end
25+ function viewblock_stored (a:: AbstractArray{<:Any,N} , I:: Block{N} ) where {N}
26+ return viewblock_stored (a, Tuple (I)... )
27+ end
28+
29+ using FillArrays: Zeros
30+ # Get a view of a block if it is stored, otherwise return a lazy zeros.
31+ function viewblock_or_zeros (a:: AbstractArray{<:Any,N} , I:: Vararg{Block{1},N} ) where {N}
32+ if isstored (a, I... )
33+ return viewblock_stored (a, I... )
34+ else
35+ block_ax = map ((ax, i) -> eachblockaxis (ax)[Int (i)], axes (a), I)
36+ return Zeros {eltype(a)} (block_ax)
37+ end
38+ end
39+ function viewblock_or_zeros (a:: AbstractArray{<:Any,N} , I:: Block{N} ) where {N}
40+ return viewblock_or_zeros (a, Tuple (I)... )
41+ end
42+
43+ function map_block! (f, a_dest:: AbstractArray , I:: Block , a_srcs:: AbstractArray... )
44+ a_srcs_I = map (a_src -> viewblock_or_zeros (a_src, I), a_srcs)
45+ if isstored (a_dest, I)
46+ a_dest[I] .= f .(a_srcs_I... )
47+ else
48+ a_dest[I] = Broadcast. broadcast_preserving_zero_d (f, a_srcs_I... )
49+ end
50+ return a_dest
51+ end
52+
2153function map_blockwise! (f, a_dest:: AbstractArray , a_srcs:: AbstractArray... )
2254 # TODO : This assumes element types are numbers, generalize this logic.
2355 f_preserves_zeros = f (zero .(eltype .(a_srcs))... ) == zero (eltype (a_dest))
@@ -27,22 +59,7 @@ function map_blockwise!(f, a_dest::AbstractArray, a_srcs::AbstractArray...)
2759 BlockRange (a_dest)
2860 end
2961 for I in Is
30- # TODO : Use:
31- # block_dest = @view a_dest[I]
32- # or:
33- # block_dest = @view! a_dest[I]
34- block_dest = blocks_maybe_single (a_dest)[Int .(Tuple (I))... ]
35- # TODO : Use:
36- # block_srcs = map(a_src -> @view(a_src[I]), a_srcs)
37- block_srcs = map (a_srcs) do a_src
38- return blocks_maybe_single (a_src)[Int .(Tuple (I))... ]
39- end
40- # TODO : Use `map!!` to handle immutable blocks.
41- map! (f, block_dest, block_srcs... )
42- # Replace the entire block, handles initializing new blocks
43- # or if blocks are immutable.
44- # TODO : Use `a_dest[I] = block_dest`.
45- blocks (a_dest)[Int .(Tuple (I))... ] = block_dest
62+ map_block! (f, a_dest, I, a_srcs... )
4663 end
4764 return a_dest
4865end
151168function map_stored_blocks (f, a:: AbstractArray )
152169 block_stored_indices = collect (eachblockstoredindex (a))
153170 if isempty (block_stored_indices)
171+ eltype_a′ = Base. promote_op (f, eltype (a))
154172 blocktype_a′ = Base. promote_op (f, blocktype (a))
155- return BlockSparseArray {eltype(blocktype_a′),ndims(a),blocktype_a′} (undef, axes (a))
173+ eltype_a′′ = ! isconcretetype (eltype_a′) ? Any : eltype_a′
174+ blocktype_a′′ =
175+ ! isconcretetype (blocktype_a′) ? AbstractArray{eltype_a′′,ndims (a)} : blocktype_a′
176+ return BlockSparseArray {eltype_a′′,ndims(a),blocktype_a′′} (undef, axes (a))
156177 end
157178 stored_blocks = map (B -> f (@view! (a[B])), block_stored_indices)
158179 blocktype_a′ = eltype (stored_blocks)
0 commit comments