Skip to content

Commit ab984a5

Browse files
andreasnoacktkelman
authored andcommitted
Use containertype to determine array type for array broadcast (#19745)
1 parent 7ba6ad6 commit ab984a5

File tree

2 files changed

+35
-13
lines changed

2 files changed

+35
-13
lines changed

base/broadcast.jl

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,9 @@ export bitbroadcast, dotview
1111
export broadcast_getindex, broadcast_setindex!
1212

1313
## Broadcasting utilities ##
14-
15-
broadcast_array_type() = Array
16-
broadcast_array_type(A, As...) =
17-
if is_nullable_array(A) || broadcast_array_type(As...) === Array{Nullable}
18-
Array{Nullable}
19-
else
20-
Array
21-
end
22-
2314
# fallbacks for some special cases
2415
@inline broadcast(f, x::Number...) = f(x...)
2516
@inline broadcast{N}(f, t::NTuple{N}, ts::Vararg{NTuple{N}}) = map(f, t, ts...)
26-
@inline broadcast(f, As::AbstractArray...) =
27-
broadcast_c(f, broadcast_array_type(As...), As...)
2817

2918
# special cases for "X .= ..." (broadcast!) assignments
3019
broadcast!(::typeof(identity), X::AbstractArray, x::Number) = fill!(X, x)
@@ -313,7 +302,7 @@ ziptype{T}(::Type{T}, A) = typestuple(T, A)
313302
ziptype{T}(::Type{T}, A, B) = (Base.@_pure_meta; Iterators.Zip2{typestuple(T, A), typestuple(T, B)})
314303
@inline ziptype{T}(::Type{T}, A, B, C, D...) = Iterators.Zip{typestuple(T, A), ziptype(T, B, C, D...)}
315304

316-
_broadcast_type{S}(::Type{S}, f, T::Type, As...) = Base._return_type(S, typestuple(S, T, As...))
305+
_broadcast_type{S}(::Type{S}, f, T::Type, As...) = Base._return_type(f, typestuple(S, T, As...))
317306
_broadcast_type{T}(::Type{T}, f, A, Bs...) = Base._default_eltype(Base.Generator{ziptype(T, A, Bs...), ftype(f, A, Bs...)})
318307

319308
# broadcast methods that dispatch on the type of the final container

test/broadcast.jl

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ StrangeType18623(x,y) = (x,y)
363363
let
364364
f(A, n) = broadcast(x -> +(x, n), A)
365365
@test @inferred(f([1.0], 1)) == [2.0]
366-
g() = (a = 1; Base.Broadcast._broadcast_type(x -> x + a, 1.0))
366+
g() = (a = 1; Base.Broadcast._broadcast_type(Any, x -> x + a, 1.0))
367367
@test @inferred(g()) === Float64
368368
end
369369

@@ -376,3 +376,36 @@ end
376376

377377
# Check that broadcast!(f, A) populates A via independent calls to f (#12277, #19722).
378378
@test let z = 1; A = broadcast!(() -> z += 1, zeros(2)); A[1] != A[2]; end
379+
380+
# broadcasting for custom AbstractArray
381+
immutable Array19745{T,N} <: AbstractArray{T,N}
382+
data::Array{T,N}
383+
end
384+
Base.getindex(A::Array19745, i::Integer...) = A.data[i...]
385+
Base.size(A::Array19745) = size(A.data)
386+
387+
Base.Broadcast.containertype{T<:Array19745}(::Type{T}) = Array19745
388+
389+
Base.Broadcast.promote_containertype(::Type{Array19745}, ::Type{Array19745}) = Array19745
390+
Base.Broadcast.promote_containertype(::Type{Array19745}, ::Type{Array}) = Array19745
391+
Base.Broadcast.promote_containertype(::Type{Array19745}, ct) = Array19745
392+
Base.Broadcast.promote_containertype(::Type{Array}, ::Type{Array19745}) = Array19745
393+
Base.Broadcast.promote_containertype(ct, ::Type{Array19745}) = Array19745
394+
395+
Base.Broadcast.broadcast_indices(::Type{Array19745}, A) = indices(A)
396+
Base.Broadcast.broadcast_indices(::Type{Array19745}, A::Ref) = ()
397+
398+
getfield19745(x::Array19745) = x.data
399+
getfield19745(x) = x
400+
401+
Base.Broadcast.broadcast_c(f, ::Type{Array19745}, A, Bs...) =
402+
Array19745(Base.Broadcast.broadcast_c(f, Array, getfield19745(A), map(getfield19745, Bs)...))
403+
404+
@testset "broadcasting for custom AbstractArray" begin
405+
a = randn(10)
406+
aa = Array19745(a)
407+
@test a .+ 1 == @inferred(aa .+ 1)
408+
@test a .* a' == @inferred(aa .* aa')
409+
@test isa(aa .+ 1, Array19745)
410+
@test isa(aa .* aa', Array19745)
411+
end

0 commit comments

Comments
 (0)