From 7d120b92b18a6f8f2e9771d878ccb83d42c73fc5 Mon Sep 17 00:00:00 2001 From: pabloferz Date: Sat, 15 Oct 2016 14:28:10 -0500 Subject: [PATCH] Make Ref behave as a scalar wrapper for broadcast --- base/abstractarray.jl | 6 ++++++ base/broadcast.jl | 5 +++++ test/broadcast.jl | 6 ++++++ 3 files changed, 17 insertions(+) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index abd6772288d96d..576e58d9c071ed 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -1754,9 +1754,15 @@ end # These are needed because map(eltype, As) is not inferrable promote_eltype_op(::Any) = (@_pure_meta; Any) promote_eltype_op(op, A) = (@_pure_meta; promote_op(op, eltype(A))) +promote_eltype_op(op, A::Ref) = (@_pure_meta; promote_op(op, typeof(A))) +promote_eltype_op(op, A, B::Ref) = (@_pure_meta; promote_op(op, eltype(A), typeof(B))) +promote_eltype_op(op, A::Ref, B) = (@_pure_meta; promote_op(op, typeof(A), eltype(B))) +promote_eltype_op(op, A::Ref, B::Ref) = (@_pure_meta; promote_op(op, typeof(A), typeof(B))) promote_eltype_op{T}(op, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, T)) promote_eltype_op{T}(op, ::AbstractArray{T}, A) = (@_pure_meta; promote_op(op, T, eltype(A))) promote_eltype_op{T}(op, A, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, eltype(A), T)) +promote_eltype_op{T}(op, ::AbstractArray{T}, A::Ref) = (@_pure_meta; promote_op(op, T, typeof(A))) +promote_eltype_op{T}(op, A::Ref, ::AbstractArray{T}) = (@_pure_meta; promote_op(op, typeof(A), T)) promote_eltype_op{R,S}(op, ::AbstractArray{R}, ::AbstractArray{S}) = (@_pure_meta; promote_op(op, R, S)) promote_eltype_op(op, A, B) = (@_pure_meta; promote_op(op, eltype(A), eltype(B))) promote_eltype_op(op, A, B, C, D...) = (@_pure_meta; promote_eltype_op(op, promote_eltype_op(op, A, B), C, D...)) diff --git a/base/broadcast.jl b/base/broadcast.jl index 917a9be9f3a5a6..31cce7fed06eb7 100644 --- a/base/broadcast.jl +++ b/base/broadcast.jl @@ -9,6 +9,8 @@ import Base: broadcast export broadcast!, bitbroadcast, dotview export broadcast_getindex, broadcast_setindex! +typealias RefArrOrVal Union{Base.RefArray, Base.RefValue} + ## Broadcasting utilities ## # fallback for broadcasting with zero arguments and some special cases @@ -30,6 +32,7 @@ end containertype(x) = containertype(typeof(x)) containertype(::Type) = Any containertype{T<:Tuple}(::Type{T}) = Tuple +containertype{T<:RefArrOrVal}(::Type{T}) = Array containertype{T<:AbstractArray}(::Type{T}) = Array containertype(ct1, ct2) = promote_containertype(containertype(ct1), containertype(ct2)) @inline containertype(ct1, ct2, cts...) = promote_containertype(containertype(ct1), containertype(ct2, cts...)) @@ -48,6 +51,7 @@ broadcast_indices(A) = broadcast_indices(containertype(A), A) broadcast_indices(::Type{Any}, A) = () broadcast_indices(::Type{Tuple}, A) = (OneTo(length(A)),) broadcast_indices(::Type{Array}, A) = indices(A) +broadcast_indices(::Type{Array}, A::RefArrOrVal) = () @inline broadcast_indices(A, B...) = broadcast_shape((), broadcast_indices(A), map(broadcast_indices, B)...) # shape (i.e., tuple-of-indices) inputs broadcast_shape(shape::Tuple) = shape @@ -127,6 +131,7 @@ dumpbitcache(Bc::Vector{UInt64}, bind::Int, C::Vector{Bool}) = Base.copy_to_bitarray_chunks!(Bc, ((bind - 1) << 6) + 1, C, 1, min(bitcache_size, (length(Bc)-bind+1) << 6)) @inline _broadcast_getindex(A, I) = _broadcast_getindex(containertype(A), A, I) +@inline _broadcast_getindex(A::RefArrOrVal, I) = A.x @inline _broadcast_getindex(::Type{Any}, A, I) = A @inline _broadcast_getindex(::Any, A, I) = A[I] diff --git a/test/broadcast.jl b/test/broadcast.jl index 7dca2095bff7e2..963da1678d90db 100644 --- a/test/broadcast.jl +++ b/test/broadcast.jl @@ -337,3 +337,9 @@ end @test broadcast(+, 1.0, (0, -2.0)) == (1.0,-1.0) @test broadcast(+, 1.0, (0, -2.0), [1]) == [2.0, 0.0] @test broadcast(*, ["Hello"], ", ", ["World"], "!") == ["Hello, World!"] + +# Issue #18379 +@test (+).(1, Ref(2)) == fill(3) +@test (+).(Ref(1), Ref(2)) == fill(3) +@test (+).([[0,2], [1,3]], [1,-1]) == [[1,3], [0,2]] +@test (+).([[0,2], [1,3]], Ref([1,-1]))::Vector{Vector{Int}} == [[1,1], [2,2]]