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