@@ -5,10 +5,12 @@ module Broadcast
55using Base. Cartesian
66using Base: promote_eltype_op, linearindices, tail, OneTo, to_shape,
77 _msk_end, unsafe_bitgetindex, bitcache_chunks, bitcache_size, dumpbitcache,
8- nullable_returntype, null_safe_eltype_op, hasvalue, is_nullable_array
8+ nullable_returntype, null_safe_eltype_op, hasvalue
99import Base: broadcast, broadcast!
1010export broadcast_getindex, broadcast_setindex!, dotview
1111
12+ typealias ScalarType Union{Type{Any}, Type{Nullable}}
13+
1214# # Broadcasting utilities ##
1315# fallbacks for some special cases
1416@inline broadcast (f, x:: Number... ) = f (x... )
@@ -28,37 +30,28 @@ containertype(::Type) = Any
2830containertype {T<:Ptr} (:: Type{T} ) = Any
2931containertype {T<:Tuple} (:: Type{T} ) = Tuple
3032containertype {T<:Ref} (:: Type{T} ) = Array
31- containertype {T<:AbstractArray} (:: Type{T} ) =
32- is_nullable_array (T) ? Array{Nullable} : Array
33+ containertype {T<:AbstractArray} (:: Type{T} ) = Array
3334containertype {T<:Nullable} (:: Type{T} ) = Nullable
3435containertype (ct1, ct2) = promote_containertype (containertype (ct1), containertype (ct2))
3536@inline containertype (ct1, ct2, cts... ) = promote_containertype (containertype (ct1), containertype (ct2, cts... ))
3637
3738promote_containertype (:: Type{Array} , :: Type{Array} ) = Array
3839promote_containertype (:: Type{Array} , ct) = Array
3940promote_containertype (ct, :: Type{Array} ) = Array
40- promote_containertype (:: Type{Tuple} , :: Type{Any} ) = Tuple
41- promote_containertype (:: Type{Any} , :: Type{Tuple} ) = Tuple
41+ promote_containertype (:: Type{Tuple} , :: ScalarType ) = Tuple
42+ promote_containertype (:: ScalarType , :: Type{Tuple} ) = Tuple
4243promote_containertype (:: Type{Any} , :: Type{Nullable} ) = Nullable
4344promote_containertype (:: Type{Nullable} , :: Type{Any} ) = Nullable
44- promote_containertype (:: Type{Nullable} , :: Type{Array} ) = Array{Nullable}
45- promote_containertype (:: Type{Array} , :: Type{Nullable} ) = Array{Nullable}
46- promote_containertype (:: Type{Array{Nullable}} , :: Type{Array{Nullable}} ) =
47- Array{Nullable}
48- promote_containertype (:: Type{Array{Nullable}} , :: Type{Array} ) = Array{Nullable}
49- promote_containertype (:: Type{Array} , :: Type{Array{Nullable}} ) = Array{Nullable}
50- promote_containertype (:: Type{Array{Nullable}} , ct) = Array{Nullable}
51- promote_containertype (ct, :: Type{Array{Nullable}} ) = Array{Nullable}
5245promote_containertype {T} (:: Type{T} , :: Type{T} ) = T
5346
5447# # Calculate the broadcast indices of the arguments, or error if incompatible
5548# array inputs
5649broadcast_indices () = ()
5750broadcast_indices (A) = broadcast_indices (containertype (A), A)
58- broadcast_indices (:: Union{Type{Any}, Type{Nullable}} , A) = ()
51+ broadcast_indices (:: ScalarType , A) = ()
5952broadcast_indices (:: Type{Tuple} , A) = (OneTo (length (A)),)
6053broadcast_indices (:: Type{Array} , A:: Ref ) = ()
61- broadcast_indices {T<:Array} (:: Type{T } , A) = indices (A)
54+ broadcast_indices (:: Type{Array } , A) = indices (A)
6255@inline broadcast_indices (A, B... ) = broadcast_shape ((), broadcast_indices (A), map (broadcast_indices, B)... )
6356# shape (i.e., tuple-of-indices) inputs
6457broadcast_shape (shape:: Tuple ) = shape
132125
133126Base. @propagate_inbounds _broadcast_getindex (A, I) = _broadcast_getindex (containertype (A), A, I)
134127Base. @propagate_inbounds _broadcast_getindex (:: Type{Array} , A:: Ref , I) = A[]
135- Base. @propagate_inbounds _broadcast_getindex (:: Type{Any} , A, I) = A
136- Base. @propagate_inbounds _broadcast_getindex (:: Union {Type{Any},
137- Type{Nullable}}, A, I) = A
128+ Base. @propagate_inbounds _broadcast_getindex (:: ScalarType , A, I) = A
138129Base. @propagate_inbounds _broadcast_getindex (:: Any , A, I) = A[I]
139130
140131# # Broadcasting core
@@ -285,28 +276,20 @@ ftype(f, A) = typeof(f)
285276ftype (f, A... ) = typeof (a -> f (a... ))
286277ftype (T:: Type , A... ) = Type{T}
287278
288- # nullables need to be treated like scalars sometimes and like containers
289- # other times, so there are two variants of typestuple.
290-
291- # if the first argument is Any, then Nullable should be treated like a
292- # scalar; if the first argument is Array, then Nullable should be treated
293- # like a container.
294- typestuple (:: Type , a) = (Base. @_pure_meta ; Tuple{eltype (a)})
295- typestuple (:: Type{Any} , a:: Nullable ) = (Base. @_pure_meta ; Tuple{typeof (a)})
296- typestuple (:: Type , T:: Type ) = (Base. @_pure_meta ; Tuple{Type{T}})
297- typestuple {T} (:: Type{T} , a, b... ) = (Base. @_pure_meta ; Tuple{typestuple (T, a). types... , typestuple (T, b... ). types... })
279+ typestuple (a) = (Base. @_pure_meta ; Tuple{eltype (a)})
280+ typestuple (T:: Type ) = (Base. @_pure_meta ; Tuple{Type{T}})
281+ typestuple (a, b... ) = (Base. @_pure_meta ; Tuple{typestuple (a). types... , typestuple (b... ). types... })
298282
299- # these functions take the variant of typestuple to be used as first argument
300- ziptype {T} (:: Type{T} , A) = typestuple (T, A)
301- ziptype {T} (:: Type{T} , A, B) = (Base. @_pure_meta ; Iterators. Zip2{typestuple (T, A), typestuple (T, B)})
302- @inline ziptype {T} (:: Type{T} , A, B, C, D... ) = Iterators. Zip{typestuple (T, A), ziptype (T, B, C, D... )}
283+ ziptype (A) = typestuple (A)
284+ ziptype (A, B) = (Base. @_pure_meta ; Iterators. Zip2{typestuple (A), typestuple (B)})
285+ @inline ziptype (A, B, C, D... ) = Iterators. Zip{typestuple (A), ziptype (B, C, D... )}
303286
304- _broadcast_type {S} ( :: Type{S} , f, T:: Type , As... ) = Base. _return_type (f, typestuple (S, T, As... ))
305- _broadcast_type {T} ( :: Type{T} , f, A, Bs... ) = Base. _default_eltype (Base. Generator{ziptype (T, A, Bs... ), ftype (f, A, Bs... )})
287+ _broadcast_type ( f, T:: Type , As... ) = Base. _return_type (f, typestuple (T, As... ))
288+ _broadcast_type ( f, A, Bs... ) = Base. _default_eltype (Base. Generator{ziptype (A, Bs... ), ftype (f, A, Bs... )})
306289
307290# broadcast methods that dispatch on the type of the final container
308291@inline function broadcast_c (f, :: Type{Array} , A, Bs... )
309- T = _broadcast_type (Any, f, A, Bs... )
292+ T = _broadcast_type (f, A, Bs... )
310293 shape = broadcast_indices (A, Bs... )
311294 iter = CartesianRange (shape)
312295 if isleaftype (T)
@@ -317,21 +300,14 @@ _broadcast_type{T}(::Type{T}, f, A, Bs...) = Base._default_eltype(Base.Generator
317300 end
318301 return broadcast_t (f, Any, shape, iter, A, Bs... )
319302end
320- @inline function broadcast_c (f, :: Type{Array{Nullable}} , A, Bs... )
321- @inline rec (x) = broadcast (f, x)
322- @inline rec (x, y) = broadcast (f, x, y)
323- @inline rec (x, y, z) = broadcast (f, x, y, z)
324- @inline rec (xs... ) = broadcast (f, xs... )
325- broadcast_c (rec, Array, A, Bs... )
326- end
327303function broadcast_c (f, :: Type{Tuple} , As... )
328304 shape = broadcast_indices (As... )
329305 n = length (shape[1 ])
330306 return ntuple (k-> f ((_broadcast_getindex (A, k) for A in As). .. ), n)
331307end
332308@inline function broadcast_c (f, :: Type{Nullable} , a... )
333309 nonnull = all (hasvalue, a)
334- S = _broadcast_type (Array, f, a... )
310+ S = _broadcast_type (f, a... )
335311 if isleaftype (S) && null_safe_eltype_op (f, a... )
336312 Nullable {S} (f (map (unsafe_get, a)... ), nonnull)
337313 else
@@ -347,28 +323,21 @@ end
347323"""
348324 broadcast(f, As...)
349325
350- Broadcasts the arrays, tuples, `Ref`, nullables, and/or scalars `As` to a
326+ Broadcasts the arrays, tuples, `Ref`s , nullables, and/or scalars `As` to a
351327container of the appropriate type and dimensions. In this context, anything
352- that is not a subtype of `AbstractArray`, `Ref` (except for `Ptr`s) or `Tuple`,
328+ that is not a subtype of `AbstractArray`, `Ref` (except for `Ptr`s), `Tuple`,
353329or `Nullable` is considered a scalar. The resulting container is established by
354330the following rules:
355331
356332 - If all the arguments are scalars, it returns a scalar.
357333 - If the arguments are tuples and zero or more scalars, it returns a tuple.
358- - If there is at least an array or a `Ref` in the arguments , it returns an array
359- (and treats any `Ref` as a 0-dimensional array of its contents and any tuple
360- as a 1-dimensional array) expanding singleton dimensions .
334+ - If the arguments contain at least one array or `Ref`, it returns an array
335+ (expanding singleton dimensions), and treats `Ref`s as 0-dimensional arrays,
336+ and tuples as a 1-dimensional arrays .
361337
362- The following additional rules apply to `Nullable` arguments:
363-
364- - If there is at least a `Nullable`, and all the arguments are scalars or
365- `Nullable`, it returns a `Nullable`.
366- - If there is at least an array or a `Ref` with `Nullable` entries, or there
367- is at least an array or a `Ref` (perhaps with scalar entries instead of
368- `Nullable` entries) and a nullable, then the result is an array of
369- `Nullable` entries.
370- - If there is a tuple and a nullable, the result is an error, as this case is
371- not currently supported.
338+ The following additional rule applies to `Nullable` arguments: If there is at
339+ least one `Nullable`, and all the arguments are scalars or `Nullable`, it
340+ returns a `Nullable` treating `Nullable`s as "containers".
372341
373342A special syntax exists for broadcasting: `f.(args...)` is equivalent to
374343`broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
@@ -433,21 +402,8 @@ Nullable{String}("XY")
433402julia> broadcast(/, 1.0, Nullable(2.0))
434403Nullable{Float64}(0.5)
435404
436- julia> [Nullable(1), Nullable(2), Nullable()] .* 3
437- 3-element Array{Nullable{Int64},1}:
438- 3
439- 6
440- #NULL
441-
442- julia> [1+im, 2+2im, 3+3im] ./ Nullable{Int}()
443- 3-element Array{Nullable{Complex{Float64}},1}:
444- #NULL
445- #NULL
446- #NULL
447-
448- julia> Ref(7) .+ Nullable(3)
449- 0-dimensional Array{Nullable{Int64},0}:
450- 10
405+ julia> (1 + im) ./ Nullable{Int}()
406+ Nullable{Complex{Float64}}()
451407```
452408"""
453409@inline broadcast (f, A, Bs... ) = broadcast_c (f, containertype (A, Bs... ), A, Bs... )
0 commit comments