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