1
- using Base: promote_eltype
2
- using Base. Cartesian
3
1
if VERSION >= v " 0.6.0-dev.693"
4
2
using Base. Broadcast: check_broadcast_indices, broadcast_indices
3
+ using Base. Broadcast: check_broadcast_indices, broadcast_indices,
4
+ _default_eltype, ftype, ziptype
5
5
else
6
6
using Base. Broadcast: check_broadcast_shape, broadcast_shape
7
+ using Base. Broadcast: check_broadcast_shape, broadcast_shape,
8
+ _default_eltype, ftype, ziptype
7
9
const check_broadcast_indices = check_broadcast_shape
8
10
const broadcast_indices = broadcast_shape
9
11
end
15
17
_to_shape (x) = x
16
18
end
17
19
18
- if VERSION < v " 0.5.0-dev+5434"
19
- function gen_nullcheck (narrays:: Int , nd:: Int )
20
- e_nullcheck = macroexpand (:( @nref $ nd isnull_1 d-> j_d_1 ))
21
- for k = 2 : narrays
22
- isnull = Symbol (" isnull_$k " )
23
- j_d_k = Symbol (" j_d_$k " )
24
- e_isnull_k = macroexpand (:( @nref $ nd $ (isnull) d-> $ (j_d_k) ))
25
- e_nullcheck = Expr (:|| , e_nullcheck, e_isnull_k)
26
- end
27
- return e_nullcheck
28
- end
29
-
30
- function gen_broadcast_body (nd:: Int , narrays:: Int , f, lift:: Bool )
31
- F = Expr (:quote , f)
32
- e_nullcheck = gen_nullcheck (narrays, nd)
33
- if lift
34
- return quote
35
- # set up aliases to facilitate subsequent Base.Cartesian magic
36
- B_isnull = B. isnull
37
- @nexprs $ narrays k-> (values_k = A_k. values)
38
- @nexprs $ narrays k-> (isnull_k = A_k. isnull)
39
- # check size
40
- @assert ndims (B) == $ nd
41
- @ncall $ narrays check_broadcast_shape size (B) k-> A_k
42
- # main loops
43
- @nloops ($ nd, i, B,
44
- d-> (@nexprs $ narrays k-> (j_d_k = size (A_k, d) == 1 ? 1 : i_d)), # pre
45
- begin # body
46
- if $ e_nullcheck
47
- @inbounds (@nref $ nd B_isnull i) = true
48
- else
49
- @nexprs $ narrays k-> (@inbounds v_k = @nref $ nd values_k d-> j_d_k)
50
- @inbounds (@nref $ nd B i) = (@ncall $ narrays $ F v)
51
- end
52
- end
53
- )
54
- end
55
- else
56
- return Base. Broadcast. gen_broadcast_body_cartesian (nd, narrays, f)
57
- end
58
- end
59
-
60
- function gen_broadcast_function (nd:: Int , narrays:: Int , f, lift:: Bool )
61
- As = [Symbol (" A_" * string (i)) for i = 1 : narrays]
62
- body = gen_broadcast_body (nd, narrays, f, lift)
63
- @eval let
64
- local _F_
65
- function _F_ (B, $ (As... ))
66
- $ body
67
- end
68
- _F_
69
- end
70
- end
71
-
72
- function Base. broadcast! (f, X:: NullableArray ; lift:: Bool = false )
73
- broadcast! (f, X, X; lift= lift)
74
- end
75
-
76
- @eval let cache = Dict{Any, Dict{Bool, Dict{Int, Dict{Int, Any}}}}()
77
- @doc """
78
- `broadcast!(f, B::NullableArray, As::NullableArray...; lift::Bool=false)`
79
- This method implements the same behavior as that of `broadcast!` when called on
80
- regular `Array` arguments. It also includes the `lift` keyword argument, which
81
- when set to true will lift `f` over the entries of the `As`.
82
-
83
- Lifting is disabled by default. Note that this method's signature specifies
84
- the destination `B` array as well as the source `As` arrays as all
85
- `NullableArray`s. Thus, calling `broadcast!` on a arguments consisting
86
- of both `Array`s and `NullableArray`s will fall back to the implementation
87
- of `broadcast!` in `base/broadcast.jl`.
88
- """ ->
89
- function Base. broadcast! (f, B:: NullableArray , As:: NullableArray... ; lift:: Bool = false )
90
- nd = ndims (B)
91
- narrays = length (As)
92
-
93
- cache_f = Base. @get! cache f Dict {Bool, Dict{Int, Dict{Int, Any}}} ()
94
- cache_lift = Base. @get! cache_f lift Dict {Int, Dict{Int, Any}} ()
95
- cache_f_na = Base. @get! cache_lift narrays Dict {Int, Any} ()
96
- func = Base. @get! cache_f_na nd gen_broadcast_function (nd, narrays, f, lift)
97
-
98
- func (B, As... )
99
- return B
100
- end
101
- end # let cache
102
- else
103
- using Base. Broadcast: newindexer, map_newindexer, newindex
104
-
105
- function _nullcheck (nargs)
106
- nullcheck = :(isnull_1[I_1])
107
- for i in 2 : nargs
108
- sym_isnull = Symbol (" isnull_$i " )
109
- sym_idx = Symbol (" I_$i " )
110
- nullcheck = Expr (:|| , :($ sym_isnull[$ sym_idx]), nullcheck)
111
- end
112
- # if 0 argument arrays, treat nullcheck as though it returns false
113
- nargs >= 1 ? nullcheck : :(false )
114
- end
115
-
116
- @generated function Base. Broadcast. _broadcast! {K,ID,XT,nargs} (f,
117
- Z:: NullableArray , keeps:: K , Idefaults:: ID , Xs:: XT , :: Type{Val{nargs}} ; lift= false )
118
- nullcheck = _nullcheck (nargs)
119
- quote
120
- T = eltype (Z)
121
- $ (Expr (:meta , :noinline ))
122
- # destructure keeps and Xs tuples (common to both lifted and non-lifted broadcast)
123
- @nexprs $ nargs i-> (keep_i = keeps[i])
124
- @nexprs $ nargs i-> (Idefault_i = Idefaults[i])
125
- if ! lift
126
- # destructure the keeps and As tuples
127
- @nexprs $ nargs i-> (X_i = Xs[i])
128
- @simd for I in CartesianRange (indices (Z))
129
- # reverse-broadcast the indices
130
- @nexprs $ nargs i-> (I_i = newindex (I, keep_i, Idefault_i))
131
- # extract array values
132
- @nexprs $ nargs i-> (@inbounds val_i = X_i[I_i])
133
- # call the function and store the result
134
- @inbounds Z[I] = @ncall $ nargs f val
135
- end
136
- else
137
- # destructure the indexmaps and Xs tuples
138
- @nexprs $ nargs i-> (values_i = Xs[i]. values)
139
- @nexprs $ nargs i-> (isnull_i = Xs[i]. isnull)
140
- @simd for I in CartesianRange (indices (Z))
141
- # reverse-broadcast the indices
142
- @nexprs $ nargs i-> (I_i = newindex (I, keep_i, Idefault_i))
143
- if $ nullcheck
144
- # if any args are null, store null
145
- @inbounds Z. isnull[I] = true
146
- else
147
- # extract array values
148
- @nexprs $ nargs i-> (@inbounds val_i = values_i[I_i])
149
- # call the function and store the result
150
- @inbounds Z[I] = @ncall $ nargs f val
151
- end
152
- end
153
- end
154
- end
155
- end
156
-
157
- @doc """
158
- `broadcast!(f, B::NullableArray, As::NullableArray...; lift::Bool=false)`
159
-
160
- This method implements the same behavior as that of `broadcast!` when called
161
- on regular `Array` arguments. It also includes the `lift` keyword argument,
162
- which when set to true will lift `f` over the entries of the `As`.
163
-
164
- Lifting is disabled by default. Note that this method's signature specifies
165
- the destination `B` array as well as the source `As` arrays as all
166
- `NullableArray`s. Thus, calling `broadcast!` on a arguments consisting of
167
- both `Array`s and `NullableArray`s will fall back to the implementation of
168
- `broadcast!` in `base/broadcast.jl`.
169
- """ ->
170
- # Required to solve dispatch ambiguity between
171
- # broadcast!(f, X::AbstractArray, x::Number...)
172
- # broadcast!(f, Z::NullableArrays.NullableArray, Xs::NullableArrays.NullableArray...)
173
- @inline Base. broadcast! (f, Z:: NullableArray ; lift= false ) =
174
- broadcast! (f, Z, Z; lift= lift)
175
-
176
- @inline function Base. broadcast! (f, Z:: NullableArray , Xs:: NullableArray... ;
177
- lift= false )
178
- nargs = length (Xs)
179
- shape = indices (Z)
180
- check_broadcast_indices (shape, Xs... )
181
- keeps, Idefaults = map_newindexer (shape, Xs)
182
- Base. Broadcast. _broadcast! (f, Z, keeps, Idefaults, Xs, Val{nargs}; lift= lift)
183
- return Z
184
- end
185
- end
186
20
187
21
@doc """
188
- `broadcast(f, As::NullableArray...;lift::Bool=false )`
22
+ `broadcast(f, As::NullableArray...)`
189
23
190
24
This method implements the same behavior as that of `broadcast` when called on
191
25
regular `Array` arguments. It also includes the `lift` keyword argument, which
@@ -196,10 +30,20 @@ source `As` arrays as all `NullableArray`s. Thus, calling `broadcast!` on
196
30
arguments consisting of both `Array`s and `NullableArray`s will fall back to the
197
31
implementation of `broadcast` in `base/broadcast.jl`.
198
32
""" ->
199
- @inline function Base. broadcast (f, Xs:: NullableArray... ;lift:: Bool = false )
200
- return broadcast! (f, NullableArray (eltype (promote_eltype (Xs... )),
201
- _to_shape (broadcast_indices (Xs... ))),
202
- Xs... ; lift= lift)
33
+ function Base. broadcast {N} (f, As:: Vararg{NullableArray, N} )
34
+ f2 (x... ) = lift (f, x... )
35
+ T = _default_eltype (Base. Generator{ziptype (As... ), ftype (f2, As... )})
36
+ if isleaftype (T) && ! (T <: Nullable )
37
+ return invoke (broadcast, Tuple{Function, Vararg{AbstractArray, N}}, f2, As... )
38
+ else
39
+ dest = NullableArray (eltype (T), _to_shape (broadcast_indices (As... )))
40
+ return invoke (broadcast!, Tuple{Function, AbstractArray, Vararg{AbstractArray, N}}, f2, dest, As... )
41
+ end
42
+ end
43
+
44
+ function Base. broadcast! {N} (f, dest:: AbstractArray , As:: Vararg{NullableArray, N} )
45
+ f2 (x... ) = lift (f, x... )
46
+ invoke (broadcast!, Tuple{Function, AbstractArray, Vararg{AbstractArray, N}}, f2, dest, As... )
203
47
end
204
48
205
49
# broadcasted ops
0 commit comments