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