##// END OF EJS Templates
Merge with stable
Merge with stable

File last commit:

r10264:d6512b3e merge default
r11312:3f140908 merge default
Show More
ancestor.py
86 lines | 2.4 KiB | text/x-python | PythonLexer
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 # ancestor.py - generic DAG ancestor algorithm for mercurial
#
# Copyright 2006 Matt Mackall <mpm@selenic.com>
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135
import heapq
def ancestor(a, b, pfunc):
"""
Sune Foldager
ancestor: improve docstring...
r9915 return a minimal-distance ancestor of nodes a and b, or None if there is no
such ancestor. Note that there can be several ancestors with the same
(minimal) distance, and the one returned is arbitrary.
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135
Sune Foldager
ancestor: improve docstring...
r9915 pfunc must return a list of parent vertices for a given vertex
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 """
if a == b:
return a
# find depth from root of all ancestors
Nicolas Dumazet
ancestor: caching the parent list to improve performance...
r7882 parentcache = {}
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 visit = [a, b]
depth = {}
while visit:
vertex = visit[-1]
pl = pfunc(vertex)
Nicolas Dumazet
ancestor: caching the parent list to improve performance...
r7882 parentcache[vertex] = pl
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 if not pl:
depth[vertex] = 0
visit.pop()
else:
for p in pl:
if p == a or p == b: # did we find a or b as a parent?
return p # we're done
if p not in depth:
visit.append(p)
if visit[-1] == vertex:
depth[vertex] = min([depth[p] for p in pl]) - 1
visit.pop()
# traverse ancestors in order of decreasing distance from root
def ancestors(vertex):
h = [(depth[vertex], vertex)]
Benoit Boissinot
ancestor: use set instead of dict
r8465 seen = set()
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 while h:
d, n = heapq.heappop(h)
if n not in seen:
Benoit Boissinot
ancestor: use set instead of dict
r8465 seen.add(n)
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 yield (d, n)
Nicolas Dumazet
ancestor: caching the parent list to improve performance...
r7882 for p in parentcache[n]:
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 heapq.heappush(h, (depth[p], p))
def generations(vertex):
Benoit Boissinot
ancestor: use set instead of dict
r8465 sg, s = None, set()
Thomas Arendsen Hein
white space and line break cleanups
r3673 for g, v in ancestors(vertex):
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 if g != sg:
if sg:
yield sg, s
Benoit Boissinot
ancestor: use set instead of dict
r8465 sg, s = g, set((v,))
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 else:
Benoit Boissinot
ancestor: use set instead of dict
r8465 s.add(v)
Matt Mackall
Abstract ancestor algorithm into generic function...
r3135 yield sg, s
x = generations(a)
y = generations(b)
gx = x.next()
gy = y.next()
# increment each ancestor list until it is closer to root than
# the other, or they match
try:
while 1:
if gx[0] == gy[0]:
for v in gx[1]:
if v in gy[1]:
return v
gy = y.next()
gx = x.next()
elif gx[0] > gy[0]:
gy = y.next()
else:
gx = x.next()
except StopIteration:
return None