207
207
function map_indices! end
208
208
209
209
@interface interface:: AbstractArrayInterface function map_indices! (
210
- f, a_dest:: AbstractArray , indices , as:: AbstractArray...
210
+ indices, f, a_dest:: AbstractArray , as:: AbstractArray...
211
211
)
212
212
for I in indices
213
213
a_dest[I] = f (map (a -> a[I], as)... )
@@ -221,7 +221,7 @@ function map_stored! end
221
221
@interface interface:: AbstractArrayInterface function map_stored! (
222
222
f, a_dest:: AbstractArray , as:: AbstractArray...
223
223
)
224
- @interface interface map_indices! (f, a_dest, eachstoredindex (as... ), as... )
224
+ @interface interface map_indices! (eachstoredindex (as... ), f, a_dest , as... )
225
225
return a_dest
226
226
end
227
227
@@ -231,7 +231,7 @@ function map_all! end
231
231
@interface interface:: AbstractArrayInterface function map_all! (
232
232
f, a_dest:: AbstractArray , as:: AbstractArray...
233
233
)
234
- @interface interface map_indices! (f, a_dest, eachindex (as... ), as... )
234
+ @interface interface map_indices! (eachindex (as... ), f, a_dest , as... )
235
235
return a_dest
236
236
end
237
237
@@ -250,37 +250,32 @@ using ArrayLayouts: ArrayLayouts, zero!
250
250
return @interface interface map_stored! (f, a, a)
251
251
end
252
252
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
+
253
266
@interface interface:: AbstractSparseArrayInterface function Base. map! (
254
267
f, a_dest:: AbstractArray , as:: AbstractArray...
255
268
)
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)
281
273
@interface interface zero! (a_dest)
274
+ eachstoredindex (as... )
275
+ else
276
+ eachstoredindex (a_dest)
282
277
end
283
- @interface interface map_indices! (f, a_dest, indices_stored , as... )
278
+ @interface interface map_indices! (indices, f, a_dest , as... )
284
279
return a_dest
285
280
end
286
281
0 commit comments