Skip to content

Commit e474dd4

Browse files
authored
Merge pull request #17568 from stevengj/dotview
improve a[...] .= handling of arrays of arrays and dicts of arrays
2 parents 557e483 + 0eb3e3b commit e474dd4

File tree

4 files changed

+33
-3
lines changed

4 files changed

+33
-3
lines changed

base/broadcast.jl

+21-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module Broadcast
55
using Base.Cartesian
66
using Base: promote_op, promote_eltype, promote_eltype_op, @get!, _msk_end, unsafe_bitgetindex, linearindices, tail, OneTo, to_shape
77
import Base: .+, .-, .*, ./, .\, .//, .==, .<, .!=, .<=, , .%, .<<, .>>, .^
8-
export broadcast, broadcast!, bitbroadcast
8+
export broadcast, broadcast!, bitbroadcast, dotview
99
export broadcast_getindex, broadcast_setindex!
1010

1111
## Broadcasting utilities ##
@@ -437,4 +437,24 @@ for (sigA, sigB) in ((BitArray, BitArray),
437437
end
438438
end
439439

440+
############################################################
441+
442+
# x[...] .= f.(y...) ---> broadcast!(f, dotview(x, ...), y...).
443+
# The dotview function defaults to getindex, but we override it in
444+
# a few cases to get the expected in-place behavior without affecting
445+
# explicit calls to view. (All of this can go away if slices
446+
# are changed to generate views by default.)
447+
448+
dotview(args...) = getindex(args...)
449+
dotview(A::AbstractArray, args...) = view(A, args...)
450+
dotview{T<:AbstractArray}(A::AbstractArray{T}, args...) = getindex(A, args...)
451+
# avoid splatting penalty in common cases:
452+
for nargs = 0:5
453+
args = Symbol[Symbol("x",i) for i = 1:nargs]
454+
eval(Expr(:(=), Expr(:call, :dotview, args...),
455+
Expr(:call, :getindex, args...)))
456+
eval(Expr(:(=), Expr(:call, :dotview, :(A::AbstractArray), args...),
457+
Expr(:call, :view, :A, args...)))
458+
end
459+
440460
end # module

doc/manual/functions.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ calls do not allocate new arrays over and over again for the results
660660
except that, as above, the ``broadcast!`` loop is fused with any nested
661661
"dot" calls. For example, ``X .= sin.(Y)`` is equivalent to
662662
``broadcast!(sin, X, Y)``, overwriting ``X`` with ``sin.(Y)`` in-place.
663-
If the left-hand side is a ``getindex`` expression, e.g.
663+
If the left-hand side is an array-indexing expression, e.g.
664664
``X[2:end] .= sin.(Y)``, then it translates to ``broadcast!`` on a ``view``,
665665
e.g. ``broadcast!(sin, view(X, 2:endof(X)), Y)``, so that the left-hand
666666
side is updated in-place.

src/julia-syntax.scm

+1-1
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@
15591559
(let* ((ex (partially-expand-ref expr))
15601560
(stmts (butlast (cdr ex)))
15611561
(refex (last (cdr ex)))
1562-
(nuref `(call (top view) ,(caddr refex) ,@(cdddr refex))))
1562+
(nuref `(call (top dotview) ,(caddr refex) ,@(cdddr refex))))
15631563
`(block ,@stmts ,nuref))
15641564
expr))
15651565

test/broadcast.jl

+10
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,16 @@ let x = [1:4;], y = x
274274
x[2:end] .= 1:3
275275
@test y === x == [0,1,2,3]
276276
end
277+
let a = [[4, 5], [6, 7]]
278+
a[1] .= 3
279+
@test a == [[3, 3], [6, 7]]
280+
end
281+
let d = Dict(:foo => [1,3,7], (3,4) => [5,9])
282+
d[:foo] .+= 2
283+
@test d[:foo] == [3,5,9]
284+
d[3,4] .-= 1
285+
@test d[3,4] == [4,8]
286+
end
277287

278288
# PR 16988
279289
@test Base.promote_op(+, Bool) === Int

0 commit comments

Comments
 (0)