207207function map_indices! end
208208
209209@interface interface:: AbstractArrayInterface function map_indices! (
210- f, a_dest:: AbstractArray , indices , as:: AbstractArray...
210+ indices, f, a_dest:: AbstractArray , as:: AbstractArray...
211211)
212212 for I in indices
213213 a_dest[I] = f (map (a -> a[I], as)... )
@@ -221,7 +221,7 @@ function map_stored! end
221221@interface interface:: AbstractArrayInterface function map_stored! (
222222 f, a_dest:: AbstractArray , as:: AbstractArray...
223223)
224- @interface interface map_indices! (f, a_dest, eachstoredindex (as... ), as... )
224+ @interface interface map_indices! (eachstoredindex (as... ), f, a_dest , as... )
225225 return a_dest
226226end
227227
@@ -231,7 +231,7 @@ function map_all! end
231231@interface interface:: AbstractArrayInterface function map_all! (
232232 f, a_dest:: AbstractArray , as:: AbstractArray...
233233)
234- @interface interface map_indices! (f, a_dest, eachindex (as... ), as... )
234+ @interface interface map_indices! (eachindex (as... ), f, a_dest , as... )
235235 return a_dest
236236end
237237
@@ -250,37 +250,32 @@ using ArrayLayouts: ArrayLayouts, zero!
250250 return @interface interface map_stored! (f, a, a)
251251end
252252
253+ # Determines if a function preserves the stored values
254+ # of the destination sparse array.
255+ # The current code may be inefficient since it actually
256+ # accesses an unstored element, which in the case of a
257+ # sparse array of arrays can allocate an array.
258+ # Sparse arrays could be expected to define a cheap
259+ # unstored element allocator, for example
260+ # `get_prototypical_unstored(a::AbstractArray)`.
261+ function preserves_unstored (f, a_dest:: AbstractArray , as:: AbstractArray... )
262+ I = first (eachindex (as... ))
263+ return iszero (f (map (a -> getunstoredindex (a, I), as)... ))
264+ end
265+
253266@interface interface:: AbstractSparseArrayInterface function Base. map! (
254267 f, a_dest:: AbstractArray , as:: AbstractArray...
255268)
256- # TODO : Define a function `preserves_unstored(a_dest, f, as...)`
257- # to determine if a function preserves the stored values
258- # of the destination sparse array.
259- # The current code may be inefficient since it actually
260- # accesses an unstored element, which in the case of a
261- # sparse array of arrays can allocate an array.
262- # Sparse arrays could be expected to define a cheap
263- # unstored element allocator, for example
264- # `get_prototypical_unstored(a::AbstractArray)`.
265- I = first (eachindex (as... ))
266- preserves_unstored = iszero (f (map (a -> getunstoredindex (a, I), as)... ))
267- if ! preserves_unstored
268- # Doesn't preserve unstored values, loop over all elements.
269- @interface interface map_all! (f, a_dest, as... )
270- return a_dest
271- end
272- # Unalias the inputs from the destination
273- # to make sure the inputs aren't overwritten incorrectly.
274- # See: https://github.com/JuliaLang/julia/blob/v1.11.2/base/broadcast.jl#L935-L948
275- as = map (a -> a_dest === a ? a : Base. unalias (a_dest, a), as)
276- indices_stored = eachstoredindex (as... )
277- if eachstoredindex (a_dest) ⊈ indices_stored
278- # If not all indices being mapped over are stored in the destination,
279- # zero out the destination. An extreme example of this is when
280- # the sources are sparse but the destination is dense.
269+ indices = if ! preserves_unstored (f, a_dest, as... )
270+ eachindex (a_dest)
271+ elseif any (a -> a_dest != = a, as)
272+ as = map (a -> Base. unalias (a_dest, a), as)
281273 @interface interface zero! (a_dest)
274+ eachstoredindex (as... )
275+ else
276+ eachstoredindex (a_dest)
282277 end
283- @interface interface map_indices! (f, a_dest, indices_stored , as... )
278+ @interface interface map_indices! (indices, f, a_dest , as... )
284279 return a_dest
285280end
286281
0 commit comments