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