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