Show More
@@ -134,40 +134,48 def ancestors(pfunc, *orignodes): | |||||
134 | return gca |
|
134 | return gca | |
135 | return deepest(gca) |
|
135 | return deepest(gca) | |
136 |
|
136 | |||
137 | def missingancestors(revs, bases, pfunc): |
|
137 | class incrementalmissingancestors(object): | |
138 | """Return all the ancestors of revs that are not ancestors of bases. |
|
138 | '''persistent state used to calculate missing ancestors incrementally | |
|
139 | ||||
|
140 | Although similar in spirit to lazyancestors below, this is a separate class | |||
|
141 | because trying to support contains and missingancestors operations with the | |||
|
142 | same internal data structures adds needless complexity.''' | |||
|
143 | def __init__(self, pfunc, bases): | |||
|
144 | self.bases = set(bases) | |||
|
145 | if not self.bases: | |||
|
146 | self.bases.add(nullrev) | |||
|
147 | self.pfunc = pfunc | |||
|
148 | ||||
|
149 | def missingancestors(self, revs): | |||
|
150 | '''return all the ancestors of revs that are not ancestors of self.bases | |||
139 |
|
151 | |||
140 | This may include elements from revs. |
|
152 | This may include elements from revs. | |
141 |
|
153 | |||
142 | Equivalent to the revset (::revs - ::bases). Revs are returned in |
|
154 | Equivalent to the revset (::revs - ::self.bases). Revs are returned in | |
143 | revision number order, which is a topological order. |
|
155 | revision number order, which is a topological order.''' | |
144 |
|
||||
145 | revs and bases should both be iterables. pfunc must return a list of |
|
|||
146 | parent revs for a given revs. |
|
|||
147 | """ |
|
|||
148 |
|
||||
149 | revsvisit = set(revs) |
|
156 | revsvisit = set(revs) | |
150 |
basesvisit = se |
|
157 | basesvisit = self.bases | |
151 | if not basesvisit: |
|
158 | pfunc = self.pfunc | |
152 | basesvisit.add(nullrev) |
|
|||
153 | bothvisit = revsvisit.intersection(basesvisit) |
|
159 | bothvisit = revsvisit.intersection(basesvisit) | |
154 | revsvisit.difference_update(bothvisit) |
|
160 | revsvisit.difference_update(bothvisit) | |
155 | if not revsvisit: |
|
161 | if not revsvisit: | |
156 | return [] |
|
162 | return [] | |
|
163 | ||||
157 | start = max(max(revsvisit), max(basesvisit)) |
|
164 | start = max(max(revsvisit), max(basesvisit)) | |
158 | # At this point, we hold the invariants that: |
|
165 | # At this point, we hold the invariants that: | |
159 |
# - revsvisit is the set of nodes we know are an ancestor of at least |
|
166 | # - revsvisit is the set of nodes we know are an ancestor of at least | |
160 | # of the nodes in revs |
|
167 | # one of the nodes in revs | |
161 | # - basesvisit is the same for bases |
|
168 | # - basesvisit is the same for bases | |
162 |
# - bothvisit is the set of nodes we know are ancestors of at least one |
|
169 | # - bothvisit is the set of nodes we know are ancestors of at least one | |
163 |
# the nodes in revs and one of the nodes in bases |
|
170 | # of the nodes in revs and one of the nodes in bases. bothvisit and | |
164 |
|
|
171 | # revsvisit are mutually exclusive, but bothvisit is a subset of | |
165 |
|
|
172 | # basesvisit. | |
166 |
# Now we walk down in reverse topo order, adding parents of nodes |
|
173 | # Now we walk down in reverse topo order, adding parents of nodes | |
167 |
# visited to the sets while maintaining the invariants. When a |
|
174 | # already visited to the sets while maintaining the invariants. When a | |
168 |
# in both revsvisit and basesvisit, it is removed from |
|
175 | # node is found in both revsvisit and basesvisit, it is removed from | |
169 |
# to bothvisit. When revsvisit becomes empty, there |
|
176 | # revsvisit and added to bothvisit. When revsvisit becomes empty, there | |
170 |
# revs that aren't also ancestors of bases, so |
|
177 | # are no more ancestors of revs that aren't also ancestors of bases, so | |
|
178 | # exit. | |||
171 |
|
179 | |||
172 | missing = [] |
|
180 | missing = [] | |
173 | for curr in xrange(start, nullrev, -1): |
|
181 | for curr in xrange(start, nullrev, -1): | |
@@ -176,8 +184,8 def missingancestors(revs, bases, pfunc) | |||||
176 |
|
184 | |||
177 | if curr in bothvisit: |
|
185 | if curr in bothvisit: | |
178 | bothvisit.remove(curr) |
|
186 | bothvisit.remove(curr) | |
179 |
# curr's parents might have made it into revsvisit through |
|
187 | # curr's parents might have made it into revsvisit through | |
180 | # path |
|
188 | # another path | |
181 | for p in pfunc(curr): |
|
189 | for p in pfunc(curr): | |
182 | revsvisit.discard(p) |
|
190 | revsvisit.discard(p) | |
183 | basesvisit.add(p) |
|
191 | basesvisit.add(p) | |
@@ -212,6 +220,10 def missingancestors(revs, bases, pfunc) | |||||
212 | missing.reverse() |
|
220 | missing.reverse() | |
213 | return missing |
|
221 | return missing | |
214 |
|
222 | |||
|
223 | def missingancestors(revs, bases, pfunc): | |||
|
224 | inc = incrementalmissingancestors(pfunc, bases) | |||
|
225 | return inc.missingancestors(revs) | |||
|
226 | ||||
215 | class lazyancestors(object): |
|
227 | class lazyancestors(object): | |
216 | def __init__(self, pfunc, revs, stoprev=0, inclusive=False): |
|
228 | def __init__(self, pfunc, revs, stoprev=0, inclusive=False): | |
217 | """Create a new object generating ancestors for the given revs. Does |
|
229 | """Create a new object generating ancestors for the given revs. Does |
@@ -88,7 +88,8 def test_missingancestors(seed, rng): | |||||
88 | revs = samplerevs(graphnodes) |
|
88 | revs = samplerevs(graphnodes) | |
89 |
|
89 | |||
90 | # fast algorithm |
|
90 | # fast algorithm | |
91 |
|
|
91 | inc = ancestor.incrementalmissingancestors(graph.__getitem__, bases) | |
|
92 | h = inc.missingancestors(revs) | |||
92 | # reference slow algorithm |
|
93 | # reference slow algorithm | |
93 | r = naivemissingancestors(ancs, revs, bases) |
|
94 | r = naivemissingancestors(ancs, revs, bases) | |
94 | if h != r: |
|
95 | if h != r: |
General Comments 0
You need to be logged in to leave comments.
Login now