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