290
290
sorter = tsort.TopoSorter(zip(revisions, self.get_parents(revisions)))
291
291
return sorter.iter_topo_order()
293
def is_ancestor(self, candidate_ancestor, candidate_descendant):
294
"""Determine whether a revision is an ancestor of another.
296
There are two possible outcomes: True and False, but there are three
297
possible relationships:
299
a) candidate_ancestor is an ancestor of candidate_descendant
300
b) candidate_ancestor is an descendant of candidate_descendant
301
c) candidate_ancestor is an sibling of candidate_descendant
303
To check for a, we walk from candidate_descendant, looking for
306
To check for b, we walk from candidate_ancestor, looking for
307
candidate_descendant.
309
To make a and b more efficient, we can stop any searches that hit
312
If we exhaust our searches, but neither a or b is true, then c is true.
314
In order to find c efficiently, we must avoid searching from
315
candidate_descendant or candidate_ancestor into common ancestors. But
316
if we don't search common ancestors at all, we won't know if we hit
317
common ancestors. So we have a walker for common ancestors. Note that
318
its searches are not required to terminate in order to determine c to
321
ancestor_walker = self._make_breadth_first_searcher(
322
[candidate_ancestor])
323
descendant_walker = self._make_breadth_first_searcher(
324
[candidate_descendant])
325
common_walker = self._make_breadth_first_searcher([])
326
active_ancestor = True
327
active_descendant = True
328
while (active_ancestor or active_descendant):
330
if active_descendant:
332
nodes = descendant_walker.next()
333
except StopIteration:
334
active_descendant = False
336
if candidate_ancestor in nodes:
338
new_common.update(nodes.intersection(ancestor_walker.seen))
341
nodes = ancestor_walker.next()
342
except StopIteration:
343
active_ancestor = False
345
if candidate_descendant in nodes:
347
new_common.update(nodes.intersection(
348
descendant_walker.seen))
350
new_common.update(common_walker.next())
351
except StopIteration:
353
for walker in (ancestor_walker, descendant_walker):
354
for node in new_common:
355
c_ancestors = walker.find_seen_ancestors(node)
356
walker.stop_searching_any(c_ancestors)
357
common_walker.start_searching(new_common)
294
361
class _BreadthFirstSearcher(object):
295
362
"""Parallel search the breadth-first the ancestry of revisions.