@@ -10,6 +10,8 @@ import Base: broadcast, broadcast!
1010export bitbroadcast, dotview
1111export broadcast_getindex, broadcast_setindex!
1212
13+ typealias ScalarType Union{Type{Any}, Type{Nullable}}
14+
1315# # Broadcasting utilities ##
1416# fallbacks for some special cases
1517@inline broadcast (f, x:: Number... ) = f (x... )
@@ -29,37 +31,28 @@ containertype(::Type) = Any
2931containertype {T<:Ptr} (:: Type{T} ) = Any
3032containertype {T<:Tuple} (:: Type{T} ) = Tuple
3133containertype {T<:Ref} (:: Type{T} ) = Array
32- containertype {T<:AbstractArray} (:: Type{T} ) =
33- is_nullable_array (T) ? Array{Nullable} : Array
34+ containertype {T<:AbstractArray} (:: Type{T} ) = Array
3435containertype {T<:Nullable} (:: Type{T} ) = Nullable
3536containertype (ct1, ct2) = promote_containertype (containertype (ct1), containertype (ct2))
3637@inline containertype (ct1, ct2, cts... ) = promote_containertype (containertype (ct1), containertype (ct2, cts... ))
3738
3839promote_containertype (:: Type{Array} , :: Type{Array} ) = Array
3940promote_containertype (:: Type{Array} , ct) = Array
4041promote_containertype (ct, :: Type{Array} ) = Array
41- promote_containertype (:: Type{Tuple} , :: Type{Any} ) = Tuple
42- promote_containertype (:: Type{Any} , :: Type{Tuple} ) = Tuple
42+ promote_containertype (:: Type{Tuple} , :: ScalarType ) = Tuple
43+ promote_containertype (:: ScalarType , :: Type{Tuple} ) = Tuple
4344promote_containertype (:: Type{Any} , :: Type{Nullable} ) = Nullable
4445promote_containertype (:: Type{Nullable} , :: Type{Any} ) = Nullable
45- promote_containertype (:: Type{Nullable} , :: Type{Array} ) = Array{Nullable}
46- promote_containertype (:: Type{Array} , :: Type{Nullable} ) = Array{Nullable}
47- promote_containertype (:: Type{Array{Nullable}} , :: Type{Array{Nullable}} ) =
48- Array{Nullable}
49- promote_containertype (:: Type{Array{Nullable}} , :: Type{Array} ) = Array{Nullable}
50- promote_containertype (:: Type{Array} , :: Type{Array{Nullable}} ) = Array{Nullable}
51- promote_containertype (:: Type{Array{Nullable}} , ct) = Array{Nullable}
52- promote_containertype (ct, :: Type{Array{Nullable}} ) = Array{Nullable}
5346promote_containertype {T} (:: Type{T} , :: Type{T} ) = T
5447
5548# # Calculate the broadcast indices of the arguments, or error if incompatible
5649# array inputs
5750broadcast_indices () = ()
5851broadcast_indices (A) = broadcast_indices (containertype (A), A)
59- broadcast_indices (:: Union{Type{Any}, Type{Nullable}} , A) = ()
52+ broadcast_indices (:: ScalarType , A) = ()
6053broadcast_indices (:: Type{Tuple} , A) = (OneTo (length (A)),)
6154broadcast_indices (:: Type{Array} , A:: Ref ) = ()
62- broadcast_indices {T<:Array} (:: Type{T } , A) = indices (A)
55+ broadcast_indices (:: Type{Array } , A) = indices (A)
6356@inline broadcast_indices (A, B... ) = broadcast_shape ((), broadcast_indices (A), map (broadcast_indices, B)... )
6457# shape (i.e., tuple-of-indices) inputs
6558broadcast_shape (shape:: Tuple ) = shape
133126
134127Base. @propagate_inbounds _broadcast_getindex (A, I) = _broadcast_getindex (containertype (A), A, I)
135128Base. @propagate_inbounds _broadcast_getindex (:: Type{Array} , A:: Ref , I) = A[]
136- Base. @propagate_inbounds _broadcast_getindex (:: Type{Any} , A, I) = A
137- Base. @propagate_inbounds _broadcast_getindex (:: Union {Type{Any},
138- Type{Nullable}}, A, I) = A
129+ Base. @propagate_inbounds _broadcast_getindex (:: ScalarType , A, I) = A
139130Base. @propagate_inbounds _broadcast_getindex (:: Any , A, I) = A[I]
140131
141132# # Broadcasting core
@@ -292,22 +283,21 @@ ftype(T::Type, A...) = Type{T}
292283# if the first argument is Any, then Nullable should be treated like a
293284# scalar; if the first argument is Array, then Nullable should be treated
294285# like a container.
295- typestuple (:: Type , a) = (Base. @_pure_meta ; Tuple{eltype (a)})
296- typestuple (:: Type{Any} , a:: Nullable ) = (Base. @_pure_meta ; Tuple{typeof (a)})
297- typestuple (:: Type , T:: Type ) = (Base. @_pure_meta ; Tuple{Type{T}})
298- typestuple {T} (:: Type{T} , a, b... ) = (Base. @_pure_meta ; Tuple{typestuple (T, a). types... , typestuple (T, b... ). types... })
286+ typestuple (a) = (Base. @_pure_meta ; Tuple{eltype (a)})
287+ typestuple (T:: Type ) = (Base. @_pure_meta ; Tuple{Type{T}})
288+ typestuple (a, b... ) = (Base. @_pure_meta ; Tuple{typestuple (a). types... , typestuple (b... ). types... })
299289
300290# these functions take the variant of typestuple to be used as first argument
301- ziptype {T} ( :: Type{T} , A) = typestuple (T, A)
302- ziptype {T} ( :: Type{T} , A, B) = (Base. @_pure_meta ; Iterators. Zip2{typestuple (T, A), typestuple (T, B)})
303- @inline ziptype {T} ( :: Type{T} , A, B, C, D... ) = Iterators. Zip{typestuple (T, A), ziptype (T, B, C, D... )}
291+ ziptype ( A) = typestuple (A)
292+ ziptype ( A, B) = (Base. @_pure_meta ; Iterators. Zip2{typestuple (A), typestuple (B)})
293+ @inline ziptype ( A, B, C, D... ) = Iterators. Zip{typestuple (A), ziptype (B, C, D... )}
304294
305- _broadcast_type {S} ( :: Type{S} , f, T:: Type , As... ) = Base. _return_type (f, typestuple (S, T, As... ))
306- _broadcast_type {T} ( :: Type{T} , f, A, Bs... ) = Base. _default_eltype (Base. Generator{ziptype (T, A, Bs... ), ftype (f, A, Bs... )})
295+ _broadcast_type ( f, T:: Type , As... ) = Base. _return_type (f, typestuple (T, As... ))
296+ _broadcast_type ( f, A, Bs... ) = Base. _default_eltype (Base. Generator{ziptype (A, Bs... ), ftype (f, A, Bs... )})
307297
308298# broadcast methods that dispatch on the type of the final container
309299@inline function broadcast_c (f, :: Type{Array} , A, Bs... )
310- T = _broadcast_type (Any, f, A, Bs... )
300+ T = _broadcast_type (f, A, Bs... )
311301 shape = broadcast_indices (A, Bs... )
312302 iter = CartesianRange (shape)
313303 if isleaftype (T)
@@ -318,21 +308,14 @@ _broadcast_type{T}(::Type{T}, f, A, Bs...) = Base._default_eltype(Base.Generator
318308 end
319309 return broadcast_t (f, Any, shape, iter, A, Bs... )
320310end
321- @inline function broadcast_c (f, :: Type{Array{Nullable}} , A, Bs... )
322- @inline rec (x) = broadcast (f, x)
323- @inline rec (x, y) = broadcast (f, x, y)
324- @inline rec (x, y, z) = broadcast (f, x, y, z)
325- @inline rec (xs... ) = broadcast (f, xs... )
326- broadcast_c (rec, Array, A, Bs... )
327- end
328311function broadcast_c (f, :: Type{Tuple} , As... )
329312 shape = broadcast_indices (As... )
330313 n = length (shape[1 ])
331314 return ntuple (k-> f ((_broadcast_getindex (A, k) for A in As). .. ), n)
332315end
333316@inline function broadcast_c (f, :: Type{Nullable} , a... )
334317 nonnull = all (hasvalue, a)
335- S = _broadcast_type (Array, f, a... )
318+ S = _broadcast_type (f, a... )
336319 if isleaftype (S) && null_safe_eltype_op (f, a... )
337320 Nullable {S} (f (map (unsafe_get, a)... ), nonnull)
338321 else
350333
351334Broadcasts the arrays, tuples, `Ref`, nullables, and/or scalars `As` to a
352335container of the appropriate type and dimensions. In this context, anything
353- that is not a subtype of `AbstractArray`, `Ref` (except for `Ptr`s) or `Tuple`,
354- or `Nullable` is considered a scalar. The resulting container is established by
336+ that is not a subtype of `AbstractArray`, `Ref` (except for `Ptr`s) or `Tuple`
337+ is considered a scalar. The resulting container is established by
355338the following rules:
356339
357340 - If all the arguments are scalars, it returns a scalar.
@@ -360,16 +343,10 @@ the following rules:
360343 (and treats any `Ref` as a 0-dimensional array of its contents and any tuple
361344 as a 1-dimensional array) expanding singleton dimensions.
362345
363- The following additional rules apply to `Nullable` arguments:
346+ The following additional rule apply to `Nullable` arguments:
364347
365348 - If there is at least a `Nullable`, and all the arguments are scalars or
366- `Nullable`, it returns a `Nullable`.
367- - If there is at least an array or a `Ref` with `Nullable` entries, or there
368- is at least an array or a `Ref` (perhaps with scalar entries instead of
369- `Nullable` entries) and a nullable, then the result is an array of
370- `Nullable` entries.
371- - If there is a tuple and a nullable, the result is an error, as this case is
372- not currently supported.
349+ `Nullable`, it returns a `Nullable` treating `Nullable`s as "containers".
373350
374351A special syntax exists for broadcasting: `f.(args...)` is equivalent to
375352`broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
@@ -434,21 +411,8 @@ Nullable{String}("XY")
434411julia> broadcast(/, 1.0, Nullable(2.0))
435412Nullable{Float64}(0.5)
436413
437- julia> [Nullable(1), Nullable(2), Nullable()] .* 3
438- 3-element Array{Nullable{Int64},1}:
439- 3
440- 6
441- #NULL
442-
443- julia> [1+im, 2+2im, 3+3im] ./ Nullable{Int}()
444- 3-element Array{Nullable{Complex{Float64}},1}:
445- #NULL
446- #NULL
447- #NULL
448-
449- julia> Ref(7) .+ Nullable(3)
450- 0-dimensional Array{Nullable{Int64},0}:
451- 10
414+ julia> (1 + im) ./ Nullable{Int}()
415+ Nullable{Complex{Float64}}()
452416```
453417"""
454418@inline broadcast (f, A, Bs... ) = broadcast_c (f, containertype (A, Bs... ), A, Bs... )
0 commit comments