186
186
child_node.gdfo = next_gdfo
187
187
heappush(todo, (next_gdfo, child_node))
189
def _get_dominators_to_keys(self, candidate_nodes):
190
"""Get the reverse mapping from dominators => candidate_nodes.
189
def _get_dominators_to_nodes(self, candidate_nodes):
190
"""Get the reverse mapping from dominator_key => candidate_nodes.
192
This might also exclude certain candidate_nodes if it is determined
193
that they share a dominator.
192
As a side effect, this can also remove potential candidate nodes if we
193
determine that they share a dominator.
196
196
keys_to_remove = []
197
197
for node in candidate_nodes.values():
198
if node.linear_dominator in dom_to_key:
198
if node.linear_dominator in dom_to_node:
199
199
# This node already exists, resolve which node supersedes the
201
other_node_key = dom_to_key[node.linear_dominator]
202
other_node = self._nodes[other_node_key]
201
other_node = dom_to_node[node.linear_dominator]
203
202
# There should be no way that nodes sharing a dominator could
205
204
assert other_node.gdfo != node.gdfo
206
205
if other_node.gdfo > node.gdfo:
207
206
# The other node has this node as an ancestor
208
207
keys_to_remove.append(node.key)
211
209
# Replace the other node, and set this as the new key
212
210
keys_to_remove.append(other_node.key)
213
dom_to_key[node.linear_dominator] = node.key
211
dom_to_node[node.linear_dominator] = node
215
dom_to_key[node.linear_dominator] = node.key
213
dom_to_node[node.linear_dominator] = node
216
214
for key in keys_to_remove:
217
215
candidate_nodes.pop(key)
220
218
def heads(self, keys):
221
219
"""Return the heads from amongst keys.
250
248
pass # compute it ourselves
251
dom_to_key = self._get_dominators_to_keys(candidate_nodes)
249
dom_to_node = self._get_dominators_to_nodes(candidate_nodes)
252
250
if len(candidate_nodes) < 2:
253
251
# We shrunk candidate_nodes and determined a new head
254
252
return frozenset(candidate_nodes)
260
258
if dom_heads_key in self._known_heads:
261
259
# map back into the original keys
262
260
heads = self._known_heads[dom_heads_key]
263
heads = frozenset([dom_to_key[key] for key in heads])
261
heads = frozenset([dom_to_node[key].key for key in heads])
265
heads = self._heads_from_candidate_nodes(candidate_nodes, dom_to_key)
263
heads = self._heads_from_candidate_nodes(candidate_nodes, dom_to_node)
266
264
if self.do_cache:
267
265
self._known_heads[heads_key] = heads
268
266
# Cache the dominator heads
272
270
self._known_heads[dom_heads_key] = dom_heads
275
def _heads_from_candidate_nodes(self, candidate_nodes, dom_to_key):
273
def _heads_from_candidate_nodes(self, candidate_nodes, dom_to_node):
278
276
to_cleanup_append = to_cleanup.append
325
323
candidate_nodes.pop(parent_key)
326
324
if len(candidate_nodes) <= 1:
328
if parent_key in dom_to_key:
329
orig_key = dom_to_key[parent_key]
330
if orig_key != node.key:
331
if orig_key in candidate_nodes:
332
candidate_nodes.pop(orig_key)
326
elif parent_key in dom_to_node:
327
orig_node = dom_to_node[parent_key]
328
if orig_node is not node:
329
if orig_node.key in candidate_nodes:
330
candidate_nodes.pop(orig_node.key)
333
331
if len(candidate_nodes) <= 1:
335
333
parent_node = nodes[parent_key]