289
297
cdef dict candidate_nodes
290
298
cdef dict dom_to_node
300
cdef _KnownGraphNode node
301
cdef PyObject *maybe_node
292
303
candidate_nodes = {}
294
candidate_nodes[key] = self._nodes[key]
307
# candidate_nodes[key] = node
308
maybe_node = PyDict_GetItem(nodes, key)
309
if maybe_node == NULL:
310
raise KeyError('key %s not in nodes' % (key,))
311
PyDict_SetItem(candidate_nodes, key, <object>maybe_node)
295
312
if revision.NULL_REVISION in candidate_nodes:
296
313
# NULL_REVISION is only a head if it is the only entry
297
314
candidate_nodes.pop(revision.NULL_REVISION)
298
315
if not candidate_nodes:
299
316
return set([revision.NULL_REVISION])
317
heads_key = PyFrozenSet_New(candidate_nodes)
300
318
if len(candidate_nodes) < 2:
301
return frozenset(candidate_nodes)
302
heads_key = frozenset(candidate_nodes)
304
321
heads = self._known_heads[heads_key]
307
324
pass # compute it ourselves
309
## # TODO: We could optimize for the len(candidate_nodes) > 2 by checking
310
## # for *any* pair-wise matching, and then eliminating one of the
311
## # nodes trivially. However, the fairly common case is just 2
312
## # keys, so we'll focus on that, first
313
## for node in candidate_nodes.itervalues():
314
## if dominator is None:
315
## dominator = node.linear_dominator
316
## elif dominator != node.linear_dominator:
319
## # In 'time bzr annotate NEWS' this only catches *one* item, so it
320
## # probably isn't worth the optimization
321
## # All of these nodes have the same linear_dominator, which means
322
## # they are in a line, the head is just the one with the highest
324
## def get_distance(key):
325
## return self._nodes[key].dominator_distance
326
## def get_linear_head():
327
## return max(candidate_nodes, key=get_distance)
328
## return set([get_linear_head()])
329
325
# Check the linear dominators of these keys, to see if we already
330
326
# know the heads answer
332
# for node in candidate_nodes.itervalues():
333
# dom_key.append(node.linear_dominator.key)
334
# dom_key = frozenset(dom_key)
335
# if dom_key in self._known_heads:
336
# dom_to_node = dict([(node.linear_dominator, key)
337
# for key, node in candidate_nodes.iteritems()])
338
# # map back into the original keys
339
# heads = self._known_heads[dom_key]
340
# heads = frozenset([dom_to_node[key] for key in heads])
327
dom_lookup_key, heads = self._heads_from_dominators(
328
candidate_nodes.values())
329
if heads is not None:
342
331
heads = self._heads_from_candidate_nodes(candidate_nodes)
344
# self._known_heads[heads_key] = heads
345
# # Cache the dominator heads
346
# if dom_key is not None:
347
# dom_heads = frozenset([candidate_nodes[key].linear_dominator
349
# self._known_heads[dom_key] = dom_heads
333
self._cache_heads(heads, heads_key, dom_lookup_key, candidate_nodes)
352
def _heads_from_candidate_nodes(self, dict candidate_nodes):
336
cdef object _cache_heads(self, heads, heads_key, dom_lookup_key,
339
cdef PyObject *maybe_node
340
cdef _KnownGraphNode node
342
PyDict_SetItem(self._known_heads, heads_key, heads)
345
maybe_node = PyDict_GetItem(candidate_nodes, key)
346
if maybe_node == NULL:
348
node = <object>maybe_node
349
dom_heads.append(node.linear_dominator_node.key)
350
PyDict_SetItem(self._known_heads, dom_lookup_key,
351
PyFrozenSet_New(dom_heads))
353
cdef object _heads_from_dominators(self, list candidates):
354
cdef PyObject *test_heads
355
cdef PyObject *test_key
356
cdef list heads, dom_list_key
357
cdef _KnownGraphNode node
360
for node in candidates:
361
dom_list_key.append(node.linear_dominator_node.key)
362
dom_lookup_key = PyFrozenSet_New(dom_list_key)
363
test_heads = PyDict_GetItem(self._known_heads, dom_lookup_key)
364
if test_heads == NULL:
365
return dom_lookup_key, None
366
# We need to map back to the original keys
367
dom_heads = <object>test_heads
369
for node in candidates:
370
PyDict_SetItem(dom_to_key, node.linear_dominator_node.key,
373
for dom_key in dom_heads:
374
test_key = PyDict_GetItem(dom_to_key, dom_key)
376
# Should never happen
378
heads.append(<object>test_key)
379
return dom_lookup_key, PyFrozenSet_New(heads)
381
cdef object _heads_from_candidate_nodes(self, dict candidate_nodes):
353
382
cdef list to_cleanup
354
383
cdef _KnownGraphNode node
355
384
cdef _KnownGraphNode parent_node