@@ -76,7 +76,7 @@ for N in (:Node, :GraphNode)
7676 val:: T # If is a constant, this stores the actual value
7777 feature:: UInt16 # (Possibly undefined) If is a variable (e.g., x in cos(x)), this stores the feature index.
7878 op:: UInt8 # (Possibly undefined) If operator, this is the index of the operator in the degree-specific operator enum
79- children:: NTuple{D,Base.RefValue{ $N{T,D}}} # Children nodes
79+ children:: NTuple{D,$N{T,D}}
8080
8181 # ################
8282 # # Constructors:
@@ -113,7 +113,7 @@ nodes, you can evaluate or print a given expression.
113113 operator in `operators.binops`. In other words, this is an enum
114114 of the operators, and is dependent on the specific `OperatorEnum`
115115 object. Only defined if `degree >= 1`
116- - `children::NTuple{D,Base.RefValue{ Node{T,D} }}`: Children of the node. Only defined up to `degree`
116+ - `children::NTuple{D,Node{T,D}}`: Children of the node. Only defined up to `degree`
117117
118118# Constructors
119119
@@ -166,31 +166,44 @@ when constructing or setting properties.
166166"""
167167GraphNode
168168
169+ function get_poison (n:: AbstractNode )
170+ # We don't want to use `nothing` because the type instability
171+ # hits memory hard.
172+ # Setting itself as the right child is the best thing,
173+ # because it (1) doesn't allocate, and (2) will trigger
174+ # infinite recursion errors if someone is mistakenly trying
175+ # to access the right child when `.degree == 1`.
176+ return n
177+ end
178+
169179macro make_accessors (node_type)
170180 esc (quote
171181 @inline function Base. getproperty (n:: $node_type , k:: Symbol )
172182 if k == :l
173183 # TODO : Should a depwarn be raised here? Or too slow?
174- return getfield (n, :children )[1 ][]
184+ return getfield (n, :children )[1 ]
175185 elseif k == :r
176- return getfield (n, :children )[2 ][]
186+ return getfield (n, :children )[2 ]
177187 else
178188 return getfield (n, k)
179189 end
180190 end
181191 @inline function Base. setproperty! (n:: $node_type , k:: Symbol , v)
182192 if k == :l
183193 if isdefined (n, :children )
184- getfield (n, :children )[1 ][] = v
194+ old = getfield (n, :children )
195+ setfield! (n, :children , (v, old[2 ]))
196+ v
185197 else
186- r = Ref (v )
187- setfield! (n, :children , (r, Ref {typeof(n)} () ))
188- r
198+ poison = get_poison (n )
199+ setfield! (n, :children , (v, poison ))
200+ v
189201 end
190202 elseif k == :r
191203 # TODO : Remove this assert once we know that this is safe
192- @assert isdefined (n, :children )
193- getfield (n, :children )[2 ][] = v
204+ old = getfield (n, :children )
205+ setfield! (n, :children , (old[1 ], v))
206+ v
194207 else
195208 T = fieldtype (typeof (n), k)
196209 if v isa T
@@ -203,13 +216,13 @@ macro make_accessors(node_type)
203216 end )
204217end
205218
206- @make_accessors Node
207- @make_accessors GraphNode
219+ @make_accessors Node{T, 2 } where {T}
220+ @make_accessors GraphNode{T, 2 } where {T}
208221
209222@inline children (node:: AbstractNode ) = node. children
210223@inline function children (node:: AbstractNode , :: Val{n} ) where {n}
211224 cs = children (node)
212- return ntuple (i -> cs[i][] , Val (n))
225+ return ntuple (i -> cs[i], Val (n))
213226end
214227
215228# ###############################################################################
312325 n = allocator (N, T)
313326 n. degree = D2
314327 n. op = op
315- n. children = ntuple (i -> i <= D2 ? Ref (convert (NT, children[i])) : Ref {NT} (), Val (max_degree (N)))
328+ poison = get_poison (n)
329+ n. children = ntuple (i -> i <= D2 ? convert (NT, children[i]) : poison, Val (max_degree (N)))
316330 return n
317331end
318332
0 commit comments