mirror of
https://github.com/facebook/sapling.git
synced 2024-10-04 22:07:44 +03:00
A new ancestor algorithm
The old ancestor algorithm could get fooled into returning ancestors closer to root than it ought to. Hopefully this one, which strictly orders its search by distance from room, will be foolproof.
This commit is contained in:
parent
cbe151d218
commit
dba1a9fc73
@ -8,7 +8,7 @@
|
|||||||
# This software may be used and distributed according to the terms
|
# This software may be used and distributed according to the terms
|
||||||
# of the GNU General Public License, incorporated herein by reference.
|
# of the GNU General Public License, incorporated herein by reference.
|
||||||
|
|
||||||
import zlib, struct, sha, os, tempfile, binascii
|
import zlib, struct, sha, os, tempfile, binascii, heapq
|
||||||
from mercurial import mdiff
|
from mercurial import mdiff
|
||||||
|
|
||||||
def hex(node): return binascii.hexlify(node)
|
def hex(node): return binascii.hexlify(node)
|
||||||
@ -276,38 +276,42 @@ class revlog:
|
|||||||
return node
|
return node
|
||||||
|
|
||||||
def ancestor(self, a, b):
|
def ancestor(self, a, b):
|
||||||
def expand(list, map):
|
# calculate the distance of every node from root
|
||||||
a = []
|
dist = {nullid: 0}
|
||||||
while list:
|
for i in xrange(self.count()):
|
||||||
n = list.pop(0)
|
n = self.node(i)
|
||||||
map[n] = 1
|
p1, p2 = self.parents(n)
|
||||||
yield n
|
dist[n] = max(dist[p1], dist[p2]) + 1
|
||||||
for p in self.parents(n):
|
|
||||||
if p != nullid and p not in map:
|
# traverse ancestors in order of decreasing distance from root
|
||||||
list.append(p)
|
def ancestors(node):
|
||||||
yield nullid
|
# we store negative distances because heap returns smallest member
|
||||||
|
h = [(-dist[node], node)]
|
||||||
|
seen = {}
|
||||||
|
earliest = self.count()
|
||||||
|
while h:
|
||||||
|
d, n = heapq.heappop(h)
|
||||||
|
r = self.rev(n)
|
||||||
|
if n not in seen:
|
||||||
|
seen[n] = 1
|
||||||
|
yield (-d, n)
|
||||||
|
for p in self.parents(n):
|
||||||
|
heapq.heappush(h, (-dist[p], p))
|
||||||
|
|
||||||
amap = {}
|
x = ancestors(a)
|
||||||
bmap = {}
|
y = ancestors(b)
|
||||||
ag = expand([a], amap)
|
lx = x.next()
|
||||||
bg = expand([b], bmap)
|
ly = y.next()
|
||||||
adone = bdone = 0
|
|
||||||
|
|
||||||
while not adone or not bdone:
|
# increment each ancestor list until it is closer to root than
|
||||||
if not adone:
|
# the other, or they match
|
||||||
an = ag.next()
|
while 1:
|
||||||
if an == nullid:
|
if lx == ly:
|
||||||
adone = 1
|
return lx[1]
|
||||||
elif an in bmap:
|
elif lx < ly:
|
||||||
return an
|
ly = y.next()
|
||||||
if not bdone:
|
elif lx > ly:
|
||||||
bn = bg.next()
|
lx = x.next()
|
||||||
if bn == nullid:
|
|
||||||
bdone = 1
|
|
||||||
elif bn in amap:
|
|
||||||
return bn
|
|
||||||
|
|
||||||
return nullid
|
|
||||||
|
|
||||||
def group(self, linkmap):
|
def group(self, linkmap):
|
||||||
# given a list of changeset revs, return a set of deltas and
|
# given a list of changeset revs, return a set of deltas and
|
||||||
|
Loading…
Reference in New Issue
Block a user