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