##// END OF EJS Templates
dagutil: remove externalize() and externalizeall()...
Gregory Szorc -
r39196:0e46b92b default
parent child Browse files
Show More
@@ -1,287 +1,270
1 1 # dagutil.py - dag utilities for mercurial
2 2 #
3 3 # Copyright 2010 Benoit Boissinot <bboissin@gmail.com>
4 4 # and Peter Arrenbrecht <peter@arrenbrecht.ch>
5 5 #
6 6 # This software may be used and distributed according to the terms of the
7 7 # GNU General Public License version 2 or any later version.
8 8
9 9 from __future__ import absolute_import
10 10
11 11 from .i18n import _
12 12 from .node import nullrev
13 13
14 14 class basedag(object):
15 15 '''generic interface for DAGs
16 16
17 17 terms:
18 18 "ix" (short for index) identifies a nodes internally,
19 19 "id" identifies one externally.
20 20
21 21 All params are ixs unless explicitly suffixed otherwise.
22 22 Pluralized params are lists or sets.
23 23 '''
24 24
25 25 def __init__(self):
26 26 self._inverse = None
27 27
28 28 def nodeset(self):
29 29 '''set of all node ixs'''
30 30 raise NotImplementedError
31 31
32 32 def heads(self):
33 33 '''list of head ixs'''
34 34 raise NotImplementedError
35 35
36 36 def parents(self, ix):
37 37 '''list of parents ixs of ix'''
38 38 raise NotImplementedError
39 39
40 40 def inverse(self):
41 41 '''inverse DAG, where parents becomes children, etc.'''
42 42 raise NotImplementedError
43 43
44 44 def ancestorset(self, starts, stops=None):
45 45 '''
46 46 set of all ancestors of starts (incl), but stop walk at stops (excl)
47 47 '''
48 48 raise NotImplementedError
49 49
50 50 def descendantset(self, starts, stops=None):
51 51 '''
52 52 set of all descendants of starts (incl), but stop walk at stops (excl)
53 53 '''
54 54 return self.inverse().ancestorset(starts, stops)
55 55
56 56 def headsetofconnecteds(self, ixs):
57 57 '''
58 58 subset of connected list of ixs so that no node has a descendant in it
59 59
60 60 By "connected list" we mean that if an ancestor and a descendant are in
61 61 the list, then so is at least one path connecting them.
62 62 '''
63 63 raise NotImplementedError
64 64
65 def externalize(self, ix):
66 '''return a node id'''
67 return self._externalize(ix)
68
69 def externalizeall(self, ixs):
70 '''return a list of (or set if given a set) of node ids'''
71 ids = self._externalizeall(ixs)
72 if isinstance(ixs, set):
73 return set(ids)
74 return list(ids)
75
76 65 def internalize(self, id):
77 66 '''return a node ix'''
78 67 return self._internalize(id)
79 68
80 69 def internalizeall(self, ids, filterunknown=False):
81 70 '''return a list of (or set if given a set) of node ixs'''
82 71 ixs = self._internalizeall(ids, filterunknown)
83 72 if isinstance(ids, set):
84 73 return set(ixs)
85 74 return list(ixs)
86 75
87 76
88 77 class genericdag(basedag):
89 78 '''generic implementations for DAGs'''
90 79
91 80 def ancestorset(self, starts, stops=None):
92 81 if stops:
93 82 stops = set(stops)
94 83 else:
95 84 stops = set()
96 85 seen = set()
97 86 pending = list(starts)
98 87 while pending:
99 88 n = pending.pop()
100 89 if n not in seen and n not in stops:
101 90 seen.add(n)
102 91 pending.extend(self.parents(n))
103 92 return seen
104 93
105 94 def headsetofconnecteds(self, ixs):
106 95 hds = set(ixs)
107 96 if not hds:
108 97 return hds
109 98 for n in ixs:
110 99 for p in self.parents(n):
111 100 hds.discard(p)
112 101 assert hds
113 102 return hds
114 103
115 104
116 105 class revlogbaseddag(basedag):
117 106 '''generic dag interface to a revlog'''
118 107
119 108 def __init__(self, revlog, nodeset):
120 109 basedag.__init__(self)
121 110 self._revlog = revlog
122 111 self._heads = None
123 112 self._nodeset = nodeset
124 113
125 114 def nodeset(self):
126 115 return self._nodeset
127 116
128 117 def heads(self):
129 118 if self._heads is None:
130 119 self._heads = self._getheads()
131 120 return self._heads
132 121
133 def _externalize(self, ix):
134 return self._revlog.index[ix][7]
135 def _externalizeall(self, ixs):
136 idx = self._revlog.index
137 return [idx[i][7] for i in ixs]
138
139 122 def _internalize(self, id):
140 123 ix = self._revlog.rev(id)
141 124 if ix == nullrev:
142 125 raise LookupError(id, self._revlog.indexfile, _('nullid'))
143 126 return ix
144 127 def _internalizeall(self, ids, filterunknown):
145 128 rl = self._revlog
146 129 if filterunknown:
147 130 return [r for r in map(rl.nodemap.get, ids)
148 131 if (r is not None
149 132 and r != nullrev
150 133 and r not in rl.filteredrevs)]
151 134 return [self._internalize(i) for i in ids]
152 135
153 136
154 137 class revlogdag(revlogbaseddag):
155 138 '''dag interface to a revlog'''
156 139
157 140 def __init__(self, revlog, localsubset=None):
158 141 revlogbaseddag.__init__(self, revlog, set(revlog))
159 142 self._heads = localsubset
160 143
161 144 def _getheads(self):
162 145 return [r for r in self._revlog.headrevs() if r != nullrev]
163 146
164 147 def parents(self, ix):
165 148 rlog = self._revlog
166 149 idx = rlog.index
167 150 revdata = idx[ix]
168 151 prev = revdata[5]
169 152 if prev != nullrev:
170 153 prev2 = revdata[6]
171 154 if prev2 == nullrev:
172 155 return [prev]
173 156 return [prev, prev2]
174 157 prev2 = revdata[6]
175 158 if prev2 != nullrev:
176 159 return [prev2]
177 160 return []
178 161
179 162 def inverse(self):
180 163 if self._inverse is None:
181 164 self._inverse = inverserevlogdag(self)
182 165 return self._inverse
183 166
184 167 def ancestorset(self, starts, stops=None):
185 168 rlog = self._revlog
186 169 idx = rlog.index
187 170 if stops:
188 171 stops = set(stops)
189 172 else:
190 173 stops = set()
191 174 seen = set()
192 175 pending = list(starts)
193 176 while pending:
194 177 rev = pending.pop()
195 178 if rev not in seen and rev not in stops:
196 179 seen.add(rev)
197 180 revdata = idx[rev]
198 181 for i in [5, 6]:
199 182 prev = revdata[i]
200 183 if prev != nullrev:
201 184 pending.append(prev)
202 185 return seen
203 186
204 187 def headsetofconnecteds(self, ixs):
205 188 if not ixs:
206 189 return set()
207 190 rlog = self._revlog
208 191 idx = rlog.index
209 192 headrevs = set(ixs)
210 193 for rev in ixs:
211 194 revdata = idx[rev]
212 195 for i in [5, 6]:
213 196 prev = revdata[i]
214 197 if prev != nullrev:
215 198 headrevs.discard(prev)
216 199 assert headrevs
217 200 return headrevs
218 201
219 202 def linearize(self, ixs):
220 203 '''linearize and topologically sort a list of revisions
221 204
222 205 The linearization process tries to create long runs of revs where
223 206 a child rev comes immediately after its first parent. This is done by
224 207 visiting the heads of the given revs in inverse topological order,
225 208 and for each visited rev, visiting its second parent, then its first
226 209 parent, then adding the rev itself to the output list.
227 210 '''
228 211 sorted = []
229 212 visit = list(self.headsetofconnecteds(ixs))
230 213 visit.sort(reverse=True)
231 214 finished = set()
232 215
233 216 while visit:
234 217 cur = visit.pop()
235 218 if cur < 0:
236 219 cur = -cur - 1
237 220 if cur not in finished:
238 221 sorted.append(cur)
239 222 finished.add(cur)
240 223 else:
241 224 visit.append(-cur - 1)
242 225 visit += [p for p in self.parents(cur)
243 226 if p in ixs and p not in finished]
244 227 assert len(sorted) == len(ixs)
245 228 return sorted
246 229
247 230
248 231 class inverserevlogdag(revlogbaseddag, genericdag):
249 232 '''inverse of an existing revlog dag; see revlogdag.inverse()'''
250 233
251 234 def __init__(self, orig):
252 235 revlogbaseddag.__init__(self, orig._revlog, orig._nodeset)
253 236 self._orig = orig
254 237 self._children = {}
255 238 self._roots = []
256 239 self._walkfrom = len(self._revlog) - 1
257 240
258 241 def _walkto(self, walkto):
259 242 rev = self._walkfrom
260 243 cs = self._children
261 244 roots = self._roots
262 245 idx = self._revlog.index
263 246 while rev >= walkto:
264 247 data = idx[rev]
265 248 isroot = True
266 249 for prev in [data[5], data[6]]: # parent revs
267 250 if prev != nullrev:
268 251 cs.setdefault(prev, []).append(rev)
269 252 isroot = False
270 253 if isroot:
271 254 roots.append(rev)
272 255 rev -= 1
273 256 self._walkfrom = rev
274 257
275 258 def _getheads(self):
276 259 self._walkto(nullrev)
277 260 return self._roots
278 261
279 262 def parents(self, ix):
280 263 if ix is None:
281 264 return []
282 265 if ix <= self._walkfrom:
283 266 self._walkto(ix)
284 267 return self._children.get(ix, [])
285 268
286 269 def inverse(self):
287 270 return self._orig
General Comments 0
You need to be logged in to leave comments. Login now