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