##// END OF EJS Templates
parsers: introduce index_commonancestorsheads...
Mads Kiilerich -
r21102:4eb65537 default
parent child Browse files
Show More
@@ -1,1990 +1,2090 b''
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static inline int hexdigit(const char *p, Py_ssize_t off)
38 static inline int hexdigit(const char *p, Py_ssize_t off)
39 {
39 {
40 int8_t val = hextable[(unsigned char)p[off]];
40 int8_t val = hextable[(unsigned char)p[off]];
41
41
42 if (val >= 0) {
42 if (val >= 0) {
43 return val;
43 return val;
44 }
44 }
45
45
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
46 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
47 return 0;
47 return 0;
48 }
48 }
49
49
50 /*
50 /*
51 * Turn a hex-encoded string into binary.
51 * Turn a hex-encoded string into binary.
52 */
52 */
53 static PyObject *unhexlify(const char *str, int len)
53 static PyObject *unhexlify(const char *str, int len)
54 {
54 {
55 PyObject *ret;
55 PyObject *ret;
56 char *d;
56 char *d;
57 int i;
57 int i;
58
58
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
59 ret = PyBytes_FromStringAndSize(NULL, len / 2);
60
60
61 if (!ret)
61 if (!ret)
62 return NULL;
62 return NULL;
63
63
64 d = PyBytes_AsString(ret);
64 d = PyBytes_AsString(ret);
65
65
66 for (i = 0; i < len;) {
66 for (i = 0; i < len;) {
67 int hi = hexdigit(str, i++);
67 int hi = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
68 int lo = hexdigit(str, i++);
69 *d++ = (hi << 4) | lo;
69 *d++ = (hi << 4) | lo;
70 }
70 }
71
71
72 return ret;
72 return ret;
73 }
73 }
74
74
75 /*
75 /*
76 * This code assumes that a manifest is stitched together with newline
76 * This code assumes that a manifest is stitched together with newline
77 * ('\n') characters.
77 * ('\n') characters.
78 */
78 */
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
79 static PyObject *parse_manifest(PyObject *self, PyObject *args)
80 {
80 {
81 PyObject *mfdict, *fdict;
81 PyObject *mfdict, *fdict;
82 char *str, *start, *end;
82 char *str, *start, *end;
83 int len;
83 int len;
84
84
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
85 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
86 &PyDict_Type, &mfdict,
86 &PyDict_Type, &mfdict,
87 &PyDict_Type, &fdict,
87 &PyDict_Type, &fdict,
88 &str, &len))
88 &str, &len))
89 goto quit;
89 goto quit;
90
90
91 start = str;
91 start = str;
92 end = str + len;
92 end = str + len;
93 while (start < end) {
93 while (start < end) {
94 PyObject *file = NULL, *node = NULL;
94 PyObject *file = NULL, *node = NULL;
95 PyObject *flags = NULL;
95 PyObject *flags = NULL;
96 char *zero = NULL, *newline = NULL;
96 char *zero = NULL, *newline = NULL;
97 ptrdiff_t nlen;
97 ptrdiff_t nlen;
98
98
99 zero = memchr(start, '\0', end - start);
99 zero = memchr(start, '\0', end - start);
100 if (!zero) {
100 if (!zero) {
101 PyErr_SetString(PyExc_ValueError,
101 PyErr_SetString(PyExc_ValueError,
102 "manifest entry has no separator");
102 "manifest entry has no separator");
103 goto quit;
103 goto quit;
104 }
104 }
105
105
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
106 newline = memchr(zero + 1, '\n', end - (zero + 1));
107 if (!newline) {
107 if (!newline) {
108 PyErr_SetString(PyExc_ValueError,
108 PyErr_SetString(PyExc_ValueError,
109 "manifest contains trailing garbage");
109 "manifest contains trailing garbage");
110 goto quit;
110 goto quit;
111 }
111 }
112
112
113 file = PyBytes_FromStringAndSize(start, zero - start);
113 file = PyBytes_FromStringAndSize(start, zero - start);
114
114
115 if (!file)
115 if (!file)
116 goto bail;
116 goto bail;
117
117
118 nlen = newline - zero - 1;
118 nlen = newline - zero - 1;
119
119
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
120 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
121 if (!node)
121 if (!node)
122 goto bail;
122 goto bail;
123
123
124 if (nlen > 40) {
124 if (nlen > 40) {
125 flags = PyBytes_FromStringAndSize(zero + 41,
125 flags = PyBytes_FromStringAndSize(zero + 41,
126 nlen - 40);
126 nlen - 40);
127 if (!flags)
127 if (!flags)
128 goto bail;
128 goto bail;
129
129
130 if (PyDict_SetItem(fdict, file, flags) == -1)
130 if (PyDict_SetItem(fdict, file, flags) == -1)
131 goto bail;
131 goto bail;
132 }
132 }
133
133
134 if (PyDict_SetItem(mfdict, file, node) == -1)
134 if (PyDict_SetItem(mfdict, file, node) == -1)
135 goto bail;
135 goto bail;
136
136
137 start = newline + 1;
137 start = newline + 1;
138
138
139 Py_XDECREF(flags);
139 Py_XDECREF(flags);
140 Py_XDECREF(node);
140 Py_XDECREF(node);
141 Py_XDECREF(file);
141 Py_XDECREF(file);
142 continue;
142 continue;
143 bail:
143 bail:
144 Py_XDECREF(flags);
144 Py_XDECREF(flags);
145 Py_XDECREF(node);
145 Py_XDECREF(node);
146 Py_XDECREF(file);
146 Py_XDECREF(file);
147 goto quit;
147 goto quit;
148 }
148 }
149
149
150 Py_INCREF(Py_None);
150 Py_INCREF(Py_None);
151 return Py_None;
151 return Py_None;
152 quit:
152 quit:
153 return NULL;
153 return NULL;
154 }
154 }
155
155
156 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
156 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
157 {
157 {
158 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
158 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
159 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
159 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
160 char state, *cur, *str, *cpos;
160 char state, *cur, *str, *cpos;
161 int mode, size, mtime;
161 int mode, size, mtime;
162 unsigned int flen;
162 unsigned int flen;
163 int len, pos = 40;
163 int len, pos = 40;
164
164
165 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
165 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
166 &PyDict_Type, &dmap,
166 &PyDict_Type, &dmap,
167 &PyDict_Type, &cmap,
167 &PyDict_Type, &cmap,
168 &str, &len))
168 &str, &len))
169 goto quit;
169 goto quit;
170
170
171 /* read parents */
171 /* read parents */
172 if (len < 40)
172 if (len < 40)
173 goto quit;
173 goto quit;
174
174
175 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
175 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
176 if (!parents)
176 if (!parents)
177 goto quit;
177 goto quit;
178
178
179 /* read filenames */
179 /* read filenames */
180 while (pos >= 40 && pos < len) {
180 while (pos >= 40 && pos < len) {
181 cur = str + pos;
181 cur = str + pos;
182 /* unpack header */
182 /* unpack header */
183 state = *cur;
183 state = *cur;
184 mode = getbe32(cur + 1);
184 mode = getbe32(cur + 1);
185 size = getbe32(cur + 5);
185 size = getbe32(cur + 5);
186 mtime = getbe32(cur + 9);
186 mtime = getbe32(cur + 9);
187 flen = getbe32(cur + 13);
187 flen = getbe32(cur + 13);
188 pos += 17;
188 pos += 17;
189 cur += 17;
189 cur += 17;
190 if (flen > len - pos) {
190 if (flen > len - pos) {
191 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
191 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
192 goto quit;
192 goto quit;
193 }
193 }
194
194
195 entry = Py_BuildValue("ciii", state, mode, size, mtime);
195 entry = Py_BuildValue("ciii", state, mode, size, mtime);
196 if (!entry)
196 if (!entry)
197 goto quit;
197 goto quit;
198 PyObject_GC_UnTrack(entry); /* don't waste time with this */
198 PyObject_GC_UnTrack(entry); /* don't waste time with this */
199
199
200 cpos = memchr(cur, 0, flen);
200 cpos = memchr(cur, 0, flen);
201 if (cpos) {
201 if (cpos) {
202 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
202 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
203 cname = PyBytes_FromStringAndSize(cpos + 1,
203 cname = PyBytes_FromStringAndSize(cpos + 1,
204 flen - (cpos - cur) - 1);
204 flen - (cpos - cur) - 1);
205 if (!fname || !cname ||
205 if (!fname || !cname ||
206 PyDict_SetItem(cmap, fname, cname) == -1 ||
206 PyDict_SetItem(cmap, fname, cname) == -1 ||
207 PyDict_SetItem(dmap, fname, entry) == -1)
207 PyDict_SetItem(dmap, fname, entry) == -1)
208 goto quit;
208 goto quit;
209 Py_DECREF(cname);
209 Py_DECREF(cname);
210 } else {
210 } else {
211 fname = PyBytes_FromStringAndSize(cur, flen);
211 fname = PyBytes_FromStringAndSize(cur, flen);
212 if (!fname ||
212 if (!fname ||
213 PyDict_SetItem(dmap, fname, entry) == -1)
213 PyDict_SetItem(dmap, fname, entry) == -1)
214 goto quit;
214 goto quit;
215 }
215 }
216 Py_DECREF(fname);
216 Py_DECREF(fname);
217 Py_DECREF(entry);
217 Py_DECREF(entry);
218 fname = cname = entry = NULL;
218 fname = cname = entry = NULL;
219 pos += flen;
219 pos += flen;
220 }
220 }
221
221
222 ret = parents;
222 ret = parents;
223 Py_INCREF(ret);
223 Py_INCREF(ret);
224 quit:
224 quit:
225 Py_XDECREF(fname);
225 Py_XDECREF(fname);
226 Py_XDECREF(cname);
226 Py_XDECREF(cname);
227 Py_XDECREF(entry);
227 Py_XDECREF(entry);
228 Py_XDECREF(parents);
228 Py_XDECREF(parents);
229 return ret;
229 return ret;
230 }
230 }
231
231
232 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
232 static inline int getintat(PyObject *tuple, int off, uint32_t *v)
233 {
233 {
234 PyObject *o = PyTuple_GET_ITEM(tuple, off);
234 PyObject *o = PyTuple_GET_ITEM(tuple, off);
235 long val;
235 long val;
236
236
237 if (PyInt_Check(o))
237 if (PyInt_Check(o))
238 val = PyInt_AS_LONG(o);
238 val = PyInt_AS_LONG(o);
239 else if (PyLong_Check(o)) {
239 else if (PyLong_Check(o)) {
240 val = PyLong_AsLong(o);
240 val = PyLong_AsLong(o);
241 if (val == -1 && PyErr_Occurred())
241 if (val == -1 && PyErr_Occurred())
242 return -1;
242 return -1;
243 } else {
243 } else {
244 PyErr_SetString(PyExc_TypeError, "expected an int or long");
244 PyErr_SetString(PyExc_TypeError, "expected an int or long");
245 return -1;
245 return -1;
246 }
246 }
247 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
247 if (LONG_MAX > INT_MAX && (val > INT_MAX || val < INT_MIN)) {
248 PyErr_SetString(PyExc_OverflowError,
248 PyErr_SetString(PyExc_OverflowError,
249 "Python value to large to convert to uint32_t");
249 "Python value to large to convert to uint32_t");
250 return -1;
250 return -1;
251 }
251 }
252 *v = (uint32_t)val;
252 *v = (uint32_t)val;
253 return 0;
253 return 0;
254 }
254 }
255
255
256 static PyObject *dirstate_unset;
256 static PyObject *dirstate_unset;
257
257
258 /*
258 /*
259 * Efficiently pack a dirstate object into its on-disk format.
259 * Efficiently pack a dirstate object into its on-disk format.
260 */
260 */
261 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
261 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
262 {
262 {
263 PyObject *packobj = NULL;
263 PyObject *packobj = NULL;
264 PyObject *map, *copymap, *pl;
264 PyObject *map, *copymap, *pl;
265 Py_ssize_t nbytes, pos, l;
265 Py_ssize_t nbytes, pos, l;
266 PyObject *k, *v, *pn;
266 PyObject *k, *v, *pn;
267 char *p, *s;
267 char *p, *s;
268 double now;
268 double now;
269
269
270 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
270 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
271 &PyDict_Type, &map, &PyDict_Type, &copymap,
271 &PyDict_Type, &map, &PyDict_Type, &copymap,
272 &pl, &now))
272 &pl, &now))
273 return NULL;
273 return NULL;
274
274
275 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
275 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
276 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
276 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
277 return NULL;
277 return NULL;
278 }
278 }
279
279
280 /* Figure out how much we need to allocate. */
280 /* Figure out how much we need to allocate. */
281 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
281 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
282 PyObject *c;
282 PyObject *c;
283 if (!PyString_Check(k)) {
283 if (!PyString_Check(k)) {
284 PyErr_SetString(PyExc_TypeError, "expected string key");
284 PyErr_SetString(PyExc_TypeError, "expected string key");
285 goto bail;
285 goto bail;
286 }
286 }
287 nbytes += PyString_GET_SIZE(k) + 17;
287 nbytes += PyString_GET_SIZE(k) + 17;
288 c = PyDict_GetItem(copymap, k);
288 c = PyDict_GetItem(copymap, k);
289 if (c) {
289 if (c) {
290 if (!PyString_Check(c)) {
290 if (!PyString_Check(c)) {
291 PyErr_SetString(PyExc_TypeError,
291 PyErr_SetString(PyExc_TypeError,
292 "expected string key");
292 "expected string key");
293 goto bail;
293 goto bail;
294 }
294 }
295 nbytes += PyString_GET_SIZE(c) + 1;
295 nbytes += PyString_GET_SIZE(c) + 1;
296 }
296 }
297 }
297 }
298
298
299 packobj = PyString_FromStringAndSize(NULL, nbytes);
299 packobj = PyString_FromStringAndSize(NULL, nbytes);
300 if (packobj == NULL)
300 if (packobj == NULL)
301 goto bail;
301 goto bail;
302
302
303 p = PyString_AS_STRING(packobj);
303 p = PyString_AS_STRING(packobj);
304
304
305 pn = PySequence_ITEM(pl, 0);
305 pn = PySequence_ITEM(pl, 0);
306 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
306 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
307 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
307 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
308 goto bail;
308 goto bail;
309 }
309 }
310 memcpy(p, s, l);
310 memcpy(p, s, l);
311 p += 20;
311 p += 20;
312 pn = PySequence_ITEM(pl, 1);
312 pn = PySequence_ITEM(pl, 1);
313 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
313 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
314 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
314 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
315 goto bail;
315 goto bail;
316 }
316 }
317 memcpy(p, s, l);
317 memcpy(p, s, l);
318 p += 20;
318 p += 20;
319
319
320 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
320 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
321 uint32_t mode, size, mtime;
321 uint32_t mode, size, mtime;
322 Py_ssize_t len, l;
322 Py_ssize_t len, l;
323 PyObject *o;
323 PyObject *o;
324 char *s, *t;
324 char *s, *t;
325
325
326 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
326 if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) {
327 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
327 PyErr_SetString(PyExc_TypeError, "expected a 4-tuple");
328 goto bail;
328 goto bail;
329 }
329 }
330 o = PyTuple_GET_ITEM(v, 0);
330 o = PyTuple_GET_ITEM(v, 0);
331 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
331 if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) {
332 PyErr_SetString(PyExc_TypeError, "expected one byte");
332 PyErr_SetString(PyExc_TypeError, "expected one byte");
333 goto bail;
333 goto bail;
334 }
334 }
335 *p++ = *s;
335 *p++ = *s;
336 if (getintat(v, 1, &mode) == -1)
336 if (getintat(v, 1, &mode) == -1)
337 goto bail;
337 goto bail;
338 if (getintat(v, 2, &size) == -1)
338 if (getintat(v, 2, &size) == -1)
339 goto bail;
339 goto bail;
340 if (getintat(v, 3, &mtime) == -1)
340 if (getintat(v, 3, &mtime) == -1)
341 goto bail;
341 goto bail;
342 if (*s == 'n' && mtime == (uint32_t)now) {
342 if (*s == 'n' && mtime == (uint32_t)now) {
343 /* See pure/parsers.py:pack_dirstate for why we do
343 /* See pure/parsers.py:pack_dirstate for why we do
344 * this. */
344 * this. */
345 if (PyDict_SetItem(map, k, dirstate_unset) == -1)
345 if (PyDict_SetItem(map, k, dirstate_unset) == -1)
346 goto bail;
346 goto bail;
347 mtime = -1;
347 mtime = -1;
348 }
348 }
349 putbe32(mode, p);
349 putbe32(mode, p);
350 putbe32(size, p + 4);
350 putbe32(size, p + 4);
351 putbe32(mtime, p + 8);
351 putbe32(mtime, p + 8);
352 t = p + 12;
352 t = p + 12;
353 p += 16;
353 p += 16;
354 len = PyString_GET_SIZE(k);
354 len = PyString_GET_SIZE(k);
355 memcpy(p, PyString_AS_STRING(k), len);
355 memcpy(p, PyString_AS_STRING(k), len);
356 p += len;
356 p += len;
357 o = PyDict_GetItem(copymap, k);
357 o = PyDict_GetItem(copymap, k);
358 if (o) {
358 if (o) {
359 *p++ = '\0';
359 *p++ = '\0';
360 l = PyString_GET_SIZE(o);
360 l = PyString_GET_SIZE(o);
361 memcpy(p, PyString_AS_STRING(o), l);
361 memcpy(p, PyString_AS_STRING(o), l);
362 p += l;
362 p += l;
363 len += l + 1;
363 len += l + 1;
364 }
364 }
365 putbe32((uint32_t)len, t);
365 putbe32((uint32_t)len, t);
366 }
366 }
367
367
368 pos = p - PyString_AS_STRING(packobj);
368 pos = p - PyString_AS_STRING(packobj);
369 if (pos != nbytes) {
369 if (pos != nbytes) {
370 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
370 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
371 (long)pos, (long)nbytes);
371 (long)pos, (long)nbytes);
372 goto bail;
372 goto bail;
373 }
373 }
374
374
375 return packobj;
375 return packobj;
376 bail:
376 bail:
377 Py_XDECREF(packobj);
377 Py_XDECREF(packobj);
378 return NULL;
378 return NULL;
379 }
379 }
380
380
381 /*
381 /*
382 * A base-16 trie for fast node->rev mapping.
382 * A base-16 trie for fast node->rev mapping.
383 *
383 *
384 * Positive value is index of the next node in the trie
384 * Positive value is index of the next node in the trie
385 * Negative value is a leaf: -(rev + 1)
385 * Negative value is a leaf: -(rev + 1)
386 * Zero is empty
386 * Zero is empty
387 */
387 */
388 typedef struct {
388 typedef struct {
389 int children[16];
389 int children[16];
390 } nodetree;
390 } nodetree;
391
391
392 /*
392 /*
393 * This class has two behaviours.
393 * This class has two behaviours.
394 *
394 *
395 * When used in a list-like way (with integer keys), we decode an
395 * When used in a list-like way (with integer keys), we decode an
396 * entry in a RevlogNG index file on demand. Our last entry is a
396 * entry in a RevlogNG index file on demand. Our last entry is a
397 * sentinel, always a nullid. We have limited support for
397 * sentinel, always a nullid. We have limited support for
398 * integer-keyed insert and delete, only at elements right before the
398 * integer-keyed insert and delete, only at elements right before the
399 * sentinel.
399 * sentinel.
400 *
400 *
401 * With string keys, we lazily perform a reverse mapping from node to
401 * With string keys, we lazily perform a reverse mapping from node to
402 * rev, using a base-16 trie.
402 * rev, using a base-16 trie.
403 */
403 */
404 typedef struct {
404 typedef struct {
405 PyObject_HEAD
405 PyObject_HEAD
406 /* Type-specific fields go here. */
406 /* Type-specific fields go here. */
407 PyObject *data; /* raw bytes of index */
407 PyObject *data; /* raw bytes of index */
408 PyObject **cache; /* cached tuples */
408 PyObject **cache; /* cached tuples */
409 const char **offsets; /* populated on demand */
409 const char **offsets; /* populated on demand */
410 Py_ssize_t raw_length; /* original number of elements */
410 Py_ssize_t raw_length; /* original number of elements */
411 Py_ssize_t length; /* current number of elements */
411 Py_ssize_t length; /* current number of elements */
412 PyObject *added; /* populated on demand */
412 PyObject *added; /* populated on demand */
413 PyObject *headrevs; /* cache, invalidated on changes */
413 PyObject *headrevs; /* cache, invalidated on changes */
414 nodetree *nt; /* base-16 trie */
414 nodetree *nt; /* base-16 trie */
415 int ntlength; /* # nodes in use */
415 int ntlength; /* # nodes in use */
416 int ntcapacity; /* # nodes allocated */
416 int ntcapacity; /* # nodes allocated */
417 int ntdepth; /* maximum depth of tree */
417 int ntdepth; /* maximum depth of tree */
418 int ntsplits; /* # splits performed */
418 int ntsplits; /* # splits performed */
419 int ntrev; /* last rev scanned */
419 int ntrev; /* last rev scanned */
420 int ntlookups; /* # lookups */
420 int ntlookups; /* # lookups */
421 int ntmisses; /* # lookups that miss the cache */
421 int ntmisses; /* # lookups that miss the cache */
422 int inlined;
422 int inlined;
423 } indexObject;
423 } indexObject;
424
424
425 static Py_ssize_t index_length(const indexObject *self)
425 static Py_ssize_t index_length(const indexObject *self)
426 {
426 {
427 if (self->added == NULL)
427 if (self->added == NULL)
428 return self->length;
428 return self->length;
429 return self->length + PyList_GET_SIZE(self->added);
429 return self->length + PyList_GET_SIZE(self->added);
430 }
430 }
431
431
432 static PyObject *nullentry;
432 static PyObject *nullentry;
433 static const char nullid[20];
433 static const char nullid[20];
434
434
435 static long inline_scan(indexObject *self, const char **offsets);
435 static long inline_scan(indexObject *self, const char **offsets);
436
436
437 #if LONG_MAX == 0x7fffffffL
437 #if LONG_MAX == 0x7fffffffL
438 static char *tuple_format = "Kiiiiiis#";
438 static char *tuple_format = "Kiiiiiis#";
439 #else
439 #else
440 static char *tuple_format = "kiiiiiis#";
440 static char *tuple_format = "kiiiiiis#";
441 #endif
441 #endif
442
442
443 /* A RevlogNG v1 index entry is 64 bytes long. */
443 /* A RevlogNG v1 index entry is 64 bytes long. */
444 static const long v1_hdrsize = 64;
444 static const long v1_hdrsize = 64;
445
445
446 /*
446 /*
447 * Return a pointer to the beginning of a RevlogNG record.
447 * Return a pointer to the beginning of a RevlogNG record.
448 */
448 */
449 static const char *index_deref(indexObject *self, Py_ssize_t pos)
449 static const char *index_deref(indexObject *self, Py_ssize_t pos)
450 {
450 {
451 if (self->inlined && pos > 0) {
451 if (self->inlined && pos > 0) {
452 if (self->offsets == NULL) {
452 if (self->offsets == NULL) {
453 self->offsets = malloc(self->raw_length *
453 self->offsets = malloc(self->raw_length *
454 sizeof(*self->offsets));
454 sizeof(*self->offsets));
455 if (self->offsets == NULL)
455 if (self->offsets == NULL)
456 return (const char *)PyErr_NoMemory();
456 return (const char *)PyErr_NoMemory();
457 inline_scan(self, self->offsets);
457 inline_scan(self, self->offsets);
458 }
458 }
459 return self->offsets[pos];
459 return self->offsets[pos];
460 }
460 }
461
461
462 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
462 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
463 }
463 }
464
464
465 /*
465 /*
466 * RevlogNG format (all in big endian, data may be inlined):
466 * RevlogNG format (all in big endian, data may be inlined):
467 * 6 bytes: offset
467 * 6 bytes: offset
468 * 2 bytes: flags
468 * 2 bytes: flags
469 * 4 bytes: compressed length
469 * 4 bytes: compressed length
470 * 4 bytes: uncompressed length
470 * 4 bytes: uncompressed length
471 * 4 bytes: base revision
471 * 4 bytes: base revision
472 * 4 bytes: link revision
472 * 4 bytes: link revision
473 * 4 bytes: parent 1 revision
473 * 4 bytes: parent 1 revision
474 * 4 bytes: parent 2 revision
474 * 4 bytes: parent 2 revision
475 * 32 bytes: nodeid (only 20 bytes used)
475 * 32 bytes: nodeid (only 20 bytes used)
476 */
476 */
477 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
477 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
478 {
478 {
479 uint64_t offset_flags;
479 uint64_t offset_flags;
480 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
480 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
481 const char *c_node_id;
481 const char *c_node_id;
482 const char *data;
482 const char *data;
483 Py_ssize_t length = index_length(self);
483 Py_ssize_t length = index_length(self);
484 PyObject *entry;
484 PyObject *entry;
485
485
486 if (pos < 0)
486 if (pos < 0)
487 pos += length;
487 pos += length;
488
488
489 if (pos < 0 || pos >= length) {
489 if (pos < 0 || pos >= length) {
490 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
490 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
491 return NULL;
491 return NULL;
492 }
492 }
493
493
494 if (pos == length - 1) {
494 if (pos == length - 1) {
495 Py_INCREF(nullentry);
495 Py_INCREF(nullentry);
496 return nullentry;
496 return nullentry;
497 }
497 }
498
498
499 if (pos >= self->length - 1) {
499 if (pos >= self->length - 1) {
500 PyObject *obj;
500 PyObject *obj;
501 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
501 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
502 Py_INCREF(obj);
502 Py_INCREF(obj);
503 return obj;
503 return obj;
504 }
504 }
505
505
506 if (self->cache) {
506 if (self->cache) {
507 if (self->cache[pos]) {
507 if (self->cache[pos]) {
508 Py_INCREF(self->cache[pos]);
508 Py_INCREF(self->cache[pos]);
509 return self->cache[pos];
509 return self->cache[pos];
510 }
510 }
511 } else {
511 } else {
512 self->cache = calloc(self->raw_length, sizeof(PyObject *));
512 self->cache = calloc(self->raw_length, sizeof(PyObject *));
513 if (self->cache == NULL)
513 if (self->cache == NULL)
514 return PyErr_NoMemory();
514 return PyErr_NoMemory();
515 }
515 }
516
516
517 data = index_deref(self, pos);
517 data = index_deref(self, pos);
518 if (data == NULL)
518 if (data == NULL)
519 return NULL;
519 return NULL;
520
520
521 offset_flags = getbe32(data + 4);
521 offset_flags = getbe32(data + 4);
522 if (pos == 0) /* mask out version number for the first entry */
522 if (pos == 0) /* mask out version number for the first entry */
523 offset_flags &= 0xFFFF;
523 offset_flags &= 0xFFFF;
524 else {
524 else {
525 uint32_t offset_high = getbe32(data);
525 uint32_t offset_high = getbe32(data);
526 offset_flags |= ((uint64_t)offset_high) << 32;
526 offset_flags |= ((uint64_t)offset_high) << 32;
527 }
527 }
528
528
529 comp_len = getbe32(data + 8);
529 comp_len = getbe32(data + 8);
530 uncomp_len = getbe32(data + 12);
530 uncomp_len = getbe32(data + 12);
531 base_rev = getbe32(data + 16);
531 base_rev = getbe32(data + 16);
532 link_rev = getbe32(data + 20);
532 link_rev = getbe32(data + 20);
533 parent_1 = getbe32(data + 24);
533 parent_1 = getbe32(data + 24);
534 parent_2 = getbe32(data + 28);
534 parent_2 = getbe32(data + 28);
535 c_node_id = data + 32;
535 c_node_id = data + 32;
536
536
537 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
537 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
538 uncomp_len, base_rev, link_rev,
538 uncomp_len, base_rev, link_rev,
539 parent_1, parent_2, c_node_id, 20);
539 parent_1, parent_2, c_node_id, 20);
540
540
541 if (entry) {
541 if (entry) {
542 PyObject_GC_UnTrack(entry);
542 PyObject_GC_UnTrack(entry);
543 Py_INCREF(entry);
543 Py_INCREF(entry);
544 }
544 }
545
545
546 self->cache[pos] = entry;
546 self->cache[pos] = entry;
547
547
548 return entry;
548 return entry;
549 }
549 }
550
550
551 /*
551 /*
552 * Return the 20-byte SHA of the node corresponding to the given rev.
552 * Return the 20-byte SHA of the node corresponding to the given rev.
553 */
553 */
554 static const char *index_node(indexObject *self, Py_ssize_t pos)
554 static const char *index_node(indexObject *self, Py_ssize_t pos)
555 {
555 {
556 Py_ssize_t length = index_length(self);
556 Py_ssize_t length = index_length(self);
557 const char *data;
557 const char *data;
558
558
559 if (pos == length - 1 || pos == INT_MAX)
559 if (pos == length - 1 || pos == INT_MAX)
560 return nullid;
560 return nullid;
561
561
562 if (pos >= length)
562 if (pos >= length)
563 return NULL;
563 return NULL;
564
564
565 if (pos >= self->length - 1) {
565 if (pos >= self->length - 1) {
566 PyObject *tuple, *str;
566 PyObject *tuple, *str;
567 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
567 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
568 str = PyTuple_GetItem(tuple, 7);
568 str = PyTuple_GetItem(tuple, 7);
569 return str ? PyString_AS_STRING(str) : NULL;
569 return str ? PyString_AS_STRING(str) : NULL;
570 }
570 }
571
571
572 data = index_deref(self, pos);
572 data = index_deref(self, pos);
573 return data ? data + 32 : NULL;
573 return data ? data + 32 : NULL;
574 }
574 }
575
575
576 static int nt_insert(indexObject *self, const char *node, int rev);
576 static int nt_insert(indexObject *self, const char *node, int rev);
577
577
578 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
578 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
579 {
579 {
580 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
580 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
581 return -1;
581 return -1;
582 if (*nodelen == 20)
582 if (*nodelen == 20)
583 return 0;
583 return 0;
584 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
584 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
585 return -1;
585 return -1;
586 }
586 }
587
587
588 static PyObject *index_insert(indexObject *self, PyObject *args)
588 static PyObject *index_insert(indexObject *self, PyObject *args)
589 {
589 {
590 PyObject *obj;
590 PyObject *obj;
591 char *node;
591 char *node;
592 long offset;
592 long offset;
593 Py_ssize_t len, nodelen;
593 Py_ssize_t len, nodelen;
594
594
595 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
595 if (!PyArg_ParseTuple(args, "lO", &offset, &obj))
596 return NULL;
596 return NULL;
597
597
598 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
598 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
599 PyErr_SetString(PyExc_TypeError, "8-tuple required");
599 PyErr_SetString(PyExc_TypeError, "8-tuple required");
600 return NULL;
600 return NULL;
601 }
601 }
602
602
603 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
603 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
604 return NULL;
604 return NULL;
605
605
606 len = index_length(self);
606 len = index_length(self);
607
607
608 if (offset < 0)
608 if (offset < 0)
609 offset += len;
609 offset += len;
610
610
611 if (offset != len - 1) {
611 if (offset != len - 1) {
612 PyErr_SetString(PyExc_IndexError,
612 PyErr_SetString(PyExc_IndexError,
613 "insert only supported at index -1");
613 "insert only supported at index -1");
614 return NULL;
614 return NULL;
615 }
615 }
616
616
617 if (offset > INT_MAX) {
617 if (offset > INT_MAX) {
618 PyErr_SetString(PyExc_ValueError,
618 PyErr_SetString(PyExc_ValueError,
619 "currently only 2**31 revs supported");
619 "currently only 2**31 revs supported");
620 return NULL;
620 return NULL;
621 }
621 }
622
622
623 if (self->added == NULL) {
623 if (self->added == NULL) {
624 self->added = PyList_New(0);
624 self->added = PyList_New(0);
625 if (self->added == NULL)
625 if (self->added == NULL)
626 return NULL;
626 return NULL;
627 }
627 }
628
628
629 if (PyList_Append(self->added, obj) == -1)
629 if (PyList_Append(self->added, obj) == -1)
630 return NULL;
630 return NULL;
631
631
632 if (self->nt)
632 if (self->nt)
633 nt_insert(self, node, (int)offset);
633 nt_insert(self, node, (int)offset);
634
634
635 Py_CLEAR(self->headrevs);
635 Py_CLEAR(self->headrevs);
636 Py_RETURN_NONE;
636 Py_RETURN_NONE;
637 }
637 }
638
638
639 static void _index_clearcaches(indexObject *self)
639 static void _index_clearcaches(indexObject *self)
640 {
640 {
641 if (self->cache) {
641 if (self->cache) {
642 Py_ssize_t i;
642 Py_ssize_t i;
643
643
644 for (i = 0; i < self->raw_length; i++)
644 for (i = 0; i < self->raw_length; i++)
645 Py_CLEAR(self->cache[i]);
645 Py_CLEAR(self->cache[i]);
646 free(self->cache);
646 free(self->cache);
647 self->cache = NULL;
647 self->cache = NULL;
648 }
648 }
649 if (self->offsets) {
649 if (self->offsets) {
650 free(self->offsets);
650 free(self->offsets);
651 self->offsets = NULL;
651 self->offsets = NULL;
652 }
652 }
653 if (self->nt) {
653 if (self->nt) {
654 free(self->nt);
654 free(self->nt);
655 self->nt = NULL;
655 self->nt = NULL;
656 }
656 }
657 Py_CLEAR(self->headrevs);
657 Py_CLEAR(self->headrevs);
658 }
658 }
659
659
660 static PyObject *index_clearcaches(indexObject *self)
660 static PyObject *index_clearcaches(indexObject *self)
661 {
661 {
662 _index_clearcaches(self);
662 _index_clearcaches(self);
663 self->ntlength = self->ntcapacity = 0;
663 self->ntlength = self->ntcapacity = 0;
664 self->ntdepth = self->ntsplits = 0;
664 self->ntdepth = self->ntsplits = 0;
665 self->ntrev = -1;
665 self->ntrev = -1;
666 self->ntlookups = self->ntmisses = 0;
666 self->ntlookups = self->ntmisses = 0;
667 Py_RETURN_NONE;
667 Py_RETURN_NONE;
668 }
668 }
669
669
670 static PyObject *index_stats(indexObject *self)
670 static PyObject *index_stats(indexObject *self)
671 {
671 {
672 PyObject *obj = PyDict_New();
672 PyObject *obj = PyDict_New();
673
673
674 if (obj == NULL)
674 if (obj == NULL)
675 return NULL;
675 return NULL;
676
676
677 #define istat(__n, __d) \
677 #define istat(__n, __d) \
678 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
678 if (PyDict_SetItemString(obj, __d, PyInt_FromSsize_t(self->__n)) == -1) \
679 goto bail;
679 goto bail;
680
680
681 if (self->added) {
681 if (self->added) {
682 Py_ssize_t len = PyList_GET_SIZE(self->added);
682 Py_ssize_t len = PyList_GET_SIZE(self->added);
683 if (PyDict_SetItemString(obj, "index entries added",
683 if (PyDict_SetItemString(obj, "index entries added",
684 PyInt_FromSsize_t(len)) == -1)
684 PyInt_FromSsize_t(len)) == -1)
685 goto bail;
685 goto bail;
686 }
686 }
687
687
688 if (self->raw_length != self->length - 1)
688 if (self->raw_length != self->length - 1)
689 istat(raw_length, "revs on disk");
689 istat(raw_length, "revs on disk");
690 istat(length, "revs in memory");
690 istat(length, "revs in memory");
691 istat(ntcapacity, "node trie capacity");
691 istat(ntcapacity, "node trie capacity");
692 istat(ntdepth, "node trie depth");
692 istat(ntdepth, "node trie depth");
693 istat(ntlength, "node trie count");
693 istat(ntlength, "node trie count");
694 istat(ntlookups, "node trie lookups");
694 istat(ntlookups, "node trie lookups");
695 istat(ntmisses, "node trie misses");
695 istat(ntmisses, "node trie misses");
696 istat(ntrev, "node trie last rev scanned");
696 istat(ntrev, "node trie last rev scanned");
697 istat(ntsplits, "node trie splits");
697 istat(ntsplits, "node trie splits");
698
698
699 #undef istat
699 #undef istat
700
700
701 return obj;
701 return obj;
702
702
703 bail:
703 bail:
704 Py_XDECREF(obj);
704 Py_XDECREF(obj);
705 return NULL;
705 return NULL;
706 }
706 }
707
707
708 /*
708 /*
709 * When we cache a list, we want to be sure the caller can't mutate
709 * When we cache a list, we want to be sure the caller can't mutate
710 * the cached copy.
710 * the cached copy.
711 */
711 */
712 static PyObject *list_copy(PyObject *list)
712 static PyObject *list_copy(PyObject *list)
713 {
713 {
714 Py_ssize_t len = PyList_GET_SIZE(list);
714 Py_ssize_t len = PyList_GET_SIZE(list);
715 PyObject *newlist = PyList_New(len);
715 PyObject *newlist = PyList_New(len);
716 Py_ssize_t i;
716 Py_ssize_t i;
717
717
718 if (newlist == NULL)
718 if (newlist == NULL)
719 return NULL;
719 return NULL;
720
720
721 for (i = 0; i < len; i++) {
721 for (i = 0; i < len; i++) {
722 PyObject *obj = PyList_GET_ITEM(list, i);
722 PyObject *obj = PyList_GET_ITEM(list, i);
723 Py_INCREF(obj);
723 Py_INCREF(obj);
724 PyList_SET_ITEM(newlist, i, obj);
724 PyList_SET_ITEM(newlist, i, obj);
725 }
725 }
726
726
727 return newlist;
727 return newlist;
728 }
728 }
729
729
730 static PyObject *index_headrevs(indexObject *self)
730 static PyObject *index_headrevs(indexObject *self)
731 {
731 {
732 Py_ssize_t i, len, addlen;
732 Py_ssize_t i, len, addlen;
733 char *nothead = NULL;
733 char *nothead = NULL;
734 PyObject *heads;
734 PyObject *heads;
735
735
736 if (self->headrevs)
736 if (self->headrevs)
737 return list_copy(self->headrevs);
737 return list_copy(self->headrevs);
738
738
739 len = index_length(self) - 1;
739 len = index_length(self) - 1;
740 heads = PyList_New(0);
740 heads = PyList_New(0);
741 if (heads == NULL)
741 if (heads == NULL)
742 goto bail;
742 goto bail;
743 if (len == 0) {
743 if (len == 0) {
744 PyObject *nullid = PyInt_FromLong(-1);
744 PyObject *nullid = PyInt_FromLong(-1);
745 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
745 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
746 Py_XDECREF(nullid);
746 Py_XDECREF(nullid);
747 goto bail;
747 goto bail;
748 }
748 }
749 goto done;
749 goto done;
750 }
750 }
751
751
752 nothead = calloc(len, 1);
752 nothead = calloc(len, 1);
753 if (nothead == NULL)
753 if (nothead == NULL)
754 goto bail;
754 goto bail;
755
755
756 for (i = 0; i < self->raw_length; i++) {
756 for (i = 0; i < self->raw_length; i++) {
757 const char *data = index_deref(self, i);
757 const char *data = index_deref(self, i);
758 int parent_1 = getbe32(data + 24);
758 int parent_1 = getbe32(data + 24);
759 int parent_2 = getbe32(data + 28);
759 int parent_2 = getbe32(data + 28);
760 if (parent_1 >= 0)
760 if (parent_1 >= 0)
761 nothead[parent_1] = 1;
761 nothead[parent_1] = 1;
762 if (parent_2 >= 0)
762 if (parent_2 >= 0)
763 nothead[parent_2] = 1;
763 nothead[parent_2] = 1;
764 }
764 }
765
765
766 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
766 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
767
767
768 for (i = 0; i < addlen; i++) {
768 for (i = 0; i < addlen; i++) {
769 PyObject *rev = PyList_GET_ITEM(self->added, i);
769 PyObject *rev = PyList_GET_ITEM(self->added, i);
770 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
770 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
771 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
771 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
772 long parent_1, parent_2;
772 long parent_1, parent_2;
773
773
774 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
774 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
775 PyErr_SetString(PyExc_TypeError,
775 PyErr_SetString(PyExc_TypeError,
776 "revlog parents are invalid");
776 "revlog parents are invalid");
777 goto bail;
777 goto bail;
778 }
778 }
779 parent_1 = PyInt_AS_LONG(p1);
779 parent_1 = PyInt_AS_LONG(p1);
780 parent_2 = PyInt_AS_LONG(p2);
780 parent_2 = PyInt_AS_LONG(p2);
781 if (parent_1 >= 0)
781 if (parent_1 >= 0)
782 nothead[parent_1] = 1;
782 nothead[parent_1] = 1;
783 if (parent_2 >= 0)
783 if (parent_2 >= 0)
784 nothead[parent_2] = 1;
784 nothead[parent_2] = 1;
785 }
785 }
786
786
787 for (i = 0; i < len; i++) {
787 for (i = 0; i < len; i++) {
788 PyObject *head;
788 PyObject *head;
789
789
790 if (nothead[i])
790 if (nothead[i])
791 continue;
791 continue;
792 head = PyInt_FromLong(i);
792 head = PyInt_FromLong(i);
793 if (head == NULL || PyList_Append(heads, head) == -1) {
793 if (head == NULL || PyList_Append(heads, head) == -1) {
794 Py_XDECREF(head);
794 Py_XDECREF(head);
795 goto bail;
795 goto bail;
796 }
796 }
797 }
797 }
798
798
799 done:
799 done:
800 self->headrevs = heads;
800 self->headrevs = heads;
801 free(nothead);
801 free(nothead);
802 return list_copy(self->headrevs);
802 return list_copy(self->headrevs);
803 bail:
803 bail:
804 Py_XDECREF(heads);
804 Py_XDECREF(heads);
805 free(nothead);
805 free(nothead);
806 return NULL;
806 return NULL;
807 }
807 }
808
808
809 static inline int nt_level(const char *node, Py_ssize_t level)
809 static inline int nt_level(const char *node, Py_ssize_t level)
810 {
810 {
811 int v = node[level>>1];
811 int v = node[level>>1];
812 if (!(level & 1))
812 if (!(level & 1))
813 v >>= 4;
813 v >>= 4;
814 return v & 0xf;
814 return v & 0xf;
815 }
815 }
816
816
817 /*
817 /*
818 * Return values:
818 * Return values:
819 *
819 *
820 * -4: match is ambiguous (multiple candidates)
820 * -4: match is ambiguous (multiple candidates)
821 * -2: not found
821 * -2: not found
822 * rest: valid rev
822 * rest: valid rev
823 */
823 */
824 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
824 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
825 int hex)
825 int hex)
826 {
826 {
827 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
827 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
828 int level, maxlevel, off;
828 int level, maxlevel, off;
829
829
830 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
830 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
831 return -1;
831 return -1;
832
832
833 if (self->nt == NULL)
833 if (self->nt == NULL)
834 return -2;
834 return -2;
835
835
836 if (hex)
836 if (hex)
837 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
837 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
838 else
838 else
839 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
839 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
840
840
841 for (level = off = 0; level < maxlevel; level++) {
841 for (level = off = 0; level < maxlevel; level++) {
842 int k = getnybble(node, level);
842 int k = getnybble(node, level);
843 nodetree *n = &self->nt[off];
843 nodetree *n = &self->nt[off];
844 int v = n->children[k];
844 int v = n->children[k];
845
845
846 if (v < 0) {
846 if (v < 0) {
847 const char *n;
847 const char *n;
848 Py_ssize_t i;
848 Py_ssize_t i;
849
849
850 v = -v - 1;
850 v = -v - 1;
851 n = index_node(self, v);
851 n = index_node(self, v);
852 if (n == NULL)
852 if (n == NULL)
853 return -2;
853 return -2;
854 for (i = level; i < maxlevel; i++)
854 for (i = level; i < maxlevel; i++)
855 if (getnybble(node, i) != nt_level(n, i))
855 if (getnybble(node, i) != nt_level(n, i))
856 return -2;
856 return -2;
857 return v;
857 return v;
858 }
858 }
859 if (v == 0)
859 if (v == 0)
860 return -2;
860 return -2;
861 off = v;
861 off = v;
862 }
862 }
863 /* multiple matches against an ambiguous prefix */
863 /* multiple matches against an ambiguous prefix */
864 return -4;
864 return -4;
865 }
865 }
866
866
867 static int nt_new(indexObject *self)
867 static int nt_new(indexObject *self)
868 {
868 {
869 if (self->ntlength == self->ntcapacity) {
869 if (self->ntlength == self->ntcapacity) {
870 self->ntcapacity *= 2;
870 self->ntcapacity *= 2;
871 self->nt = realloc(self->nt,
871 self->nt = realloc(self->nt,
872 self->ntcapacity * sizeof(nodetree));
872 self->ntcapacity * sizeof(nodetree));
873 if (self->nt == NULL) {
873 if (self->nt == NULL) {
874 PyErr_SetString(PyExc_MemoryError, "out of memory");
874 PyErr_SetString(PyExc_MemoryError, "out of memory");
875 return -1;
875 return -1;
876 }
876 }
877 memset(&self->nt[self->ntlength], 0,
877 memset(&self->nt[self->ntlength], 0,
878 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
878 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
879 }
879 }
880 return self->ntlength++;
880 return self->ntlength++;
881 }
881 }
882
882
883 static int nt_insert(indexObject *self, const char *node, int rev)
883 static int nt_insert(indexObject *self, const char *node, int rev)
884 {
884 {
885 int level = 0;
885 int level = 0;
886 int off = 0;
886 int off = 0;
887
887
888 while (level < 40) {
888 while (level < 40) {
889 int k = nt_level(node, level);
889 int k = nt_level(node, level);
890 nodetree *n;
890 nodetree *n;
891 int v;
891 int v;
892
892
893 n = &self->nt[off];
893 n = &self->nt[off];
894 v = n->children[k];
894 v = n->children[k];
895
895
896 if (v == 0) {
896 if (v == 0) {
897 n->children[k] = -rev - 1;
897 n->children[k] = -rev - 1;
898 return 0;
898 return 0;
899 }
899 }
900 if (v < 0) {
900 if (v < 0) {
901 const char *oldnode = index_node(self, -v - 1);
901 const char *oldnode = index_node(self, -v - 1);
902 int noff;
902 int noff;
903
903
904 if (!oldnode || !memcmp(oldnode, node, 20)) {
904 if (!oldnode || !memcmp(oldnode, node, 20)) {
905 n->children[k] = -rev - 1;
905 n->children[k] = -rev - 1;
906 return 0;
906 return 0;
907 }
907 }
908 noff = nt_new(self);
908 noff = nt_new(self);
909 if (noff == -1)
909 if (noff == -1)
910 return -1;
910 return -1;
911 /* self->nt may have been changed by realloc */
911 /* self->nt may have been changed by realloc */
912 self->nt[off].children[k] = noff;
912 self->nt[off].children[k] = noff;
913 off = noff;
913 off = noff;
914 n = &self->nt[off];
914 n = &self->nt[off];
915 n->children[nt_level(oldnode, ++level)] = v;
915 n->children[nt_level(oldnode, ++level)] = v;
916 if (level > self->ntdepth)
916 if (level > self->ntdepth)
917 self->ntdepth = level;
917 self->ntdepth = level;
918 self->ntsplits += 1;
918 self->ntsplits += 1;
919 } else {
919 } else {
920 level += 1;
920 level += 1;
921 off = v;
921 off = v;
922 }
922 }
923 }
923 }
924
924
925 return -1;
925 return -1;
926 }
926 }
927
927
928 static int nt_init(indexObject *self)
928 static int nt_init(indexObject *self)
929 {
929 {
930 if (self->nt == NULL) {
930 if (self->nt == NULL) {
931 if (self->raw_length > INT_MAX) {
931 if (self->raw_length > INT_MAX) {
932 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
932 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
933 return -1;
933 return -1;
934 }
934 }
935 self->ntcapacity = self->raw_length < 4
935 self->ntcapacity = self->raw_length < 4
936 ? 4 : (int)self->raw_length / 2;
936 ? 4 : (int)self->raw_length / 2;
937
937
938 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
938 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
939 if (self->nt == NULL) {
939 if (self->nt == NULL) {
940 PyErr_NoMemory();
940 PyErr_NoMemory();
941 return -1;
941 return -1;
942 }
942 }
943 self->ntlength = 1;
943 self->ntlength = 1;
944 self->ntrev = (int)index_length(self) - 1;
944 self->ntrev = (int)index_length(self) - 1;
945 self->ntlookups = 1;
945 self->ntlookups = 1;
946 self->ntmisses = 0;
946 self->ntmisses = 0;
947 if (nt_insert(self, nullid, INT_MAX) == -1)
947 if (nt_insert(self, nullid, INT_MAX) == -1)
948 return -1;
948 return -1;
949 }
949 }
950 return 0;
950 return 0;
951 }
951 }
952
952
953 /*
953 /*
954 * Return values:
954 * Return values:
955 *
955 *
956 * -3: error (exception set)
956 * -3: error (exception set)
957 * -2: not found (no exception set)
957 * -2: not found (no exception set)
958 * rest: valid rev
958 * rest: valid rev
959 */
959 */
960 static int index_find_node(indexObject *self,
960 static int index_find_node(indexObject *self,
961 const char *node, Py_ssize_t nodelen)
961 const char *node, Py_ssize_t nodelen)
962 {
962 {
963 int rev;
963 int rev;
964
964
965 self->ntlookups++;
965 self->ntlookups++;
966 rev = nt_find(self, node, nodelen, 0);
966 rev = nt_find(self, node, nodelen, 0);
967 if (rev >= -1)
967 if (rev >= -1)
968 return rev;
968 return rev;
969
969
970 if (nt_init(self) == -1)
970 if (nt_init(self) == -1)
971 return -3;
971 return -3;
972
972
973 /*
973 /*
974 * For the first handful of lookups, we scan the entire index,
974 * For the first handful of lookups, we scan the entire index,
975 * and cache only the matching nodes. This optimizes for cases
975 * and cache only the matching nodes. This optimizes for cases
976 * like "hg tip", where only a few nodes are accessed.
976 * like "hg tip", where only a few nodes are accessed.
977 *
977 *
978 * After that, we cache every node we visit, using a single
978 * After that, we cache every node we visit, using a single
979 * scan amortized over multiple lookups. This gives the best
979 * scan amortized over multiple lookups. This gives the best
980 * bulk performance, e.g. for "hg log".
980 * bulk performance, e.g. for "hg log".
981 */
981 */
982 if (self->ntmisses++ < 4) {
982 if (self->ntmisses++ < 4) {
983 for (rev = self->ntrev - 1; rev >= 0; rev--) {
983 for (rev = self->ntrev - 1; rev >= 0; rev--) {
984 const char *n = index_node(self, rev);
984 const char *n = index_node(self, rev);
985 if (n == NULL)
985 if (n == NULL)
986 return -2;
986 return -2;
987 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
987 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
988 if (nt_insert(self, n, rev) == -1)
988 if (nt_insert(self, n, rev) == -1)
989 return -3;
989 return -3;
990 break;
990 break;
991 }
991 }
992 }
992 }
993 } else {
993 } else {
994 for (rev = self->ntrev - 1; rev >= 0; rev--) {
994 for (rev = self->ntrev - 1; rev >= 0; rev--) {
995 const char *n = index_node(self, rev);
995 const char *n = index_node(self, rev);
996 if (n == NULL) {
996 if (n == NULL) {
997 self->ntrev = rev + 1;
997 self->ntrev = rev + 1;
998 return -2;
998 return -2;
999 }
999 }
1000 if (nt_insert(self, n, rev) == -1) {
1000 if (nt_insert(self, n, rev) == -1) {
1001 self->ntrev = rev + 1;
1001 self->ntrev = rev + 1;
1002 return -3;
1002 return -3;
1003 }
1003 }
1004 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1004 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1005 break;
1005 break;
1006 }
1006 }
1007 }
1007 }
1008 self->ntrev = rev;
1008 self->ntrev = rev;
1009 }
1009 }
1010
1010
1011 if (rev >= 0)
1011 if (rev >= 0)
1012 return rev;
1012 return rev;
1013 return -2;
1013 return -2;
1014 }
1014 }
1015
1015
1016 static PyObject *raise_revlog_error(void)
1016 static PyObject *raise_revlog_error(void)
1017 {
1017 {
1018 static PyObject *errclass;
1018 static PyObject *errclass;
1019 PyObject *mod = NULL, *errobj;
1019 PyObject *mod = NULL, *errobj;
1020
1020
1021 if (errclass == NULL) {
1021 if (errclass == NULL) {
1022 PyObject *dict;
1022 PyObject *dict;
1023
1023
1024 mod = PyImport_ImportModule("mercurial.error");
1024 mod = PyImport_ImportModule("mercurial.error");
1025 if (mod == NULL)
1025 if (mod == NULL)
1026 goto classfail;
1026 goto classfail;
1027
1027
1028 dict = PyModule_GetDict(mod);
1028 dict = PyModule_GetDict(mod);
1029 if (dict == NULL)
1029 if (dict == NULL)
1030 goto classfail;
1030 goto classfail;
1031
1031
1032 errclass = PyDict_GetItemString(dict, "RevlogError");
1032 errclass = PyDict_GetItemString(dict, "RevlogError");
1033 if (errclass == NULL) {
1033 if (errclass == NULL) {
1034 PyErr_SetString(PyExc_SystemError,
1034 PyErr_SetString(PyExc_SystemError,
1035 "could not find RevlogError");
1035 "could not find RevlogError");
1036 goto classfail;
1036 goto classfail;
1037 }
1037 }
1038 Py_INCREF(errclass);
1038 Py_INCREF(errclass);
1039 }
1039 }
1040
1040
1041 errobj = PyObject_CallFunction(errclass, NULL);
1041 errobj = PyObject_CallFunction(errclass, NULL);
1042 if (errobj == NULL)
1042 if (errobj == NULL)
1043 return NULL;
1043 return NULL;
1044 PyErr_SetObject(errclass, errobj);
1044 PyErr_SetObject(errclass, errobj);
1045 return errobj;
1045 return errobj;
1046
1046
1047 classfail:
1047 classfail:
1048 Py_XDECREF(mod);
1048 Py_XDECREF(mod);
1049 return NULL;
1049 return NULL;
1050 }
1050 }
1051
1051
1052 static PyObject *index_getitem(indexObject *self, PyObject *value)
1052 static PyObject *index_getitem(indexObject *self, PyObject *value)
1053 {
1053 {
1054 char *node;
1054 char *node;
1055 Py_ssize_t nodelen;
1055 Py_ssize_t nodelen;
1056 int rev;
1056 int rev;
1057
1057
1058 if (PyInt_Check(value))
1058 if (PyInt_Check(value))
1059 return index_get(self, PyInt_AS_LONG(value));
1059 return index_get(self, PyInt_AS_LONG(value));
1060
1060
1061 if (node_check(value, &node, &nodelen) == -1)
1061 if (node_check(value, &node, &nodelen) == -1)
1062 return NULL;
1062 return NULL;
1063 rev = index_find_node(self, node, nodelen);
1063 rev = index_find_node(self, node, nodelen);
1064 if (rev >= -1)
1064 if (rev >= -1)
1065 return PyInt_FromLong(rev);
1065 return PyInt_FromLong(rev);
1066 if (rev == -2)
1066 if (rev == -2)
1067 raise_revlog_error();
1067 raise_revlog_error();
1068 return NULL;
1068 return NULL;
1069 }
1069 }
1070
1070
1071 static int nt_partialmatch(indexObject *self, const char *node,
1071 static int nt_partialmatch(indexObject *self, const char *node,
1072 Py_ssize_t nodelen)
1072 Py_ssize_t nodelen)
1073 {
1073 {
1074 int rev;
1074 int rev;
1075
1075
1076 if (nt_init(self) == -1)
1076 if (nt_init(self) == -1)
1077 return -3;
1077 return -3;
1078
1078
1079 if (self->ntrev > 0) {
1079 if (self->ntrev > 0) {
1080 /* ensure that the radix tree is fully populated */
1080 /* ensure that the radix tree is fully populated */
1081 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1081 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1082 const char *n = index_node(self, rev);
1082 const char *n = index_node(self, rev);
1083 if (n == NULL)
1083 if (n == NULL)
1084 return -2;
1084 return -2;
1085 if (nt_insert(self, n, rev) == -1)
1085 if (nt_insert(self, n, rev) == -1)
1086 return -3;
1086 return -3;
1087 }
1087 }
1088 self->ntrev = rev;
1088 self->ntrev = rev;
1089 }
1089 }
1090
1090
1091 return nt_find(self, node, nodelen, 1);
1091 return nt_find(self, node, nodelen, 1);
1092 }
1092 }
1093
1093
1094 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1094 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1095 {
1095 {
1096 const char *fullnode;
1096 const char *fullnode;
1097 int nodelen;
1097 int nodelen;
1098 char *node;
1098 char *node;
1099 int rev, i;
1099 int rev, i;
1100
1100
1101 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1101 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1102 return NULL;
1102 return NULL;
1103
1103
1104 if (nodelen < 4) {
1104 if (nodelen < 4) {
1105 PyErr_SetString(PyExc_ValueError, "key too short");
1105 PyErr_SetString(PyExc_ValueError, "key too short");
1106 return NULL;
1106 return NULL;
1107 }
1107 }
1108
1108
1109 if (nodelen > 40) {
1109 if (nodelen > 40) {
1110 PyErr_SetString(PyExc_ValueError, "key too long");
1110 PyErr_SetString(PyExc_ValueError, "key too long");
1111 return NULL;
1111 return NULL;
1112 }
1112 }
1113
1113
1114 for (i = 0; i < nodelen; i++)
1114 for (i = 0; i < nodelen; i++)
1115 hexdigit(node, i);
1115 hexdigit(node, i);
1116 if (PyErr_Occurred()) {
1116 if (PyErr_Occurred()) {
1117 /* input contains non-hex characters */
1117 /* input contains non-hex characters */
1118 PyErr_Clear();
1118 PyErr_Clear();
1119 Py_RETURN_NONE;
1119 Py_RETURN_NONE;
1120 }
1120 }
1121
1121
1122 rev = nt_partialmatch(self, node, nodelen);
1122 rev = nt_partialmatch(self, node, nodelen);
1123
1123
1124 switch (rev) {
1124 switch (rev) {
1125 case -4:
1125 case -4:
1126 raise_revlog_error();
1126 raise_revlog_error();
1127 case -3:
1127 case -3:
1128 return NULL;
1128 return NULL;
1129 case -2:
1129 case -2:
1130 Py_RETURN_NONE;
1130 Py_RETURN_NONE;
1131 case -1:
1131 case -1:
1132 return PyString_FromStringAndSize(nullid, 20);
1132 return PyString_FromStringAndSize(nullid, 20);
1133 }
1133 }
1134
1134
1135 fullnode = index_node(self, rev);
1135 fullnode = index_node(self, rev);
1136 if (fullnode == NULL) {
1136 if (fullnode == NULL) {
1137 PyErr_Format(PyExc_IndexError,
1137 PyErr_Format(PyExc_IndexError,
1138 "could not access rev %d", rev);
1138 "could not access rev %d", rev);
1139 return NULL;
1139 return NULL;
1140 }
1140 }
1141 return PyString_FromStringAndSize(fullnode, 20);
1141 return PyString_FromStringAndSize(fullnode, 20);
1142 }
1142 }
1143
1143
1144 static PyObject *index_m_get(indexObject *self, PyObject *args)
1144 static PyObject *index_m_get(indexObject *self, PyObject *args)
1145 {
1145 {
1146 Py_ssize_t nodelen;
1146 Py_ssize_t nodelen;
1147 PyObject *val;
1147 PyObject *val;
1148 char *node;
1148 char *node;
1149 int rev;
1149 int rev;
1150
1150
1151 if (!PyArg_ParseTuple(args, "O", &val))
1151 if (!PyArg_ParseTuple(args, "O", &val))
1152 return NULL;
1152 return NULL;
1153 if (node_check(val, &node, &nodelen) == -1)
1153 if (node_check(val, &node, &nodelen) == -1)
1154 return NULL;
1154 return NULL;
1155 rev = index_find_node(self, node, nodelen);
1155 rev = index_find_node(self, node, nodelen);
1156 if (rev == -3)
1156 if (rev == -3)
1157 return NULL;
1157 return NULL;
1158 if (rev == -2)
1158 if (rev == -2)
1159 Py_RETURN_NONE;
1159 Py_RETURN_NONE;
1160 return PyInt_FromLong(rev);
1160 return PyInt_FromLong(rev);
1161 }
1161 }
1162
1162
1163 static int index_contains(indexObject *self, PyObject *value)
1163 static int index_contains(indexObject *self, PyObject *value)
1164 {
1164 {
1165 char *node;
1165 char *node;
1166 Py_ssize_t nodelen;
1166 Py_ssize_t nodelen;
1167
1167
1168 if (PyInt_Check(value)) {
1168 if (PyInt_Check(value)) {
1169 long rev = PyInt_AS_LONG(value);
1169 long rev = PyInt_AS_LONG(value);
1170 return rev >= -1 && rev < index_length(self);
1170 return rev >= -1 && rev < index_length(self);
1171 }
1171 }
1172
1172
1173 if (node_check(value, &node, &nodelen) == -1)
1173 if (node_check(value, &node, &nodelen) == -1)
1174 return -1;
1174 return -1;
1175
1175
1176 switch (index_find_node(self, node, nodelen)) {
1176 switch (index_find_node(self, node, nodelen)) {
1177 case -3:
1177 case -3:
1178 return -1;
1178 return -1;
1179 case -2:
1179 case -2:
1180 return 0;
1180 return 0;
1181 default:
1181 default:
1182 return 1;
1182 return 1;
1183 }
1183 }
1184 }
1184 }
1185
1185
1186 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1186 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1187 {
1187 {
1188 if (rev >= self->length - 1) {
1188 if (rev >= self->length - 1) {
1189 PyObject *tuple = PyList_GET_ITEM(self->added,
1189 PyObject *tuple = PyList_GET_ITEM(self->added,
1190 rev - self->length + 1);
1190 rev - self->length + 1);
1191 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1191 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1192 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1192 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1193 } else {
1193 } else {
1194 const char *data = index_deref(self, rev);
1194 const char *data = index_deref(self, rev);
1195 ps[0] = getbe32(data + 24);
1195 ps[0] = getbe32(data + 24);
1196 ps[1] = getbe32(data + 28);
1196 ps[1] = getbe32(data + 28);
1197 }
1197 }
1198 }
1198 }
1199
1199
1200 typedef uint64_t bitmask;
1200 typedef uint64_t bitmask;
1201
1201
1202 /*
1202 /*
1203 * Given a disjoint set of revs, return all candidates for the
1203 * Given a disjoint set of revs, return all candidates for the
1204 * greatest common ancestor. In revset notation, this is the set
1204 * greatest common ancestor. In revset notation, this is the set
1205 * "heads(::a and ::b and ...)"
1205 * "heads(::a and ::b and ...)"
1206 */
1206 */
1207 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1207 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1208 int revcount)
1208 int revcount)
1209 {
1209 {
1210 const bitmask allseen = (1ull << revcount) - 1;
1210 const bitmask allseen = (1ull << revcount) - 1;
1211 const bitmask poison = 1ull << revcount;
1211 const bitmask poison = 1ull << revcount;
1212 PyObject *gca = PyList_New(0);
1212 PyObject *gca = PyList_New(0);
1213 int i, v, interesting;
1213 int i, v, interesting;
1214 int maxrev = -1;
1214 int maxrev = -1;
1215 long sp;
1215 long sp;
1216 bitmask *seen;
1216 bitmask *seen;
1217
1217
1218 if (gca == NULL)
1218 if (gca == NULL)
1219 return PyErr_NoMemory();
1219 return PyErr_NoMemory();
1220
1220
1221 for (i = 0; i < revcount; i++) {
1221 for (i = 0; i < revcount; i++) {
1222 if (revs[i] > maxrev)
1222 if (revs[i] > maxrev)
1223 maxrev = revs[i];
1223 maxrev = revs[i];
1224 }
1224 }
1225
1225
1226 seen = calloc(sizeof(*seen), maxrev + 1);
1226 seen = calloc(sizeof(*seen), maxrev + 1);
1227 if (seen == NULL) {
1227 if (seen == NULL) {
1228 Py_DECREF(gca);
1228 Py_DECREF(gca);
1229 return PyErr_NoMemory();
1229 return PyErr_NoMemory();
1230 }
1230 }
1231
1231
1232 for (i = 0; i < revcount; i++)
1232 for (i = 0; i < revcount; i++)
1233 seen[revs[i]] = 1ull << i;
1233 seen[revs[i]] = 1ull << i;
1234
1234
1235 interesting = revcount;
1235 interesting = revcount;
1236
1236
1237 for (v = maxrev; v >= 0 && interesting; v--) {
1237 for (v = maxrev; v >= 0 && interesting; v--) {
1238 long sv = seen[v];
1238 long sv = seen[v];
1239 int parents[2];
1239 int parents[2];
1240
1240
1241 if (!sv)
1241 if (!sv)
1242 continue;
1242 continue;
1243
1243
1244 if (sv < poison) {
1244 if (sv < poison) {
1245 interesting -= 1;
1245 interesting -= 1;
1246 if (sv == allseen) {
1246 if (sv == allseen) {
1247 PyObject *obj = PyInt_FromLong(v);
1247 PyObject *obj = PyInt_FromLong(v);
1248 if (obj == NULL)
1248 if (obj == NULL)
1249 goto bail;
1249 goto bail;
1250 if (PyList_Append(gca, obj) == -1) {
1250 if (PyList_Append(gca, obj) == -1) {
1251 Py_DECREF(obj);
1251 Py_DECREF(obj);
1252 goto bail;
1252 goto bail;
1253 }
1253 }
1254 sv |= poison;
1254 sv |= poison;
1255 for (i = 0; i < revcount; i++) {
1255 for (i = 0; i < revcount; i++) {
1256 if (revs[i] == v)
1256 if (revs[i] == v)
1257 goto done;
1257 goto done;
1258 }
1258 }
1259 }
1259 }
1260 }
1260 }
1261 index_get_parents(self, v, parents);
1261 index_get_parents(self, v, parents);
1262
1262
1263 for (i = 0; i < 2; i++) {
1263 for (i = 0; i < 2; i++) {
1264 int p = parents[i];
1264 int p = parents[i];
1265 if (p == -1)
1265 if (p == -1)
1266 continue;
1266 continue;
1267 sp = seen[p];
1267 sp = seen[p];
1268 if (sv < poison) {
1268 if (sv < poison) {
1269 if (sp == 0) {
1269 if (sp == 0) {
1270 seen[p] = sv;
1270 seen[p] = sv;
1271 interesting++;
1271 interesting++;
1272 }
1272 }
1273 else if (sp != sv)
1273 else if (sp != sv)
1274 seen[p] |= sv;
1274 seen[p] |= sv;
1275 } else {
1275 } else {
1276 if (sp && sp < poison)
1276 if (sp && sp < poison)
1277 interesting--;
1277 interesting--;
1278 seen[p] = sv;
1278 seen[p] = sv;
1279 }
1279 }
1280 }
1280 }
1281 }
1281 }
1282
1282
1283 done:
1283 done:
1284 free(seen);
1284 free(seen);
1285 return gca;
1285 return gca;
1286 bail:
1286 bail:
1287 free(seen);
1287 free(seen);
1288 Py_XDECREF(gca);
1288 Py_XDECREF(gca);
1289 return NULL;
1289 return NULL;
1290 }
1290 }
1291
1291
1292 /*
1292 /*
1293 * Given a disjoint set of revs, return the subset with the longest
1293 * Given a disjoint set of revs, return the subset with the longest
1294 * path to the root.
1294 * path to the root.
1295 */
1295 */
1296 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1296 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1297 {
1297 {
1298 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1298 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1299 static const Py_ssize_t capacity = 24;
1299 static const Py_ssize_t capacity = 24;
1300 int *depth, *interesting = NULL;
1300 int *depth, *interesting = NULL;
1301 int i, j, v, ninteresting;
1301 int i, j, v, ninteresting;
1302 PyObject *dict = NULL, *keys;
1302 PyObject *dict = NULL, *keys;
1303 long *seen = NULL;
1303 long *seen = NULL;
1304 int maxrev = -1;
1304 int maxrev = -1;
1305 long final;
1305 long final;
1306
1306
1307 if (revcount > capacity) {
1307 if (revcount > capacity) {
1308 PyErr_Format(PyExc_OverflowError,
1308 PyErr_Format(PyExc_OverflowError,
1309 "bitset size (%ld) > capacity (%ld)",
1309 "bitset size (%ld) > capacity (%ld)",
1310 (long)revcount, (long)capacity);
1310 (long)revcount, (long)capacity);
1311 return NULL;
1311 return NULL;
1312 }
1312 }
1313
1313
1314 for (i = 0; i < revcount; i++) {
1314 for (i = 0; i < revcount; i++) {
1315 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1315 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1316 if (n > maxrev)
1316 if (n > maxrev)
1317 maxrev = n;
1317 maxrev = n;
1318 }
1318 }
1319
1319
1320 depth = calloc(sizeof(*depth), maxrev + 1);
1320 depth = calloc(sizeof(*depth), maxrev + 1);
1321 if (depth == NULL)
1321 if (depth == NULL)
1322 return PyErr_NoMemory();
1322 return PyErr_NoMemory();
1323
1323
1324 seen = calloc(sizeof(*seen), maxrev + 1);
1324 seen = calloc(sizeof(*seen), maxrev + 1);
1325 if (seen == NULL) {
1325 if (seen == NULL) {
1326 PyErr_NoMemory();
1326 PyErr_NoMemory();
1327 goto bail;
1327 goto bail;
1328 }
1328 }
1329
1329
1330 interesting = calloc(sizeof(*interesting), 2 << revcount);
1330 interesting = calloc(sizeof(*interesting), 2 << revcount);
1331 if (interesting == NULL) {
1331 if (interesting == NULL) {
1332 PyErr_NoMemory();
1332 PyErr_NoMemory();
1333 goto bail;
1333 goto bail;
1334 }
1334 }
1335
1335
1336 if (PyList_Sort(revs) == -1)
1336 if (PyList_Sort(revs) == -1)
1337 goto bail;
1337 goto bail;
1338
1338
1339 for (i = 0; i < revcount; i++) {
1339 for (i = 0; i < revcount; i++) {
1340 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1340 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1341 long b = 1l << i;
1341 long b = 1l << i;
1342 depth[n] = 1;
1342 depth[n] = 1;
1343 seen[n] = b;
1343 seen[n] = b;
1344 interesting[b] = 1;
1344 interesting[b] = 1;
1345 }
1345 }
1346
1346
1347 ninteresting = (int)revcount;
1347 ninteresting = (int)revcount;
1348
1348
1349 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1349 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1350 int dv = depth[v];
1350 int dv = depth[v];
1351 int parents[2];
1351 int parents[2];
1352 long sv;
1352 long sv;
1353
1353
1354 if (dv == 0)
1354 if (dv == 0)
1355 continue;
1355 continue;
1356
1356
1357 sv = seen[v];
1357 sv = seen[v];
1358 index_get_parents(self, v, parents);
1358 index_get_parents(self, v, parents);
1359
1359
1360 for (i = 0; i < 2; i++) {
1360 for (i = 0; i < 2; i++) {
1361 int p = parents[i];
1361 int p = parents[i];
1362 long nsp, sp;
1362 long nsp, sp;
1363 int dp;
1363 int dp;
1364
1364
1365 if (p == -1)
1365 if (p == -1)
1366 continue;
1366 continue;
1367
1367
1368 dp = depth[p];
1368 dp = depth[p];
1369 nsp = sp = seen[p];
1369 nsp = sp = seen[p];
1370 if (dp <= dv) {
1370 if (dp <= dv) {
1371 depth[p] = dv + 1;
1371 depth[p] = dv + 1;
1372 if (sp != sv) {
1372 if (sp != sv) {
1373 interesting[sv] += 1;
1373 interesting[sv] += 1;
1374 nsp = seen[p] = sv;
1374 nsp = seen[p] = sv;
1375 if (sp) {
1375 if (sp) {
1376 interesting[sp] -= 1;
1376 interesting[sp] -= 1;
1377 if (interesting[sp] == 0)
1377 if (interesting[sp] == 0)
1378 ninteresting -= 1;
1378 ninteresting -= 1;
1379 }
1379 }
1380 }
1380 }
1381 }
1381 }
1382 else if (dv == dp - 1) {
1382 else if (dv == dp - 1) {
1383 nsp = sp | sv;
1383 nsp = sp | sv;
1384 if (nsp == sp)
1384 if (nsp == sp)
1385 continue;
1385 continue;
1386 seen[p] = nsp;
1386 seen[p] = nsp;
1387 interesting[sp] -= 1;
1387 interesting[sp] -= 1;
1388 if (interesting[sp] == 0 && interesting[nsp] > 0)
1388 if (interesting[sp] == 0 && interesting[nsp] > 0)
1389 ninteresting -= 1;
1389 ninteresting -= 1;
1390 interesting[nsp] += 1;
1390 interesting[nsp] += 1;
1391 }
1391 }
1392 }
1392 }
1393 interesting[sv] -= 1;
1393 interesting[sv] -= 1;
1394 if (interesting[sv] == 0)
1394 if (interesting[sv] == 0)
1395 ninteresting -= 1;
1395 ninteresting -= 1;
1396 }
1396 }
1397
1397
1398 final = 0;
1398 final = 0;
1399 j = ninteresting;
1399 j = ninteresting;
1400 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1400 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1401 if (interesting[i] == 0)
1401 if (interesting[i] == 0)
1402 continue;
1402 continue;
1403 final |= i;
1403 final |= i;
1404 j -= 1;
1404 j -= 1;
1405 }
1405 }
1406 if (final == 0)
1406 if (final == 0)
1407 return PyList_New(0);
1407 return PyList_New(0);
1408
1408
1409 dict = PyDict_New();
1409 dict = PyDict_New();
1410 if (dict == NULL)
1410 if (dict == NULL)
1411 goto bail;
1411 goto bail;
1412
1412
1413 for (i = 0; i < revcount; i++) {
1413 for (i = 0; i < revcount; i++) {
1414 PyObject *key;
1414 PyObject *key;
1415
1415
1416 if ((final & (1 << i)) == 0)
1416 if ((final & (1 << i)) == 0)
1417 continue;
1417 continue;
1418
1418
1419 key = PyList_GET_ITEM(revs, i);
1419 key = PyList_GET_ITEM(revs, i);
1420 Py_INCREF(key);
1420 Py_INCREF(key);
1421 Py_INCREF(Py_None);
1421 Py_INCREF(Py_None);
1422 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1422 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1423 Py_DECREF(key);
1423 Py_DECREF(key);
1424 Py_DECREF(Py_None);
1424 Py_DECREF(Py_None);
1425 goto bail;
1425 goto bail;
1426 }
1426 }
1427 }
1427 }
1428
1428
1429 keys = PyDict_Keys(dict);
1429 keys = PyDict_Keys(dict);
1430
1430
1431 free(depth);
1431 free(depth);
1432 free(seen);
1432 free(seen);
1433 free(interesting);
1433 free(interesting);
1434 Py_DECREF(dict);
1434 Py_DECREF(dict);
1435
1435
1436 return keys;
1436 return keys;
1437 bail:
1437 bail:
1438 free(depth);
1438 free(depth);
1439 free(seen);
1439 free(seen);
1440 free(interesting);
1440 free(interesting);
1441 Py_XDECREF(dict);
1441 Py_XDECREF(dict);
1442
1442
1443 return NULL;
1443 return NULL;
1444 }
1444 }
1445
1445
1446 /*
1446 /*
1447 * Given a (possibly overlapping) set of revs, return the greatest
1447 * Given a (possibly overlapping) set of revs, return the greatest
1448 * common ancestors: those with the longest path to the root.
1448 * common ancestors: those with the longest path to the root.
1449 */
1449 */
1450 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1450 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1451 {
1451 {
1452 PyObject *ret = NULL, *gca = NULL;
1452 PyObject *ret = NULL, *gca = NULL;
1453 Py_ssize_t argcount, i, len;
1453 Py_ssize_t argcount, i, len;
1454 bitmask repeat = 0;
1454 bitmask repeat = 0;
1455 int revcount = 0;
1455 int revcount = 0;
1456 int *revs;
1456 int *revs;
1457
1457
1458 argcount = PySequence_Length(args);
1458 argcount = PySequence_Length(args);
1459 revs = malloc(argcount * sizeof(*revs));
1459 revs = malloc(argcount * sizeof(*revs));
1460 if (argcount > 0 && revs == NULL)
1460 if (argcount > 0 && revs == NULL)
1461 return PyErr_NoMemory();
1461 return PyErr_NoMemory();
1462 len = index_length(self) - 1;
1462 len = index_length(self) - 1;
1463
1463
1464 for (i = 0; i < argcount; i++) {
1464 for (i = 0; i < argcount; i++) {
1465 static const int capacity = 24;
1465 static const int capacity = 24;
1466 PyObject *obj = PySequence_GetItem(args, i);
1466 PyObject *obj = PySequence_GetItem(args, i);
1467 bitmask x;
1467 bitmask x;
1468 long val;
1468 long val;
1469
1469
1470 if (!PyInt_Check(obj)) {
1470 if (!PyInt_Check(obj)) {
1471 PyErr_SetString(PyExc_TypeError,
1471 PyErr_SetString(PyExc_TypeError,
1472 "arguments must all be ints");
1472 "arguments must all be ints");
1473 goto bail;
1473 goto bail;
1474 }
1474 }
1475 val = PyInt_AsLong(obj);
1475 val = PyInt_AsLong(obj);
1476 if (val == -1) {
1476 if (val == -1) {
1477 ret = PyList_New(0);
1477 ret = PyList_New(0);
1478 goto done;
1478 goto done;
1479 }
1479 }
1480 if (val < 0 || val >= len) {
1480 if (val < 0 || val >= len) {
1481 PyErr_SetString(PyExc_IndexError,
1481 PyErr_SetString(PyExc_IndexError,
1482 "index out of range");
1482 "index out of range");
1483 goto bail;
1483 goto bail;
1484 }
1484 }
1485 /* this cheesy bloom filter lets us avoid some more
1485 /* this cheesy bloom filter lets us avoid some more
1486 * expensive duplicate checks in the common set-is-disjoint
1486 * expensive duplicate checks in the common set-is-disjoint
1487 * case */
1487 * case */
1488 x = 1ull << (val & 0x3f);
1488 x = 1ull << (val & 0x3f);
1489 if (repeat & x) {
1489 if (repeat & x) {
1490 int k;
1490 int k;
1491 for (k = 0; k < revcount; k++) {
1491 for (k = 0; k < revcount; k++) {
1492 if (val == revs[k])
1492 if (val == revs[k])
1493 goto duplicate;
1493 goto duplicate;
1494 }
1494 }
1495 }
1495 }
1496 else repeat |= x;
1496 else repeat |= x;
1497 if (revcount >= capacity) {
1497 if (revcount >= capacity) {
1498 PyErr_Format(PyExc_OverflowError,
1498 PyErr_Format(PyExc_OverflowError,
1499 "bitset size (%d) > capacity (%d)",
1499 "bitset size (%d) > capacity (%d)",
1500 revcount, capacity);
1500 revcount, capacity);
1501 goto bail;
1501 goto bail;
1502 }
1502 }
1503 revs[revcount++] = (int)val;
1503 revs[revcount++] = (int)val;
1504 duplicate:;
1504 duplicate:;
1505 }
1505 }
1506
1506
1507 if (revcount == 0) {
1507 if (revcount == 0) {
1508 ret = PyList_New(0);
1508 ret = PyList_New(0);
1509 goto done;
1509 goto done;
1510 }
1510 }
1511 if (revcount == 1) {
1511 if (revcount == 1) {
1512 PyObject *obj;
1512 PyObject *obj;
1513 ret = PyList_New(1);
1513 ret = PyList_New(1);
1514 if (ret == NULL)
1514 if (ret == NULL)
1515 goto bail;
1515 goto bail;
1516 obj = PyInt_FromLong(revs[0]);
1516 obj = PyInt_FromLong(revs[0]);
1517 if (obj == NULL)
1517 if (obj == NULL)
1518 goto bail;
1518 goto bail;
1519 PyList_SET_ITEM(ret, 0, obj);
1519 PyList_SET_ITEM(ret, 0, obj);
1520 goto done;
1520 goto done;
1521 }
1521 }
1522
1522
1523 gca = find_gca_candidates(self, revs, revcount);
1523 gca = find_gca_candidates(self, revs, revcount);
1524 if (gca == NULL)
1524 if (gca == NULL)
1525 goto bail;
1525 goto bail;
1526
1526
1527 if (PyList_GET_SIZE(gca) <= 1) {
1527 if (PyList_GET_SIZE(gca) <= 1) {
1528 ret = gca;
1528 ret = gca;
1529 Py_INCREF(gca);
1529 Py_INCREF(gca);
1530 }
1530 }
1531 else ret = find_deepest(self, gca);
1531 else ret = find_deepest(self, gca);
1532
1532
1533 done:
1533 done:
1534 free(revs);
1534 free(revs);
1535 Py_XDECREF(gca);
1535 Py_XDECREF(gca);
1536
1536
1537 return ret;
1537 return ret;
1538
1538
1539 bail:
1539 bail:
1540 free(revs);
1540 free(revs);
1541 Py_XDECREF(gca);
1541 Py_XDECREF(gca);
1542 Py_XDECREF(ret);
1542 Py_XDECREF(ret);
1543 return NULL;
1543 return NULL;
1544 }
1544 }
1545
1545
1546 /*
1546 /*
1547 * Given a (possibly overlapping) set of revs, return all the
1548 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1549 */
1550 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1551 {
1552 PyObject *ret = NULL, *gca = NULL;
1553 Py_ssize_t argcount, i, len;
1554 bitmask repeat = 0;
1555 int revcount = 0;
1556 int *revs;
1557
1558 argcount = PySequence_Length(args);
1559 revs = malloc(argcount * sizeof(*revs));
1560 if (argcount > 0 && revs == NULL)
1561 return PyErr_NoMemory();
1562 len = index_length(self) - 1;
1563
1564 for (i = 0; i < argcount; i++) {
1565 static const int capacity = 24;
1566 PyObject *obj = PySequence_GetItem(args, i);
1567 bitmask x;
1568 long val;
1569
1570 if (!PyInt_Check(obj)) {
1571 PyErr_SetString(PyExc_TypeError,
1572 "arguments must all be ints");
1573 goto bail;
1574 }
1575 val = PyInt_AsLong(obj);
1576 if (val == -1) {
1577 ret = PyList_New(0);
1578 goto done;
1579 }
1580 if (val < 0 || val >= len) {
1581 PyErr_SetString(PyExc_IndexError,
1582 "index out of range");
1583 goto bail;
1584 }
1585 /* this cheesy bloom filter lets us avoid some more
1586 * expensive duplicate checks in the common set-is-disjoint
1587 * case */
1588 x = 1ull << (val & 0x3f);
1589 if (repeat & x) {
1590 int k;
1591 for (k = 0; k < revcount; k++) {
1592 if (val == revs[k])
1593 goto duplicate;
1594 }
1595 }
1596 else repeat |= x;
1597 if (revcount >= capacity) {
1598 PyErr_Format(PyExc_OverflowError,
1599 "bitset size (%d) > capacity (%d)",
1600 revcount, capacity);
1601 goto bail;
1602 }
1603 revs[revcount++] = (int)val;
1604 duplicate:;
1605 }
1606
1607 if (revcount == 0) {
1608 ret = PyList_New(0);
1609 goto done;
1610 }
1611 if (revcount == 1) {
1612 PyObject *obj;
1613 ret = PyList_New(1);
1614 if (ret == NULL)
1615 goto bail;
1616 obj = PyInt_FromLong(revs[0]);
1617 if (obj == NULL)
1618 goto bail;
1619 PyList_SET_ITEM(ret, 0, obj);
1620 goto done;
1621 }
1622
1623 gca = find_gca_candidates(self, revs, revcount);
1624 if (gca == NULL)
1625 goto bail;
1626
1627 ret = gca;
1628 Py_INCREF(gca);
1629
1630 done:
1631 free(revs);
1632 Py_XDECREF(gca);
1633
1634 return ret;
1635
1636 bail:
1637 free(revs);
1638 Py_XDECREF(gca);
1639 Py_XDECREF(ret);
1640 return NULL;
1641 }
1642
1643 /*
1547 * Invalidate any trie entries introduced by added revs.
1644 * Invalidate any trie entries introduced by added revs.
1548 */
1645 */
1549 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1646 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1550 {
1647 {
1551 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1648 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1552
1649
1553 for (i = start; i < len; i++) {
1650 for (i = start; i < len; i++) {
1554 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1651 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1555 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1652 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1556
1653
1557 nt_insert(self, PyString_AS_STRING(node), -1);
1654 nt_insert(self, PyString_AS_STRING(node), -1);
1558 }
1655 }
1559
1656
1560 if (start == 0)
1657 if (start == 0)
1561 Py_CLEAR(self->added);
1658 Py_CLEAR(self->added);
1562 }
1659 }
1563
1660
1564 /*
1661 /*
1565 * Delete a numeric range of revs, which must be at the end of the
1662 * Delete a numeric range of revs, which must be at the end of the
1566 * range, but exclude the sentinel nullid entry.
1663 * range, but exclude the sentinel nullid entry.
1567 */
1664 */
1568 static int index_slice_del(indexObject *self, PyObject *item)
1665 static int index_slice_del(indexObject *self, PyObject *item)
1569 {
1666 {
1570 Py_ssize_t start, stop, step, slicelength;
1667 Py_ssize_t start, stop, step, slicelength;
1571 Py_ssize_t length = index_length(self);
1668 Py_ssize_t length = index_length(self);
1572 int ret = 0;
1669 int ret = 0;
1573
1670
1574 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1671 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1575 &start, &stop, &step, &slicelength) < 0)
1672 &start, &stop, &step, &slicelength) < 0)
1576 return -1;
1673 return -1;
1577
1674
1578 if (slicelength <= 0)
1675 if (slicelength <= 0)
1579 return 0;
1676 return 0;
1580
1677
1581 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1678 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1582 stop = start;
1679 stop = start;
1583
1680
1584 if (step < 0) {
1681 if (step < 0) {
1585 stop = start + 1;
1682 stop = start + 1;
1586 start = stop + step*(slicelength - 1) - 1;
1683 start = stop + step*(slicelength - 1) - 1;
1587 step = -step;
1684 step = -step;
1588 }
1685 }
1589
1686
1590 if (step != 1) {
1687 if (step != 1) {
1591 PyErr_SetString(PyExc_ValueError,
1688 PyErr_SetString(PyExc_ValueError,
1592 "revlog index delete requires step size of 1");
1689 "revlog index delete requires step size of 1");
1593 return -1;
1690 return -1;
1594 }
1691 }
1595
1692
1596 if (stop != length - 1) {
1693 if (stop != length - 1) {
1597 PyErr_SetString(PyExc_IndexError,
1694 PyErr_SetString(PyExc_IndexError,
1598 "revlog index deletion indices are invalid");
1695 "revlog index deletion indices are invalid");
1599 return -1;
1696 return -1;
1600 }
1697 }
1601
1698
1602 if (start < self->length - 1) {
1699 if (start < self->length - 1) {
1603 if (self->nt) {
1700 if (self->nt) {
1604 Py_ssize_t i;
1701 Py_ssize_t i;
1605
1702
1606 for (i = start + 1; i < self->length - 1; i++) {
1703 for (i = start + 1; i < self->length - 1; i++) {
1607 const char *node = index_node(self, i);
1704 const char *node = index_node(self, i);
1608
1705
1609 if (node)
1706 if (node)
1610 nt_insert(self, node, -1);
1707 nt_insert(self, node, -1);
1611 }
1708 }
1612 if (self->added)
1709 if (self->added)
1613 nt_invalidate_added(self, 0);
1710 nt_invalidate_added(self, 0);
1614 if (self->ntrev > start)
1711 if (self->ntrev > start)
1615 self->ntrev = (int)start;
1712 self->ntrev = (int)start;
1616 }
1713 }
1617 self->length = start + 1;
1714 self->length = start + 1;
1618 if (start < self->raw_length) {
1715 if (start < self->raw_length) {
1619 if (self->cache) {
1716 if (self->cache) {
1620 Py_ssize_t i;
1717 Py_ssize_t i;
1621 for (i = start; i < self->raw_length; i++)
1718 for (i = start; i < self->raw_length; i++)
1622 Py_CLEAR(self->cache[i]);
1719 Py_CLEAR(self->cache[i]);
1623 }
1720 }
1624 self->raw_length = start;
1721 self->raw_length = start;
1625 }
1722 }
1626 goto done;
1723 goto done;
1627 }
1724 }
1628
1725
1629 if (self->nt) {
1726 if (self->nt) {
1630 nt_invalidate_added(self, start - self->length + 1);
1727 nt_invalidate_added(self, start - self->length + 1);
1631 if (self->ntrev > start)
1728 if (self->ntrev > start)
1632 self->ntrev = (int)start;
1729 self->ntrev = (int)start;
1633 }
1730 }
1634 if (self->added)
1731 if (self->added)
1635 ret = PyList_SetSlice(self->added, start - self->length + 1,
1732 ret = PyList_SetSlice(self->added, start - self->length + 1,
1636 PyList_GET_SIZE(self->added), NULL);
1733 PyList_GET_SIZE(self->added), NULL);
1637 done:
1734 done:
1638 Py_CLEAR(self->headrevs);
1735 Py_CLEAR(self->headrevs);
1639 return ret;
1736 return ret;
1640 }
1737 }
1641
1738
1642 /*
1739 /*
1643 * Supported ops:
1740 * Supported ops:
1644 *
1741 *
1645 * slice deletion
1742 * slice deletion
1646 * string assignment (extend node->rev mapping)
1743 * string assignment (extend node->rev mapping)
1647 * string deletion (shrink node->rev mapping)
1744 * string deletion (shrink node->rev mapping)
1648 */
1745 */
1649 static int index_assign_subscript(indexObject *self, PyObject *item,
1746 static int index_assign_subscript(indexObject *self, PyObject *item,
1650 PyObject *value)
1747 PyObject *value)
1651 {
1748 {
1652 char *node;
1749 char *node;
1653 Py_ssize_t nodelen;
1750 Py_ssize_t nodelen;
1654 long rev;
1751 long rev;
1655
1752
1656 if (PySlice_Check(item) && value == NULL)
1753 if (PySlice_Check(item) && value == NULL)
1657 return index_slice_del(self, item);
1754 return index_slice_del(self, item);
1658
1755
1659 if (node_check(item, &node, &nodelen) == -1)
1756 if (node_check(item, &node, &nodelen) == -1)
1660 return -1;
1757 return -1;
1661
1758
1662 if (value == NULL)
1759 if (value == NULL)
1663 return self->nt ? nt_insert(self, node, -1) : 0;
1760 return self->nt ? nt_insert(self, node, -1) : 0;
1664 rev = PyInt_AsLong(value);
1761 rev = PyInt_AsLong(value);
1665 if (rev > INT_MAX || rev < 0) {
1762 if (rev > INT_MAX || rev < 0) {
1666 if (!PyErr_Occurred())
1763 if (!PyErr_Occurred())
1667 PyErr_SetString(PyExc_ValueError, "rev out of range");
1764 PyErr_SetString(PyExc_ValueError, "rev out of range");
1668 return -1;
1765 return -1;
1669 }
1766 }
1670 return nt_insert(self, node, (int)rev);
1767 return nt_insert(self, node, (int)rev);
1671 }
1768 }
1672
1769
1673 /*
1770 /*
1674 * Find all RevlogNG entries in an index that has inline data. Update
1771 * Find all RevlogNG entries in an index that has inline data. Update
1675 * the optional "offsets" table with those entries.
1772 * the optional "offsets" table with those entries.
1676 */
1773 */
1677 static long inline_scan(indexObject *self, const char **offsets)
1774 static long inline_scan(indexObject *self, const char **offsets)
1678 {
1775 {
1679 const char *data = PyString_AS_STRING(self->data);
1776 const char *data = PyString_AS_STRING(self->data);
1680 Py_ssize_t pos = 0;
1777 Py_ssize_t pos = 0;
1681 Py_ssize_t end = PyString_GET_SIZE(self->data);
1778 Py_ssize_t end = PyString_GET_SIZE(self->data);
1682 long incr = v1_hdrsize;
1779 long incr = v1_hdrsize;
1683 Py_ssize_t len = 0;
1780 Py_ssize_t len = 0;
1684
1781
1685 while (pos + v1_hdrsize <= end && pos >= 0) {
1782 while (pos + v1_hdrsize <= end && pos >= 0) {
1686 uint32_t comp_len;
1783 uint32_t comp_len;
1687 /* 3rd element of header is length of compressed inline data */
1784 /* 3rd element of header is length of compressed inline data */
1688 comp_len = getbe32(data + pos + 8);
1785 comp_len = getbe32(data + pos + 8);
1689 incr = v1_hdrsize + comp_len;
1786 incr = v1_hdrsize + comp_len;
1690 if (offsets)
1787 if (offsets)
1691 offsets[len] = data + pos;
1788 offsets[len] = data + pos;
1692 len++;
1789 len++;
1693 pos += incr;
1790 pos += incr;
1694 }
1791 }
1695
1792
1696 if (pos != end) {
1793 if (pos != end) {
1697 if (!PyErr_Occurred())
1794 if (!PyErr_Occurred())
1698 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1795 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1699 return -1;
1796 return -1;
1700 }
1797 }
1701
1798
1702 return len;
1799 return len;
1703 }
1800 }
1704
1801
1705 static int index_init(indexObject *self, PyObject *args)
1802 static int index_init(indexObject *self, PyObject *args)
1706 {
1803 {
1707 PyObject *data_obj, *inlined_obj;
1804 PyObject *data_obj, *inlined_obj;
1708 Py_ssize_t size;
1805 Py_ssize_t size;
1709
1806
1710 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1807 /* Initialize before argument-checking to avoid index_dealloc() crash. */
1711 self->raw_length = 0;
1808 self->raw_length = 0;
1712 self->added = NULL;
1809 self->added = NULL;
1713 self->cache = NULL;
1810 self->cache = NULL;
1714 self->data = NULL;
1811 self->data = NULL;
1715 self->headrevs = NULL;
1812 self->headrevs = NULL;
1716 self->nt = NULL;
1813 self->nt = NULL;
1717 self->offsets = NULL;
1814 self->offsets = NULL;
1718
1815
1719 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1816 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
1720 return -1;
1817 return -1;
1721 if (!PyString_Check(data_obj)) {
1818 if (!PyString_Check(data_obj)) {
1722 PyErr_SetString(PyExc_TypeError, "data is not a string");
1819 PyErr_SetString(PyExc_TypeError, "data is not a string");
1723 return -1;
1820 return -1;
1724 }
1821 }
1725 size = PyString_GET_SIZE(data_obj);
1822 size = PyString_GET_SIZE(data_obj);
1726
1823
1727 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1824 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
1728 self->data = data_obj;
1825 self->data = data_obj;
1729
1826
1730 self->ntlength = self->ntcapacity = 0;
1827 self->ntlength = self->ntcapacity = 0;
1731 self->ntdepth = self->ntsplits = 0;
1828 self->ntdepth = self->ntsplits = 0;
1732 self->ntlookups = self->ntmisses = 0;
1829 self->ntlookups = self->ntmisses = 0;
1733 self->ntrev = -1;
1830 self->ntrev = -1;
1734 Py_INCREF(self->data);
1831 Py_INCREF(self->data);
1735
1832
1736 if (self->inlined) {
1833 if (self->inlined) {
1737 long len = inline_scan(self, NULL);
1834 long len = inline_scan(self, NULL);
1738 if (len == -1)
1835 if (len == -1)
1739 goto bail;
1836 goto bail;
1740 self->raw_length = len;
1837 self->raw_length = len;
1741 self->length = len + 1;
1838 self->length = len + 1;
1742 } else {
1839 } else {
1743 if (size % v1_hdrsize) {
1840 if (size % v1_hdrsize) {
1744 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1841 PyErr_SetString(PyExc_ValueError, "corrupt index file");
1745 goto bail;
1842 goto bail;
1746 }
1843 }
1747 self->raw_length = size / v1_hdrsize;
1844 self->raw_length = size / v1_hdrsize;
1748 self->length = self->raw_length + 1;
1845 self->length = self->raw_length + 1;
1749 }
1846 }
1750
1847
1751 return 0;
1848 return 0;
1752 bail:
1849 bail:
1753 return -1;
1850 return -1;
1754 }
1851 }
1755
1852
1756 static PyObject *index_nodemap(indexObject *self)
1853 static PyObject *index_nodemap(indexObject *self)
1757 {
1854 {
1758 Py_INCREF(self);
1855 Py_INCREF(self);
1759 return (PyObject *)self;
1856 return (PyObject *)self;
1760 }
1857 }
1761
1858
1762 static void index_dealloc(indexObject *self)
1859 static void index_dealloc(indexObject *self)
1763 {
1860 {
1764 _index_clearcaches(self);
1861 _index_clearcaches(self);
1765 Py_XDECREF(self->data);
1862 Py_XDECREF(self->data);
1766 Py_XDECREF(self->added);
1863 Py_XDECREF(self->added);
1767 PyObject_Del(self);
1864 PyObject_Del(self);
1768 }
1865 }
1769
1866
1770 static PySequenceMethods index_sequence_methods = {
1867 static PySequenceMethods index_sequence_methods = {
1771 (lenfunc)index_length, /* sq_length */
1868 (lenfunc)index_length, /* sq_length */
1772 0, /* sq_concat */
1869 0, /* sq_concat */
1773 0, /* sq_repeat */
1870 0, /* sq_repeat */
1774 (ssizeargfunc)index_get, /* sq_item */
1871 (ssizeargfunc)index_get, /* sq_item */
1775 0, /* sq_slice */
1872 0, /* sq_slice */
1776 0, /* sq_ass_item */
1873 0, /* sq_ass_item */
1777 0, /* sq_ass_slice */
1874 0, /* sq_ass_slice */
1778 (objobjproc)index_contains, /* sq_contains */
1875 (objobjproc)index_contains, /* sq_contains */
1779 };
1876 };
1780
1877
1781 static PyMappingMethods index_mapping_methods = {
1878 static PyMappingMethods index_mapping_methods = {
1782 (lenfunc)index_length, /* mp_length */
1879 (lenfunc)index_length, /* mp_length */
1783 (binaryfunc)index_getitem, /* mp_subscript */
1880 (binaryfunc)index_getitem, /* mp_subscript */
1784 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1881 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
1785 };
1882 };
1786
1883
1787 static PyMethodDef index_methods[] = {
1884 static PyMethodDef index_methods[] = {
1788 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1885 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
1789 "return the gca set of the given revs"},
1886 "return the gca set of the given revs"},
1887 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
1888 METH_VARARGS,
1889 "return the heads of the common ancestors of the given revs"},
1790 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1890 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
1791 "clear the index caches"},
1891 "clear the index caches"},
1792 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1892 {"get", (PyCFunction)index_m_get, METH_VARARGS,
1793 "get an index entry"},
1893 "get an index entry"},
1794 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1894 {"headrevs", (PyCFunction)index_headrevs, METH_NOARGS,
1795 "get head revisions"},
1895 "get head revisions"},
1796 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1896 {"insert", (PyCFunction)index_insert, METH_VARARGS,
1797 "insert an index entry"},
1897 "insert an index entry"},
1798 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1898 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
1799 "match a potentially ambiguous node ID"},
1899 "match a potentially ambiguous node ID"},
1800 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1900 {"stats", (PyCFunction)index_stats, METH_NOARGS,
1801 "stats for the index"},
1901 "stats for the index"},
1802 {NULL} /* Sentinel */
1902 {NULL} /* Sentinel */
1803 };
1903 };
1804
1904
1805 static PyGetSetDef index_getset[] = {
1905 static PyGetSetDef index_getset[] = {
1806 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1906 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
1807 {NULL} /* Sentinel */
1907 {NULL} /* Sentinel */
1808 };
1908 };
1809
1909
1810 static PyTypeObject indexType = {
1910 static PyTypeObject indexType = {
1811 PyObject_HEAD_INIT(NULL)
1911 PyObject_HEAD_INIT(NULL)
1812 0, /* ob_size */
1912 0, /* ob_size */
1813 "parsers.index", /* tp_name */
1913 "parsers.index", /* tp_name */
1814 sizeof(indexObject), /* tp_basicsize */
1914 sizeof(indexObject), /* tp_basicsize */
1815 0, /* tp_itemsize */
1915 0, /* tp_itemsize */
1816 (destructor)index_dealloc, /* tp_dealloc */
1916 (destructor)index_dealloc, /* tp_dealloc */
1817 0, /* tp_print */
1917 0, /* tp_print */
1818 0, /* tp_getattr */
1918 0, /* tp_getattr */
1819 0, /* tp_setattr */
1919 0, /* tp_setattr */
1820 0, /* tp_compare */
1920 0, /* tp_compare */
1821 0, /* tp_repr */
1921 0, /* tp_repr */
1822 0, /* tp_as_number */
1922 0, /* tp_as_number */
1823 &index_sequence_methods, /* tp_as_sequence */
1923 &index_sequence_methods, /* tp_as_sequence */
1824 &index_mapping_methods, /* tp_as_mapping */
1924 &index_mapping_methods, /* tp_as_mapping */
1825 0, /* tp_hash */
1925 0, /* tp_hash */
1826 0, /* tp_call */
1926 0, /* tp_call */
1827 0, /* tp_str */
1927 0, /* tp_str */
1828 0, /* tp_getattro */
1928 0, /* tp_getattro */
1829 0, /* tp_setattro */
1929 0, /* tp_setattro */
1830 0, /* tp_as_buffer */
1930 0, /* tp_as_buffer */
1831 Py_TPFLAGS_DEFAULT, /* tp_flags */
1931 Py_TPFLAGS_DEFAULT, /* tp_flags */
1832 "revlog index", /* tp_doc */
1932 "revlog index", /* tp_doc */
1833 0, /* tp_traverse */
1933 0, /* tp_traverse */
1834 0, /* tp_clear */
1934 0, /* tp_clear */
1835 0, /* tp_richcompare */
1935 0, /* tp_richcompare */
1836 0, /* tp_weaklistoffset */
1936 0, /* tp_weaklistoffset */
1837 0, /* tp_iter */
1937 0, /* tp_iter */
1838 0, /* tp_iternext */
1938 0, /* tp_iternext */
1839 index_methods, /* tp_methods */
1939 index_methods, /* tp_methods */
1840 0, /* tp_members */
1940 0, /* tp_members */
1841 index_getset, /* tp_getset */
1941 index_getset, /* tp_getset */
1842 0, /* tp_base */
1942 0, /* tp_base */
1843 0, /* tp_dict */
1943 0, /* tp_dict */
1844 0, /* tp_descr_get */
1944 0, /* tp_descr_get */
1845 0, /* tp_descr_set */
1945 0, /* tp_descr_set */
1846 0, /* tp_dictoffset */
1946 0, /* tp_dictoffset */
1847 (initproc)index_init, /* tp_init */
1947 (initproc)index_init, /* tp_init */
1848 0, /* tp_alloc */
1948 0, /* tp_alloc */
1849 };
1949 };
1850
1950
1851 /*
1951 /*
1852 * returns a tuple of the form (index, index, cache) with elements as
1952 * returns a tuple of the form (index, index, cache) with elements as
1853 * follows:
1953 * follows:
1854 *
1954 *
1855 * index: an index object that lazily parses RevlogNG records
1955 * index: an index object that lazily parses RevlogNG records
1856 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1956 * cache: if data is inlined, a tuple (index_file_content, 0), else None
1857 *
1957 *
1858 * added complications are for backwards compatibility
1958 * added complications are for backwards compatibility
1859 */
1959 */
1860 static PyObject *parse_index2(PyObject *self, PyObject *args)
1960 static PyObject *parse_index2(PyObject *self, PyObject *args)
1861 {
1961 {
1862 PyObject *tuple = NULL, *cache = NULL;
1962 PyObject *tuple = NULL, *cache = NULL;
1863 indexObject *idx;
1963 indexObject *idx;
1864 int ret;
1964 int ret;
1865
1965
1866 idx = PyObject_New(indexObject, &indexType);
1966 idx = PyObject_New(indexObject, &indexType);
1867 if (idx == NULL)
1967 if (idx == NULL)
1868 goto bail;
1968 goto bail;
1869
1969
1870 ret = index_init(idx, args);
1970 ret = index_init(idx, args);
1871 if (ret == -1)
1971 if (ret == -1)
1872 goto bail;
1972 goto bail;
1873
1973
1874 if (idx->inlined) {
1974 if (idx->inlined) {
1875 cache = Py_BuildValue("iO", 0, idx->data);
1975 cache = Py_BuildValue("iO", 0, idx->data);
1876 if (cache == NULL)
1976 if (cache == NULL)
1877 goto bail;
1977 goto bail;
1878 } else {
1978 } else {
1879 cache = Py_None;
1979 cache = Py_None;
1880 Py_INCREF(cache);
1980 Py_INCREF(cache);
1881 }
1981 }
1882
1982
1883 tuple = Py_BuildValue("NN", idx, cache);
1983 tuple = Py_BuildValue("NN", idx, cache);
1884 if (!tuple)
1984 if (!tuple)
1885 goto bail;
1985 goto bail;
1886 return tuple;
1986 return tuple;
1887
1987
1888 bail:
1988 bail:
1889 Py_XDECREF(idx);
1989 Py_XDECREF(idx);
1890 Py_XDECREF(cache);
1990 Py_XDECREF(cache);
1891 Py_XDECREF(tuple);
1991 Py_XDECREF(tuple);
1892 return NULL;
1992 return NULL;
1893 }
1993 }
1894
1994
1895 static char parsers_doc[] = "Efficient content parsing.";
1995 static char parsers_doc[] = "Efficient content parsing.";
1896
1996
1897 PyObject *encodedir(PyObject *self, PyObject *args);
1997 PyObject *encodedir(PyObject *self, PyObject *args);
1898 PyObject *pathencode(PyObject *self, PyObject *args);
1998 PyObject *pathencode(PyObject *self, PyObject *args);
1899 PyObject *lowerencode(PyObject *self, PyObject *args);
1999 PyObject *lowerencode(PyObject *self, PyObject *args);
1900
2000
1901 static PyMethodDef methods[] = {
2001 static PyMethodDef methods[] = {
1902 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2002 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1903 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2003 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
1904 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2004 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1905 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2005 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
1906 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2006 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
1907 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2007 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
1908 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2008 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
1909 {NULL, NULL}
2009 {NULL, NULL}
1910 };
2010 };
1911
2011
1912 void dirs_module_init(PyObject *mod);
2012 void dirs_module_init(PyObject *mod);
1913
2013
1914 static void module_init(PyObject *mod)
2014 static void module_init(PyObject *mod)
1915 {
2015 {
1916 /* This module constant has two purposes. First, it lets us unit test
2016 /* This module constant has two purposes. First, it lets us unit test
1917 * the ImportError raised without hard-coding any error text. This
2017 * the ImportError raised without hard-coding any error text. This
1918 * means we can change the text in the future without breaking tests,
2018 * means we can change the text in the future without breaking tests,
1919 * even across changesets without a recompile. Second, its presence
2019 * even across changesets without a recompile. Second, its presence
1920 * can be used to determine whether the version-checking logic is
2020 * can be used to determine whether the version-checking logic is
1921 * present, which also helps in testing across changesets without a
2021 * present, which also helps in testing across changesets without a
1922 * recompile. Note that this means the pure-Python version of parsers
2022 * recompile. Note that this means the pure-Python version of parsers
1923 * should not have this module constant. */
2023 * should not have this module constant. */
1924 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2024 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
1925
2025
1926 dirs_module_init(mod);
2026 dirs_module_init(mod);
1927
2027
1928 indexType.tp_new = PyType_GenericNew;
2028 indexType.tp_new = PyType_GenericNew;
1929 if (PyType_Ready(&indexType) < 0)
2029 if (PyType_Ready(&indexType) < 0)
1930 return;
2030 return;
1931 Py_INCREF(&indexType);
2031 Py_INCREF(&indexType);
1932
2032
1933 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2033 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
1934
2034
1935 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2035 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
1936 -1, -1, -1, -1, nullid, 20);
2036 -1, -1, -1, -1, nullid, 20);
1937 if (nullentry)
2037 if (nullentry)
1938 PyObject_GC_UnTrack(nullentry);
2038 PyObject_GC_UnTrack(nullentry);
1939
2039
1940 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
2040 dirstate_unset = Py_BuildValue("ciii", 'n', 0, -1, -1);
1941 }
2041 }
1942
2042
1943 static int check_python_version(void)
2043 static int check_python_version(void)
1944 {
2044 {
1945 PyObject *sys = PyImport_ImportModule("sys");
2045 PyObject *sys = PyImport_ImportModule("sys");
1946 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
2046 long hexversion = PyInt_AsLong(PyObject_GetAttrString(sys, "hexversion"));
1947 /* sys.hexversion is a 32-bit number by default, so the -1 case
2047 /* sys.hexversion is a 32-bit number by default, so the -1 case
1948 * should only occur in unusual circumstances (e.g. if sys.hexversion
2048 * should only occur in unusual circumstances (e.g. if sys.hexversion
1949 * is manually set to an invalid value). */
2049 * is manually set to an invalid value). */
1950 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2050 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
1951 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2051 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
1952 "modules were compiled with Python " PY_VERSION ", but "
2052 "modules were compiled with Python " PY_VERSION ", but "
1953 "Mercurial is currently using Python with sys.hexversion=%ld: "
2053 "Mercurial is currently using Python with sys.hexversion=%ld: "
1954 "Python %s\n at: %s", versionerrortext, hexversion,
2054 "Python %s\n at: %s", versionerrortext, hexversion,
1955 Py_GetVersion(), Py_GetProgramFullPath());
2055 Py_GetVersion(), Py_GetProgramFullPath());
1956 return -1;
2056 return -1;
1957 }
2057 }
1958 return 0;
2058 return 0;
1959 }
2059 }
1960
2060
1961 #ifdef IS_PY3K
2061 #ifdef IS_PY3K
1962 static struct PyModuleDef parsers_module = {
2062 static struct PyModuleDef parsers_module = {
1963 PyModuleDef_HEAD_INIT,
2063 PyModuleDef_HEAD_INIT,
1964 "parsers",
2064 "parsers",
1965 parsers_doc,
2065 parsers_doc,
1966 -1,
2066 -1,
1967 methods
2067 methods
1968 };
2068 };
1969
2069
1970 PyMODINIT_FUNC PyInit_parsers(void)
2070 PyMODINIT_FUNC PyInit_parsers(void)
1971 {
2071 {
1972 PyObject *mod;
2072 PyObject *mod;
1973
2073
1974 if (check_python_version() == -1)
2074 if (check_python_version() == -1)
1975 return;
2075 return;
1976 mod = PyModule_Create(&parsers_module);
2076 mod = PyModule_Create(&parsers_module);
1977 module_init(mod);
2077 module_init(mod);
1978 return mod;
2078 return mod;
1979 }
2079 }
1980 #else
2080 #else
1981 PyMODINIT_FUNC initparsers(void)
2081 PyMODINIT_FUNC initparsers(void)
1982 {
2082 {
1983 PyObject *mod;
2083 PyObject *mod;
1984
2084
1985 if (check_python_version() == -1)
2085 if (check_python_version() == -1)
1986 return;
2086 return;
1987 mod = Py_InitModule3("parsers", methods, parsers_doc);
2087 mod = Py_InitModule3("parsers", methods, parsers_doc);
1988 module_init(mod);
2088 module_init(mod);
1989 }
2089 }
1990 #endif
2090 #endif
General Comments 0
You need to be logged in to leave comments. Login now