@@ -10,6 +10,8 @@ import Base: broadcast, broadcast!
10
10
export bitbroadcast, dotview
11
11
export broadcast_getindex, broadcast_setindex!
12
12
13
+ typealias ScalarType Union{Type{Any}, Type{Nullable}}
14
+
13
15
# # Broadcasting utilities ##
14
16
# fallbacks for some special cases
15
17
@inline broadcast (f, x:: Number... ) = f (x... )
@@ -29,37 +31,28 @@ containertype(::Type) = Any
29
31
containertype {T<:Ptr} (:: Type{T} ) = Any
30
32
containertype {T<:Tuple} (:: Type{T} ) = Tuple
31
33
containertype {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
34
35
containertype {T<:Nullable} (:: Type{T} ) = Nullable
35
36
containertype (ct1, ct2) = promote_containertype (containertype (ct1), containertype (ct2))
36
37
@inline containertype (ct1, ct2, cts... ) = promote_containertype (containertype (ct1), containertype (ct2, cts... ))
37
38
38
39
promote_containertype (:: Type{Array} , :: Type{Array} ) = Array
39
40
promote_containertype (:: Type{Array} , ct) = Array
40
41
promote_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
43
44
promote_containertype (:: Type{Any} , :: Type{Nullable} ) = Nullable
44
45
promote_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}
53
46
promote_containertype {T} (:: Type{T} , :: Type{T} ) = T
54
47
55
48
# # Calculate the broadcast indices of the arguments, or error if incompatible
56
49
# array inputs
57
50
broadcast_indices () = ()
58
51
broadcast_indices (A) = broadcast_indices (containertype (A), A)
59
- broadcast_indices (:: Union{Type{Any}, Type{Nullable}} , A) = ()
52
+ broadcast_indices (:: ScalarType , A) = ()
60
53
broadcast_indices (:: Type{Tuple} , A) = (OneTo (length (A)),)
61
54
broadcast_indices (:: Type{Array} , A:: Ref ) = ()
62
- broadcast_indices {T<:Array} (:: Type{T } , A) = indices (A)
55
+ broadcast_indices (:: Type{Array } , A) = indices (A)
63
56
@inline broadcast_indices (A, B... ) = broadcast_shape ((), broadcast_indices (A), map (broadcast_indices, B)... )
64
57
# shape (i.e., tuple-of-indices) inputs
65
58
broadcast_shape (shape:: Tuple ) = shape
133
126
134
127
Base. @propagate_inbounds _broadcast_getindex (A, I) = _broadcast_getindex (containertype (A), A, I)
135
128
Base. @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
139
130
Base. @propagate_inbounds _broadcast_getindex (:: Any , A, I) = A[I]
140
131
141
132
# # Broadcasting core
@@ -292,22 +283,21 @@ ftype(T::Type, A...) = Type{T}
292
283
# if the first argument is Any, then Nullable should be treated like a
293
284
# scalar; if the first argument is Array, then Nullable should be treated
294
285
# 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... })
299
289
300
290
# 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... )}
304
294
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... )})
307
297
308
298
# broadcast methods that dispatch on the type of the final container
309
299
@inline function broadcast_c (f, :: Type{Array} , A, Bs... )
310
- T = _broadcast_type (Any, f, A, Bs... )
300
+ T = _broadcast_type (f, A, Bs... )
311
301
shape = broadcast_indices (A, Bs... )
312
302
iter = CartesianRange (shape)
313
303
if isleaftype (T)
@@ -318,21 +308,14 @@ _broadcast_type{T}(::Type{T}, f, A, Bs...) = Base._default_eltype(Base.Generator
318
308
end
319
309
return broadcast_t (f, Any, shape, iter, A, Bs... )
320
310
end
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
328
311
function broadcast_c (f, :: Type{Tuple} , As... )
329
312
shape = broadcast_indices (As... )
330
313
n = length (shape[1 ])
331
314
return ntuple (k-> f ((_broadcast_getindex (A, k) for A in As). .. ), n)
332
315
end
333
316
@inline function broadcast_c (f, :: Type{Nullable} , a... )
334
317
nonnull = all (hasvalue, a)
335
- S = _broadcast_type (Array, f, a... )
318
+ S = _broadcast_type (f, a... )
336
319
if isleaftype (S) && null_safe_eltype_op (f, a... )
337
320
Nullable {S} (f (map (unsafe_get, a)... ), nonnull)
338
321
else
350
333
351
334
Broadcasts the arrays, tuples, `Ref`, nullables, and/or scalars `As` to a
352
335
container 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
355
338
the following rules:
356
339
357
340
- If all the arguments are scalars, it returns a scalar.
@@ -360,16 +343,10 @@ the following rules:
360
343
(and treats any `Ref` as a 0-dimensional array of its contents and any tuple
361
344
as a 1-dimensional array) expanding singleton dimensions.
362
345
363
- The following additional rules apply to `Nullable` arguments:
346
+ The following additional rule apply to `Nullable` arguments:
364
347
365
348
- 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".
373
350
374
351
A special syntax exists for broadcasting: `f.(args...)` is equivalent to
375
352
`broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
@@ -434,21 +411,8 @@ Nullable{String}("XY")
434
411
julia> broadcast(/, 1.0, Nullable(2.0))
435
412
Nullable{Float64}(0.5)
436
413
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}}()
452
416
```
453
417
"""
454
418
@inline broadcast (f, A, Bs... ) = broadcast_c (f, containertype (A, Bs... ), A, Bs... )
0 commit comments