##// END OF EJS Templates
ancestor: improve docstring...
Sune Foldager -
r9915:806e6b6c default
parent child Browse files
Show More
@@ -1,85 +1,86 b''
1 # ancestor.py - generic DAG ancestor algorithm for mercurial
1 # ancestor.py - generic DAG ancestor algorithm for mercurial
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7
7
8 import heapq
8 import heapq
9
9
10 def ancestor(a, b, pfunc):
10 def ancestor(a, b, pfunc):
11 """
11 """
12 return the least common ancestor of nodes a and b or None if there
12 return a minimal-distance ancestor of nodes a and b, or None if there is no
13 is no such ancestor.
13 such ancestor. Note that there can be several ancestors with the same
14 (minimal) distance, and the one returned is arbitrary.
14
15
15 pfunc must return a list of parent vertices
16 pfunc must return a list of parent vertices for a given vertex
16 """
17 """
17
18
18 if a == b:
19 if a == b:
19 return a
20 return a
20
21
21 # find depth from root of all ancestors
22 # find depth from root of all ancestors
22 parentcache = {}
23 parentcache = {}
23 visit = [a, b]
24 visit = [a, b]
24 depth = {}
25 depth = {}
25 while visit:
26 while visit:
26 vertex = visit[-1]
27 vertex = visit[-1]
27 pl = pfunc(vertex)
28 pl = pfunc(vertex)
28 parentcache[vertex] = pl
29 parentcache[vertex] = pl
29 if not pl:
30 if not pl:
30 depth[vertex] = 0
31 depth[vertex] = 0
31 visit.pop()
32 visit.pop()
32 else:
33 else:
33 for p in pl:
34 for p in pl:
34 if p == a or p == b: # did we find a or b as a parent?
35 if p == a or p == b: # did we find a or b as a parent?
35 return p # we're done
36 return p # we're done
36 if p not in depth:
37 if p not in depth:
37 visit.append(p)
38 visit.append(p)
38 if visit[-1] == vertex:
39 if visit[-1] == vertex:
39 depth[vertex] = min([depth[p] for p in pl]) - 1
40 depth[vertex] = min([depth[p] for p in pl]) - 1
40 visit.pop()
41 visit.pop()
41
42
42 # traverse ancestors in order of decreasing distance from root
43 # traverse ancestors in order of decreasing distance from root
43 def ancestors(vertex):
44 def ancestors(vertex):
44 h = [(depth[vertex], vertex)]
45 h = [(depth[vertex], vertex)]
45 seen = set()
46 seen = set()
46 while h:
47 while h:
47 d, n = heapq.heappop(h)
48 d, n = heapq.heappop(h)
48 if n not in seen:
49 if n not in seen:
49 seen.add(n)
50 seen.add(n)
50 yield (d, n)
51 yield (d, n)
51 for p in parentcache[n]:
52 for p in parentcache[n]:
52 heapq.heappush(h, (depth[p], p))
53 heapq.heappush(h, (depth[p], p))
53
54
54 def generations(vertex):
55 def generations(vertex):
55 sg, s = None, set()
56 sg, s = None, set()
56 for g, v in ancestors(vertex):
57 for g, v in ancestors(vertex):
57 if g != sg:
58 if g != sg:
58 if sg:
59 if sg:
59 yield sg, s
60 yield sg, s
60 sg, s = g, set((v,))
61 sg, s = g, set((v,))
61 else:
62 else:
62 s.add(v)
63 s.add(v)
63 yield sg, s
64 yield sg, s
64
65
65 x = generations(a)
66 x = generations(a)
66 y = generations(b)
67 y = generations(b)
67 gx = x.next()
68 gx = x.next()
68 gy = y.next()
69 gy = y.next()
69
70
70 # increment each ancestor list until it is closer to root than
71 # increment each ancestor list until it is closer to root than
71 # the other, or they match
72 # the other, or they match
72 try:
73 try:
73 while 1:
74 while 1:
74 if gx[0] == gy[0]:
75 if gx[0] == gy[0]:
75 for v in gx[1]:
76 for v in gx[1]:
76 if v in gy[1]:
77 if v in gy[1]:
77 return v
78 return v
78 gy = y.next()
79 gy = y.next()
79 gx = x.next()
80 gx = x.next()
80 elif gx[0] > gy[0]:
81 elif gx[0] > gy[0]:
81 gy = y.next()
82 gy = y.next()
82 else:
83 else:
83 gx = x.next()
84 gx = x.next()
84 except StopIteration:
85 except StopIteration:
85 return None
86 return None
General Comments 0
You need to be logged in to leave comments. Login now