@@ -5,10 +5,12 @@ module Broadcast
5
5
using Base. Cartesian
6
6
using Base: promote_eltype_op, linearindices, tail, OneTo, to_shape,
7
7
_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
9
9
import Base: broadcast, broadcast!
10
10
export broadcast_getindex, broadcast_setindex!, dotview
11
11
12
+ typealias ScalarType Union{Type{Any}, Type{Nullable}}
13
+
12
14
# # Broadcasting utilities ##
13
15
# fallbacks for some special cases
14
16
@inline broadcast (f, x:: Number... ) = f (x... )
@@ -28,37 +30,28 @@ containertype(::Type) = Any
28
30
containertype {T<:Ptr} (:: Type{T} ) = Any
29
31
containertype {T<:Tuple} (:: Type{T} ) = Tuple
30
32
containertype {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
33
34
containertype {T<:Nullable} (:: Type{T} ) = Nullable
34
35
containertype (ct1, ct2) = promote_containertype (containertype (ct1), containertype (ct2))
35
36
@inline containertype (ct1, ct2, cts... ) = promote_containertype (containertype (ct1), containertype (ct2, cts... ))
36
37
37
38
promote_containertype (:: Type{Array} , :: Type{Array} ) = Array
38
39
promote_containertype (:: Type{Array} , ct) = Array
39
40
promote_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
42
43
promote_containertype (:: Type{Any} , :: Type{Nullable} ) = Nullable
43
44
promote_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}
52
45
promote_containertype {T} (:: Type{T} , :: Type{T} ) = T
53
46
54
47
# # Calculate the broadcast indices of the arguments, or error if incompatible
55
48
# array inputs
56
49
broadcast_indices () = ()
57
50
broadcast_indices (A) = broadcast_indices (containertype (A), A)
58
- broadcast_indices (:: Union{Type{Any}, Type{Nullable}} , A) = ()
51
+ broadcast_indices (:: ScalarType , A) = ()
59
52
broadcast_indices (:: Type{Tuple} , A) = (OneTo (length (A)),)
60
53
broadcast_indices (:: Type{Array} , A:: Ref ) = ()
61
- broadcast_indices {T<:Array} (:: Type{T } , A) = indices (A)
54
+ broadcast_indices (:: Type{Array } , A) = indices (A)
62
55
@inline broadcast_indices (A, B... ) = broadcast_shape ((), broadcast_indices (A), map (broadcast_indices, B)... )
63
56
# shape (i.e., tuple-of-indices) inputs
64
57
broadcast_shape (shape:: Tuple ) = shape
132
125
133
126
Base. @propagate_inbounds _broadcast_getindex (A, I) = _broadcast_getindex (containertype (A), A, I)
134
127
Base. @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
138
129
Base. @propagate_inbounds _broadcast_getindex (:: Any , A, I) = A[I]
139
130
140
131
# # Broadcasting core
@@ -285,28 +276,20 @@ ftype(f, A) = typeof(f)
285
276
ftype (f, A... ) = typeof (a -> f (a... ))
286
277
ftype (T:: Type , A... ) = Type{T}
287
278
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... })
298
282
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... )}
303
286
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... )})
306
289
307
290
# broadcast methods that dispatch on the type of the final container
308
291
@inline function broadcast_c (f, :: Type{Array} , A, Bs... )
309
- T = _broadcast_type (Any, f, A, Bs... )
292
+ T = _broadcast_type (f, A, Bs... )
310
293
shape = broadcast_indices (A, Bs... )
311
294
iter = CartesianRange (shape)
312
295
if isleaftype (T)
@@ -317,21 +300,14 @@ _broadcast_type{T}(::Type{T}, f, A, Bs...) = Base._default_eltype(Base.Generator
317
300
end
318
301
return broadcast_t (f, Any, shape, iter, A, Bs... )
319
302
end
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
327
303
function broadcast_c (f, :: Type{Tuple} , As... )
328
304
shape = broadcast_indices (As... )
329
305
n = length (shape[1 ])
330
306
return ntuple (k-> f ((_broadcast_getindex (A, k) for A in As). .. ), n)
331
307
end
332
308
@inline function broadcast_c (f, :: Type{Nullable} , a... )
333
309
nonnull = all (hasvalue, a)
334
- S = _broadcast_type (Array, f, a... )
310
+ S = _broadcast_type (f, a... )
335
311
if isleaftype (S) && null_safe_eltype_op (f, a... )
336
312
Nullable {S} (f (map (unsafe_get, a)... ), nonnull)
337
313
else
@@ -347,28 +323,21 @@ end
347
323
"""
348
324
broadcast(f, As...)
349
325
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
351
327
container 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`,
353
329
or `Nullable` is considered a scalar. The resulting container is established by
354
330
the following rules:
355
331
356
332
- If all the arguments are scalars, it returns a scalar.
357
333
- 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 .
361
337
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".
372
341
373
342
A special syntax exists for broadcasting: `f.(args...)` is equivalent to
374
343
`broadcast(f, args...)`, and nested `f.(g.(args...))` calls are fused into a
@@ -433,21 +402,8 @@ Nullable{String}("XY")
433
402
julia> broadcast(/, 1.0, Nullable(2.0))
434
403
Nullable{Float64}(0.5)
435
404
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}}()
451
407
```
452
408
"""
453
409
@inline broadcast (f, A, Bs... ) = broadcast_c (f, containertype (A, Bs... ), A, Bs... )
0 commit comments