##// END OF EJS Templates
revlog: rename indexType to HgRevlogIndex_Type as it's a global symbol...
Yuya Nishihara -
r40895:18a8def6 default
parent child Browse files
Show More
@@ -1,2873 +1,2874 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 <assert.h>
11 #include <assert.h>
12 #include <ctype.h>
12 #include <ctype.h>
13 #include <limits.h>
13 #include <limits.h>
14 #include <stddef.h>
14 #include <stddef.h>
15 #include <stdlib.h>
15 #include <stdlib.h>
16 #include <string.h>
16 #include <string.h>
17
17
18 #include "bitmanipulation.h"
18 #include "bitmanipulation.h"
19 #include "charencode.h"
19 #include "charencode.h"
20 #include "revlog.h"
20 #include "revlog.h"
21 #include "util.h"
21 #include "util.h"
22
22
23 #ifdef IS_PY3K
23 #ifdef IS_PY3K
24 /* The mapping of Python types is meant to be temporary to get Python
24 /* The mapping of Python types is meant to be temporary to get Python
25 * 3 to compile. We should remove this once Python 3 support is fully
25 * 3 to compile. We should remove this once Python 3 support is fully
26 * supported and proper types are used in the extensions themselves. */
26 * supported and proper types are used in the extensions themselves. */
27 #define PyInt_Check PyLong_Check
27 #define PyInt_Check PyLong_Check
28 #define PyInt_FromLong PyLong_FromLong
28 #define PyInt_FromLong PyLong_FromLong
29 #define PyInt_FromSsize_t PyLong_FromSsize_t
29 #define PyInt_FromSsize_t PyLong_FromSsize_t
30 #define PyInt_AsLong PyLong_AsLong
30 #define PyInt_AsLong PyLong_AsLong
31 #endif
31 #endif
32
32
33 typedef struct indexObjectStruct indexObject;
33 typedef struct indexObjectStruct indexObject;
34
34
35 typedef struct {
35 typedef struct {
36 int children[16];
36 int children[16];
37 } nodetreenode;
37 } nodetreenode;
38
38
39 /*
39 /*
40 * A base-16 trie for fast node->rev mapping.
40 * A base-16 trie for fast node->rev mapping.
41 *
41 *
42 * Positive value is index of the next node in the trie
42 * Positive value is index of the next node in the trie
43 * Negative value is a leaf: -(rev + 2)
43 * Negative value is a leaf: -(rev + 2)
44 * Zero is empty
44 * Zero is empty
45 */
45 */
46 typedef struct {
46 typedef struct {
47 indexObject *index;
47 indexObject *index;
48 nodetreenode *nodes;
48 nodetreenode *nodes;
49 unsigned length; /* # nodes in use */
49 unsigned length; /* # nodes in use */
50 unsigned capacity; /* # nodes allocated */
50 unsigned capacity; /* # nodes allocated */
51 int depth; /* maximum depth of tree */
51 int depth; /* maximum depth of tree */
52 int splits; /* # splits performed */
52 int splits; /* # splits performed */
53 } nodetree;
53 } nodetree;
54
54
55 typedef struct {
55 typedef struct {
56 PyObject_HEAD /* ; */
56 PyObject_HEAD /* ; */
57 nodetree nt;
57 nodetree nt;
58 } nodetreeObject;
58 } nodetreeObject;
59
59
60 /*
60 /*
61 * This class has two behaviors.
61 * This class has two behaviors.
62 *
62 *
63 * When used in a list-like way (with integer keys), we decode an
63 * When used in a list-like way (with integer keys), we decode an
64 * entry in a RevlogNG index file on demand. Our last entry is a
64 * entry in a RevlogNG index file on demand. Our last entry is a
65 * sentinel, always a nullid. We have limited support for
65 * sentinel, always a nullid. We have limited support for
66 * integer-keyed insert and delete, only at elements right before the
66 * integer-keyed insert and delete, only at elements right before the
67 * sentinel.
67 * sentinel.
68 *
68 *
69 * With string keys, we lazily perform a reverse mapping from node to
69 * With string keys, we lazily perform a reverse mapping from node to
70 * rev, using a base-16 trie.
70 * rev, using a base-16 trie.
71 */
71 */
72 struct indexObjectStruct {
72 struct indexObjectStruct {
73 PyObject_HEAD
73 PyObject_HEAD
74 /* Type-specific fields go here. */
74 /* Type-specific fields go here. */
75 PyObject *data; /* raw bytes of index */
75 PyObject *data; /* raw bytes of index */
76 Py_buffer buf; /* buffer of data */
76 Py_buffer buf; /* buffer of data */
77 PyObject **cache; /* cached tuples */
77 PyObject **cache; /* cached tuples */
78 const char **offsets; /* populated on demand */
78 const char **offsets; /* populated on demand */
79 Py_ssize_t raw_length; /* original number of elements */
79 Py_ssize_t raw_length; /* original number of elements */
80 Py_ssize_t length; /* current number of elements */
80 Py_ssize_t length; /* current number of elements */
81 PyObject *added; /* populated on demand */
81 PyObject *added; /* populated on demand */
82 PyObject *headrevs; /* cache, invalidated on changes */
82 PyObject *headrevs; /* cache, invalidated on changes */
83 PyObject *filteredrevs; /* filtered revs set */
83 PyObject *filteredrevs; /* filtered revs set */
84 nodetree nt; /* base-16 trie */
84 nodetree nt; /* base-16 trie */
85 int ntinitialized; /* 0 or 1 */
85 int ntinitialized; /* 0 or 1 */
86 int ntrev; /* last rev scanned */
86 int ntrev; /* last rev scanned */
87 int ntlookups; /* # lookups */
87 int ntlookups; /* # lookups */
88 int ntmisses; /* # lookups that miss the cache */
88 int ntmisses; /* # lookups that miss the cache */
89 int inlined;
89 int inlined;
90 };
90 };
91
91
92 static Py_ssize_t index_length(const indexObject *self)
92 static Py_ssize_t index_length(const indexObject *self)
93 {
93 {
94 if (self->added == NULL)
94 if (self->added == NULL)
95 return self->length;
95 return self->length;
96 return self->length + PyList_GET_SIZE(self->added);
96 return self->length + PyList_GET_SIZE(self->added);
97 }
97 }
98
98
99 static PyObject *nullentry = NULL;
99 static PyObject *nullentry = NULL;
100 static const char nullid[20] = {0};
100 static const char nullid[20] = {0};
101
101
102 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
102 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
103
103
104 #if LONG_MAX == 0x7fffffffL
104 #if LONG_MAX == 0x7fffffffL
105 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
105 static const char *const tuple_format = PY23("Kiiiiiis#", "Kiiiiiiy#");
106 #else
106 #else
107 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
107 static const char *const tuple_format = PY23("kiiiiiis#", "kiiiiiiy#");
108 #endif
108 #endif
109
109
110 /* A RevlogNG v1 index entry is 64 bytes long. */
110 /* A RevlogNG v1 index entry is 64 bytes long. */
111 static const long v1_hdrsize = 64;
111 static const long v1_hdrsize = 64;
112
112
113 static void raise_revlog_error(void)
113 static void raise_revlog_error(void)
114 {
114 {
115 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
115 PyObject *mod = NULL, *dict = NULL, *errclass = NULL;
116
116
117 mod = PyImport_ImportModule("mercurial.error");
117 mod = PyImport_ImportModule("mercurial.error");
118 if (mod == NULL) {
118 if (mod == NULL) {
119 goto cleanup;
119 goto cleanup;
120 }
120 }
121
121
122 dict = PyModule_GetDict(mod);
122 dict = PyModule_GetDict(mod);
123 if (dict == NULL) {
123 if (dict == NULL) {
124 goto cleanup;
124 goto cleanup;
125 }
125 }
126 Py_INCREF(dict);
126 Py_INCREF(dict);
127
127
128 errclass = PyDict_GetItemString(dict, "RevlogError");
128 errclass = PyDict_GetItemString(dict, "RevlogError");
129 if (errclass == NULL) {
129 if (errclass == NULL) {
130 PyErr_SetString(PyExc_SystemError,
130 PyErr_SetString(PyExc_SystemError,
131 "could not find RevlogError");
131 "could not find RevlogError");
132 goto cleanup;
132 goto cleanup;
133 }
133 }
134
134
135 /* value of exception is ignored by callers */
135 /* value of exception is ignored by callers */
136 PyErr_SetString(errclass, "RevlogError");
136 PyErr_SetString(errclass, "RevlogError");
137
137
138 cleanup:
138 cleanup:
139 Py_XDECREF(dict);
139 Py_XDECREF(dict);
140 Py_XDECREF(mod);
140 Py_XDECREF(mod);
141 }
141 }
142
142
143 /*
143 /*
144 * Return a pointer to the beginning of a RevlogNG record.
144 * Return a pointer to the beginning of a RevlogNG record.
145 */
145 */
146 static const char *index_deref(indexObject *self, Py_ssize_t pos)
146 static const char *index_deref(indexObject *self, Py_ssize_t pos)
147 {
147 {
148 if (self->inlined && pos > 0) {
148 if (self->inlined && pos > 0) {
149 if (self->offsets == NULL) {
149 if (self->offsets == NULL) {
150 self->offsets = PyMem_Malloc(self->raw_length *
150 self->offsets = PyMem_Malloc(self->raw_length *
151 sizeof(*self->offsets));
151 sizeof(*self->offsets));
152 if (self->offsets == NULL)
152 if (self->offsets == NULL)
153 return (const char *)PyErr_NoMemory();
153 return (const char *)PyErr_NoMemory();
154 inline_scan(self, self->offsets);
154 inline_scan(self, self->offsets);
155 }
155 }
156 return self->offsets[pos];
156 return self->offsets[pos];
157 }
157 }
158
158
159 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
159 return (const char *)(self->buf.buf) + pos * v1_hdrsize;
160 }
160 }
161
161
162 /*
162 /*
163 * Get parents of the given rev.
163 * Get parents of the given rev.
164 *
164 *
165 * The specified rev must be valid and must not be nullrev. A returned
165 * The specified rev must be valid and must not be nullrev. A returned
166 * parent revision may be nullrev, but is guaranteed to be in valid range.
166 * parent revision may be nullrev, but is guaranteed to be in valid range.
167 */
167 */
168 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
168 static inline int index_get_parents(indexObject *self, Py_ssize_t rev, int *ps,
169 int maxrev)
169 int maxrev)
170 {
170 {
171 if (rev >= self->length) {
171 if (rev >= self->length) {
172 long tmp;
172 long tmp;
173 PyObject *tuple =
173 PyObject *tuple =
174 PyList_GET_ITEM(self->added, rev - self->length);
174 PyList_GET_ITEM(self->added, rev - self->length);
175 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
175 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 5), &tmp)) {
176 return -1;
176 return -1;
177 }
177 }
178 ps[0] = (int)tmp;
178 ps[0] = (int)tmp;
179 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
179 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 6), &tmp)) {
180 return -1;
180 return -1;
181 }
181 }
182 ps[1] = (int)tmp;
182 ps[1] = (int)tmp;
183 } else {
183 } else {
184 const char *data = index_deref(self, rev);
184 const char *data = index_deref(self, rev);
185 ps[0] = getbe32(data + 24);
185 ps[0] = getbe32(data + 24);
186 ps[1] = getbe32(data + 28);
186 ps[1] = getbe32(data + 28);
187 }
187 }
188 /* If index file is corrupted, ps[] may point to invalid revisions. So
188 /* If index file is corrupted, ps[] may point to invalid revisions. So
189 * there is a risk of buffer overflow to trust them unconditionally. */
189 * there is a risk of buffer overflow to trust them unconditionally. */
190 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
190 if (ps[0] < -1 || ps[0] > maxrev || ps[1] < -1 || ps[1] > maxrev) {
191 PyErr_SetString(PyExc_ValueError, "parent out of range");
191 PyErr_SetString(PyExc_ValueError, "parent out of range");
192 return -1;
192 return -1;
193 }
193 }
194 return 0;
194 return 0;
195 }
195 }
196
196
197 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
197 static inline int64_t index_get_start(indexObject *self, Py_ssize_t rev)
198 {
198 {
199 uint64_t offset;
199 uint64_t offset;
200 if (rev >= self->length) {
200 if (rev >= self->length) {
201 PyObject *tuple;
201 PyObject *tuple;
202 PyObject *pylong;
202 PyObject *pylong;
203 PY_LONG_LONG tmp;
203 PY_LONG_LONG tmp;
204 tuple = PyList_GET_ITEM(self->added, rev - self->length);
204 tuple = PyList_GET_ITEM(self->added, rev - self->length);
205 pylong = PyTuple_GET_ITEM(tuple, 0);
205 pylong = PyTuple_GET_ITEM(tuple, 0);
206 tmp = PyLong_AsLongLong(pylong);
206 tmp = PyLong_AsLongLong(pylong);
207 if (tmp == -1 && PyErr_Occurred()) {
207 if (tmp == -1 && PyErr_Occurred()) {
208 return -1;
208 return -1;
209 }
209 }
210 if (tmp < 0) {
210 if (tmp < 0) {
211 PyErr_Format(PyExc_OverflowError,
211 PyErr_Format(PyExc_OverflowError,
212 "revlog entry size out of bound (%lld)",
212 "revlog entry size out of bound (%lld)",
213 (long long)tmp);
213 (long long)tmp);
214 return -1;
214 return -1;
215 }
215 }
216 offset = (uint64_t)tmp;
216 offset = (uint64_t)tmp;
217 } else {
217 } else {
218 const char *data = index_deref(self, rev);
218 const char *data = index_deref(self, rev);
219 offset = getbe32(data + 4);
219 offset = getbe32(data + 4);
220 if (rev == 0) {
220 if (rev == 0) {
221 /* mask out version number for the first entry */
221 /* mask out version number for the first entry */
222 offset &= 0xFFFF;
222 offset &= 0xFFFF;
223 } else {
223 } else {
224 uint32_t offset_high = getbe32(data);
224 uint32_t offset_high = getbe32(data);
225 offset |= ((uint64_t)offset_high) << 32;
225 offset |= ((uint64_t)offset_high) << 32;
226 }
226 }
227 }
227 }
228 return (int64_t)(offset >> 16);
228 return (int64_t)(offset >> 16);
229 }
229 }
230
230
231 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
231 static inline int index_get_length(indexObject *self, Py_ssize_t rev)
232 {
232 {
233 if (rev >= self->length) {
233 if (rev >= self->length) {
234 PyObject *tuple;
234 PyObject *tuple;
235 PyObject *pylong;
235 PyObject *pylong;
236 long ret;
236 long ret;
237 tuple = PyList_GET_ITEM(self->added, rev - self->length);
237 tuple = PyList_GET_ITEM(self->added, rev - self->length);
238 pylong = PyTuple_GET_ITEM(tuple, 1);
238 pylong = PyTuple_GET_ITEM(tuple, 1);
239 ret = PyInt_AsLong(pylong);
239 ret = PyInt_AsLong(pylong);
240 if (ret == -1 && PyErr_Occurred()) {
240 if (ret == -1 && PyErr_Occurred()) {
241 return -1;
241 return -1;
242 }
242 }
243 if (ret < 0 || ret > (long)INT_MAX) {
243 if (ret < 0 || ret > (long)INT_MAX) {
244 PyErr_Format(PyExc_OverflowError,
244 PyErr_Format(PyExc_OverflowError,
245 "revlog entry size out of bound (%ld)",
245 "revlog entry size out of bound (%ld)",
246 ret);
246 ret);
247 return -1;
247 return -1;
248 }
248 }
249 return (int)ret;
249 return (int)ret;
250 } else {
250 } else {
251 const char *data = index_deref(self, rev);
251 const char *data = index_deref(self, rev);
252 int tmp = (int)getbe32(data + 8);
252 int tmp = (int)getbe32(data + 8);
253 if (tmp < 0) {
253 if (tmp < 0) {
254 PyErr_Format(PyExc_OverflowError,
254 PyErr_Format(PyExc_OverflowError,
255 "revlog entry size out of bound (%d)",
255 "revlog entry size out of bound (%d)",
256 tmp);
256 tmp);
257 return -1;
257 return -1;
258 }
258 }
259 return tmp;
259 return tmp;
260 }
260 }
261 }
261 }
262
262
263 /*
263 /*
264 * RevlogNG format (all in big endian, data may be inlined):
264 * RevlogNG format (all in big endian, data may be inlined):
265 * 6 bytes: offset
265 * 6 bytes: offset
266 * 2 bytes: flags
266 * 2 bytes: flags
267 * 4 bytes: compressed length
267 * 4 bytes: compressed length
268 * 4 bytes: uncompressed length
268 * 4 bytes: uncompressed length
269 * 4 bytes: base revision
269 * 4 bytes: base revision
270 * 4 bytes: link revision
270 * 4 bytes: link revision
271 * 4 bytes: parent 1 revision
271 * 4 bytes: parent 1 revision
272 * 4 bytes: parent 2 revision
272 * 4 bytes: parent 2 revision
273 * 32 bytes: nodeid (only 20 bytes used)
273 * 32 bytes: nodeid (only 20 bytes used)
274 */
274 */
275 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
275 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
276 {
276 {
277 uint64_t offset_flags;
277 uint64_t offset_flags;
278 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
278 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
279 const char *c_node_id;
279 const char *c_node_id;
280 const char *data;
280 const char *data;
281 Py_ssize_t length = index_length(self);
281 Py_ssize_t length = index_length(self);
282 PyObject *entry;
282 PyObject *entry;
283
283
284 if (pos == -1) {
284 if (pos == -1) {
285 Py_INCREF(nullentry);
285 Py_INCREF(nullentry);
286 return nullentry;
286 return nullentry;
287 }
287 }
288
288
289 if (pos < 0 || pos >= length) {
289 if (pos < 0 || pos >= length) {
290 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
290 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
291 return NULL;
291 return NULL;
292 }
292 }
293
293
294 if (pos >= self->length) {
294 if (pos >= self->length) {
295 PyObject *obj;
295 PyObject *obj;
296 obj = PyList_GET_ITEM(self->added, pos - self->length);
296 obj = PyList_GET_ITEM(self->added, pos - self->length);
297 Py_INCREF(obj);
297 Py_INCREF(obj);
298 return obj;
298 return obj;
299 }
299 }
300
300
301 if (self->cache) {
301 if (self->cache) {
302 if (self->cache[pos]) {
302 if (self->cache[pos]) {
303 Py_INCREF(self->cache[pos]);
303 Py_INCREF(self->cache[pos]);
304 return self->cache[pos];
304 return self->cache[pos];
305 }
305 }
306 } else {
306 } else {
307 self->cache = calloc(self->raw_length, sizeof(PyObject *));
307 self->cache = calloc(self->raw_length, sizeof(PyObject *));
308 if (self->cache == NULL)
308 if (self->cache == NULL)
309 return PyErr_NoMemory();
309 return PyErr_NoMemory();
310 }
310 }
311
311
312 data = index_deref(self, pos);
312 data = index_deref(self, pos);
313 if (data == NULL)
313 if (data == NULL)
314 return NULL;
314 return NULL;
315
315
316 offset_flags = getbe32(data + 4);
316 offset_flags = getbe32(data + 4);
317 if (pos == 0) /* mask out version number for the first entry */
317 if (pos == 0) /* mask out version number for the first entry */
318 offset_flags &= 0xFFFF;
318 offset_flags &= 0xFFFF;
319 else {
319 else {
320 uint32_t offset_high = getbe32(data);
320 uint32_t offset_high = getbe32(data);
321 offset_flags |= ((uint64_t)offset_high) << 32;
321 offset_flags |= ((uint64_t)offset_high) << 32;
322 }
322 }
323
323
324 comp_len = getbe32(data + 8);
324 comp_len = getbe32(data + 8);
325 uncomp_len = getbe32(data + 12);
325 uncomp_len = getbe32(data + 12);
326 base_rev = getbe32(data + 16);
326 base_rev = getbe32(data + 16);
327 link_rev = getbe32(data + 20);
327 link_rev = getbe32(data + 20);
328 parent_1 = getbe32(data + 24);
328 parent_1 = getbe32(data + 24);
329 parent_2 = getbe32(data + 28);
329 parent_2 = getbe32(data + 28);
330 c_node_id = data + 32;
330 c_node_id = data + 32;
331
331
332 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
332 entry = Py_BuildValue(tuple_format, offset_flags, comp_len, uncomp_len,
333 base_rev, link_rev, parent_1, parent_2, c_node_id,
333 base_rev, link_rev, parent_1, parent_2, c_node_id,
334 20);
334 20);
335
335
336 if (entry) {
336 if (entry) {
337 PyObject_GC_UnTrack(entry);
337 PyObject_GC_UnTrack(entry);
338 Py_INCREF(entry);
338 Py_INCREF(entry);
339 }
339 }
340
340
341 self->cache[pos] = entry;
341 self->cache[pos] = entry;
342
342
343 return entry;
343 return entry;
344 }
344 }
345
345
346 /*
346 /*
347 * Return the 20-byte SHA of the node corresponding to the given rev.
347 * Return the 20-byte SHA of the node corresponding to the given rev.
348 */
348 */
349 static const char *index_node(indexObject *self, Py_ssize_t pos)
349 static const char *index_node(indexObject *self, Py_ssize_t pos)
350 {
350 {
351 Py_ssize_t length = index_length(self);
351 Py_ssize_t length = index_length(self);
352 const char *data;
352 const char *data;
353
353
354 if (pos == -1)
354 if (pos == -1)
355 return nullid;
355 return nullid;
356
356
357 if (pos >= length)
357 if (pos >= length)
358 return NULL;
358 return NULL;
359
359
360 if (pos >= self->length) {
360 if (pos >= self->length) {
361 PyObject *tuple, *str;
361 PyObject *tuple, *str;
362 tuple = PyList_GET_ITEM(self->added, pos - self->length);
362 tuple = PyList_GET_ITEM(self->added, pos - self->length);
363 str = PyTuple_GetItem(tuple, 7);
363 str = PyTuple_GetItem(tuple, 7);
364 return str ? PyBytes_AS_STRING(str) : NULL;
364 return str ? PyBytes_AS_STRING(str) : NULL;
365 }
365 }
366
366
367 data = index_deref(self, pos);
367 data = index_deref(self, pos);
368 return data ? data + 32 : NULL;
368 return data ? data + 32 : NULL;
369 }
369 }
370
370
371 /*
371 /*
372 * Return the 20-byte SHA of the node corresponding to the given rev. The
372 * Return the 20-byte SHA of the node corresponding to the given rev. The
373 * rev is assumed to be existing. If not, an exception is set.
373 * rev is assumed to be existing. If not, an exception is set.
374 */
374 */
375 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
375 static const char *index_node_existing(indexObject *self, Py_ssize_t pos)
376 {
376 {
377 const char *node = index_node(self, pos);
377 const char *node = index_node(self, pos);
378 if (node == NULL) {
378 if (node == NULL) {
379 PyErr_Format(PyExc_IndexError, "could not access rev %d",
379 PyErr_Format(PyExc_IndexError, "could not access rev %d",
380 (int)pos);
380 (int)pos);
381 }
381 }
382 return node;
382 return node;
383 }
383 }
384
384
385 static int nt_insert(nodetree *self, const char *node, int rev);
385 static int nt_insert(nodetree *self, const char *node, int rev);
386
386
387 static int node_check(PyObject *obj, char **node)
387 static int node_check(PyObject *obj, char **node)
388 {
388 {
389 Py_ssize_t nodelen;
389 Py_ssize_t nodelen;
390 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
390 if (PyBytes_AsStringAndSize(obj, node, &nodelen) == -1)
391 return -1;
391 return -1;
392 if (nodelen == 20)
392 if (nodelen == 20)
393 return 0;
393 return 0;
394 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
394 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
395 return -1;
395 return -1;
396 }
396 }
397
397
398 static PyObject *index_append(indexObject *self, PyObject *obj)
398 static PyObject *index_append(indexObject *self, PyObject *obj)
399 {
399 {
400 char *node;
400 char *node;
401 Py_ssize_t len;
401 Py_ssize_t len;
402
402
403 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
403 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
404 PyErr_SetString(PyExc_TypeError, "8-tuple required");
404 PyErr_SetString(PyExc_TypeError, "8-tuple required");
405 return NULL;
405 return NULL;
406 }
406 }
407
407
408 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
408 if (node_check(PyTuple_GET_ITEM(obj, 7), &node) == -1)
409 return NULL;
409 return NULL;
410
410
411 len = index_length(self);
411 len = index_length(self);
412
412
413 if (self->added == NULL) {
413 if (self->added == NULL) {
414 self->added = PyList_New(0);
414 self->added = PyList_New(0);
415 if (self->added == NULL)
415 if (self->added == NULL)
416 return NULL;
416 return NULL;
417 }
417 }
418
418
419 if (PyList_Append(self->added, obj) == -1)
419 if (PyList_Append(self->added, obj) == -1)
420 return NULL;
420 return NULL;
421
421
422 if (self->ntinitialized)
422 if (self->ntinitialized)
423 nt_insert(&self->nt, node, (int)len);
423 nt_insert(&self->nt, node, (int)len);
424
424
425 Py_CLEAR(self->headrevs);
425 Py_CLEAR(self->headrevs);
426 Py_RETURN_NONE;
426 Py_RETURN_NONE;
427 }
427 }
428
428
429 static PyObject *index_stats(indexObject *self)
429 static PyObject *index_stats(indexObject *self)
430 {
430 {
431 PyObject *obj = PyDict_New();
431 PyObject *obj = PyDict_New();
432 PyObject *s = NULL;
432 PyObject *s = NULL;
433 PyObject *t = NULL;
433 PyObject *t = NULL;
434
434
435 if (obj == NULL)
435 if (obj == NULL)
436 return NULL;
436 return NULL;
437
437
438 #define istat(__n, __d) \
438 #define istat(__n, __d) \
439 do { \
439 do { \
440 s = PyBytes_FromString(__d); \
440 s = PyBytes_FromString(__d); \
441 t = PyInt_FromSsize_t(self->__n); \
441 t = PyInt_FromSsize_t(self->__n); \
442 if (!s || !t) \
442 if (!s || !t) \
443 goto bail; \
443 goto bail; \
444 if (PyDict_SetItem(obj, s, t) == -1) \
444 if (PyDict_SetItem(obj, s, t) == -1) \
445 goto bail; \
445 goto bail; \
446 Py_CLEAR(s); \
446 Py_CLEAR(s); \
447 Py_CLEAR(t); \
447 Py_CLEAR(t); \
448 } while (0)
448 } while (0)
449
449
450 if (self->added) {
450 if (self->added) {
451 Py_ssize_t len = PyList_GET_SIZE(self->added);
451 Py_ssize_t len = PyList_GET_SIZE(self->added);
452 s = PyBytes_FromString("index entries added");
452 s = PyBytes_FromString("index entries added");
453 t = PyInt_FromSsize_t(len);
453 t = PyInt_FromSsize_t(len);
454 if (!s || !t)
454 if (!s || !t)
455 goto bail;
455 goto bail;
456 if (PyDict_SetItem(obj, s, t) == -1)
456 if (PyDict_SetItem(obj, s, t) == -1)
457 goto bail;
457 goto bail;
458 Py_CLEAR(s);
458 Py_CLEAR(s);
459 Py_CLEAR(t);
459 Py_CLEAR(t);
460 }
460 }
461
461
462 if (self->raw_length != self->length)
462 if (self->raw_length != self->length)
463 istat(raw_length, "revs on disk");
463 istat(raw_length, "revs on disk");
464 istat(length, "revs in memory");
464 istat(length, "revs in memory");
465 istat(ntlookups, "node trie lookups");
465 istat(ntlookups, "node trie lookups");
466 istat(ntmisses, "node trie misses");
466 istat(ntmisses, "node trie misses");
467 istat(ntrev, "node trie last rev scanned");
467 istat(ntrev, "node trie last rev scanned");
468 if (self->ntinitialized) {
468 if (self->ntinitialized) {
469 istat(nt.capacity, "node trie capacity");
469 istat(nt.capacity, "node trie capacity");
470 istat(nt.depth, "node trie depth");
470 istat(nt.depth, "node trie depth");
471 istat(nt.length, "node trie count");
471 istat(nt.length, "node trie count");
472 istat(nt.splits, "node trie splits");
472 istat(nt.splits, "node trie splits");
473 }
473 }
474
474
475 #undef istat
475 #undef istat
476
476
477 return obj;
477 return obj;
478
478
479 bail:
479 bail:
480 Py_XDECREF(obj);
480 Py_XDECREF(obj);
481 Py_XDECREF(s);
481 Py_XDECREF(s);
482 Py_XDECREF(t);
482 Py_XDECREF(t);
483 return NULL;
483 return NULL;
484 }
484 }
485
485
486 /*
486 /*
487 * When we cache a list, we want to be sure the caller can't mutate
487 * When we cache a list, we want to be sure the caller can't mutate
488 * the cached copy.
488 * the cached copy.
489 */
489 */
490 static PyObject *list_copy(PyObject *list)
490 static PyObject *list_copy(PyObject *list)
491 {
491 {
492 Py_ssize_t len = PyList_GET_SIZE(list);
492 Py_ssize_t len = PyList_GET_SIZE(list);
493 PyObject *newlist = PyList_New(len);
493 PyObject *newlist = PyList_New(len);
494 Py_ssize_t i;
494 Py_ssize_t i;
495
495
496 if (newlist == NULL)
496 if (newlist == NULL)
497 return NULL;
497 return NULL;
498
498
499 for (i = 0; i < len; i++) {
499 for (i = 0; i < len; i++) {
500 PyObject *obj = PyList_GET_ITEM(list, i);
500 PyObject *obj = PyList_GET_ITEM(list, i);
501 Py_INCREF(obj);
501 Py_INCREF(obj);
502 PyList_SET_ITEM(newlist, i, obj);
502 PyList_SET_ITEM(newlist, i, obj);
503 }
503 }
504
504
505 return newlist;
505 return newlist;
506 }
506 }
507
507
508 static int check_filter(PyObject *filter, Py_ssize_t arg)
508 static int check_filter(PyObject *filter, Py_ssize_t arg)
509 {
509 {
510 if (filter) {
510 if (filter) {
511 PyObject *arglist, *result;
511 PyObject *arglist, *result;
512 int isfiltered;
512 int isfiltered;
513
513
514 arglist = Py_BuildValue("(n)", arg);
514 arglist = Py_BuildValue("(n)", arg);
515 if (!arglist) {
515 if (!arglist) {
516 return -1;
516 return -1;
517 }
517 }
518
518
519 result = PyEval_CallObject(filter, arglist);
519 result = PyEval_CallObject(filter, arglist);
520 Py_DECREF(arglist);
520 Py_DECREF(arglist);
521 if (!result) {
521 if (!result) {
522 return -1;
522 return -1;
523 }
523 }
524
524
525 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
525 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
526 * same as this function, so we can just return it directly.*/
526 * same as this function, so we can just return it directly.*/
527 isfiltered = PyObject_IsTrue(result);
527 isfiltered = PyObject_IsTrue(result);
528 Py_DECREF(result);
528 Py_DECREF(result);
529 return isfiltered;
529 return isfiltered;
530 } else {
530 } else {
531 return 0;
531 return 0;
532 }
532 }
533 }
533 }
534
534
535 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
535 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
536 Py_ssize_t marker, char *phases)
536 Py_ssize_t marker, char *phases)
537 {
537 {
538 PyObject *iter = NULL;
538 PyObject *iter = NULL;
539 PyObject *iter_item = NULL;
539 PyObject *iter_item = NULL;
540 Py_ssize_t min_idx = index_length(self) + 2;
540 Py_ssize_t min_idx = index_length(self) + 2;
541 long iter_item_long;
541 long iter_item_long;
542
542
543 if (PyList_GET_SIZE(list) != 0) {
543 if (PyList_GET_SIZE(list) != 0) {
544 iter = PyObject_GetIter(list);
544 iter = PyObject_GetIter(list);
545 if (iter == NULL)
545 if (iter == NULL)
546 return -2;
546 return -2;
547 while ((iter_item = PyIter_Next(iter))) {
547 while ((iter_item = PyIter_Next(iter))) {
548 if (!pylong_to_long(iter_item, &iter_item_long)) {
548 if (!pylong_to_long(iter_item, &iter_item_long)) {
549 Py_DECREF(iter_item);
549 Py_DECREF(iter_item);
550 return -2;
550 return -2;
551 }
551 }
552 Py_DECREF(iter_item);
552 Py_DECREF(iter_item);
553 if (iter_item_long < min_idx)
553 if (iter_item_long < min_idx)
554 min_idx = iter_item_long;
554 min_idx = iter_item_long;
555 phases[iter_item_long] = (char)marker;
555 phases[iter_item_long] = (char)marker;
556 }
556 }
557 Py_DECREF(iter);
557 Py_DECREF(iter);
558 }
558 }
559
559
560 return min_idx;
560 return min_idx;
561 }
561 }
562
562
563 static inline void set_phase_from_parents(char *phases, int parent_1,
563 static inline void set_phase_from_parents(char *phases, int parent_1,
564 int parent_2, Py_ssize_t i)
564 int parent_2, Py_ssize_t i)
565 {
565 {
566 if (parent_1 >= 0 && phases[parent_1] > phases[i])
566 if (parent_1 >= 0 && phases[parent_1] > phases[i])
567 phases[i] = phases[parent_1];
567 phases[i] = phases[parent_1];
568 if (parent_2 >= 0 && phases[parent_2] > phases[i])
568 if (parent_2 >= 0 && phases[parent_2] > phases[i])
569 phases[i] = phases[parent_2];
569 phases[i] = phases[parent_2];
570 }
570 }
571
571
572 static PyObject *reachableroots2(indexObject *self, PyObject *args)
572 static PyObject *reachableroots2(indexObject *self, PyObject *args)
573 {
573 {
574
574
575 /* Input */
575 /* Input */
576 long minroot;
576 long minroot;
577 PyObject *includepatharg = NULL;
577 PyObject *includepatharg = NULL;
578 int includepath = 0;
578 int includepath = 0;
579 /* heads and roots are lists */
579 /* heads and roots are lists */
580 PyObject *heads = NULL;
580 PyObject *heads = NULL;
581 PyObject *roots = NULL;
581 PyObject *roots = NULL;
582 PyObject *reachable = NULL;
582 PyObject *reachable = NULL;
583
583
584 PyObject *val;
584 PyObject *val;
585 Py_ssize_t len = index_length(self);
585 Py_ssize_t len = index_length(self);
586 long revnum;
586 long revnum;
587 Py_ssize_t k;
587 Py_ssize_t k;
588 Py_ssize_t i;
588 Py_ssize_t i;
589 Py_ssize_t l;
589 Py_ssize_t l;
590 int r;
590 int r;
591 int parents[2];
591 int parents[2];
592
592
593 /* Internal data structure:
593 /* Internal data structure:
594 * tovisit: array of length len+1 (all revs + nullrev), filled upto
594 * tovisit: array of length len+1 (all revs + nullrev), filled upto
595 * lentovisit
595 * lentovisit
596 *
596 *
597 * revstates: array of length len+1 (all revs + nullrev) */
597 * revstates: array of length len+1 (all revs + nullrev) */
598 int *tovisit = NULL;
598 int *tovisit = NULL;
599 long lentovisit = 0;
599 long lentovisit = 0;
600 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
600 enum { RS_SEEN = 1, RS_ROOT = 2, RS_REACHABLE = 4 };
601 char *revstates = NULL;
601 char *revstates = NULL;
602
602
603 /* Get arguments */
603 /* Get arguments */
604 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
604 if (!PyArg_ParseTuple(args, "lO!O!O!", &minroot, &PyList_Type, &heads,
605 &PyList_Type, &roots, &PyBool_Type,
605 &PyList_Type, &roots, &PyBool_Type,
606 &includepatharg))
606 &includepatharg))
607 goto bail;
607 goto bail;
608
608
609 if (includepatharg == Py_True)
609 if (includepatharg == Py_True)
610 includepath = 1;
610 includepath = 1;
611
611
612 /* Initialize return set */
612 /* Initialize return set */
613 reachable = PyList_New(0);
613 reachable = PyList_New(0);
614 if (reachable == NULL)
614 if (reachable == NULL)
615 goto bail;
615 goto bail;
616
616
617 /* Initialize internal datastructures */
617 /* Initialize internal datastructures */
618 tovisit = (int *)malloc((len + 1) * sizeof(int));
618 tovisit = (int *)malloc((len + 1) * sizeof(int));
619 if (tovisit == NULL) {
619 if (tovisit == NULL) {
620 PyErr_NoMemory();
620 PyErr_NoMemory();
621 goto bail;
621 goto bail;
622 }
622 }
623
623
624 revstates = (char *)calloc(len + 1, 1);
624 revstates = (char *)calloc(len + 1, 1);
625 if (revstates == NULL) {
625 if (revstates == NULL) {
626 PyErr_NoMemory();
626 PyErr_NoMemory();
627 goto bail;
627 goto bail;
628 }
628 }
629
629
630 l = PyList_GET_SIZE(roots);
630 l = PyList_GET_SIZE(roots);
631 for (i = 0; i < l; i++) {
631 for (i = 0; i < l; i++) {
632 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
632 revnum = PyInt_AsLong(PyList_GET_ITEM(roots, i));
633 if (revnum == -1 && PyErr_Occurred())
633 if (revnum == -1 && PyErr_Occurred())
634 goto bail;
634 goto bail;
635 /* If root is out of range, e.g. wdir(), it must be unreachable
635 /* If root is out of range, e.g. wdir(), it must be unreachable
636 * from heads. So we can just ignore it. */
636 * from heads. So we can just ignore it. */
637 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
637 if (revnum + 1 < 0 || revnum + 1 >= len + 1)
638 continue;
638 continue;
639 revstates[revnum + 1] |= RS_ROOT;
639 revstates[revnum + 1] |= RS_ROOT;
640 }
640 }
641
641
642 /* Populate tovisit with all the heads */
642 /* Populate tovisit with all the heads */
643 l = PyList_GET_SIZE(heads);
643 l = PyList_GET_SIZE(heads);
644 for (i = 0; i < l; i++) {
644 for (i = 0; i < l; i++) {
645 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
645 revnum = PyInt_AsLong(PyList_GET_ITEM(heads, i));
646 if (revnum == -1 && PyErr_Occurred())
646 if (revnum == -1 && PyErr_Occurred())
647 goto bail;
647 goto bail;
648 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
648 if (revnum + 1 < 0 || revnum + 1 >= len + 1) {
649 PyErr_SetString(PyExc_IndexError, "head out of range");
649 PyErr_SetString(PyExc_IndexError, "head out of range");
650 goto bail;
650 goto bail;
651 }
651 }
652 if (!(revstates[revnum + 1] & RS_SEEN)) {
652 if (!(revstates[revnum + 1] & RS_SEEN)) {
653 tovisit[lentovisit++] = (int)revnum;
653 tovisit[lentovisit++] = (int)revnum;
654 revstates[revnum + 1] |= RS_SEEN;
654 revstates[revnum + 1] |= RS_SEEN;
655 }
655 }
656 }
656 }
657
657
658 /* Visit the tovisit list and find the reachable roots */
658 /* Visit the tovisit list and find the reachable roots */
659 k = 0;
659 k = 0;
660 while (k < lentovisit) {
660 while (k < lentovisit) {
661 /* Add the node to reachable if it is a root*/
661 /* Add the node to reachable if it is a root*/
662 revnum = tovisit[k++];
662 revnum = tovisit[k++];
663 if (revstates[revnum + 1] & RS_ROOT) {
663 if (revstates[revnum + 1] & RS_ROOT) {
664 revstates[revnum + 1] |= RS_REACHABLE;
664 revstates[revnum + 1] |= RS_REACHABLE;
665 val = PyInt_FromLong(revnum);
665 val = PyInt_FromLong(revnum);
666 if (val == NULL)
666 if (val == NULL)
667 goto bail;
667 goto bail;
668 r = PyList_Append(reachable, val);
668 r = PyList_Append(reachable, val);
669 Py_DECREF(val);
669 Py_DECREF(val);
670 if (r < 0)
670 if (r < 0)
671 goto bail;
671 goto bail;
672 if (includepath == 0)
672 if (includepath == 0)
673 continue;
673 continue;
674 }
674 }
675
675
676 /* Add its parents to the list of nodes to visit */
676 /* Add its parents to the list of nodes to visit */
677 if (revnum == -1)
677 if (revnum == -1)
678 continue;
678 continue;
679 r = index_get_parents(self, revnum, parents, (int)len - 1);
679 r = index_get_parents(self, revnum, parents, (int)len - 1);
680 if (r < 0)
680 if (r < 0)
681 goto bail;
681 goto bail;
682 for (i = 0; i < 2; i++) {
682 for (i = 0; i < 2; i++) {
683 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
683 if (!(revstates[parents[i] + 1] & RS_SEEN) &&
684 parents[i] >= minroot) {
684 parents[i] >= minroot) {
685 tovisit[lentovisit++] = parents[i];
685 tovisit[lentovisit++] = parents[i];
686 revstates[parents[i] + 1] |= RS_SEEN;
686 revstates[parents[i] + 1] |= RS_SEEN;
687 }
687 }
688 }
688 }
689 }
689 }
690
690
691 /* Find all the nodes in between the roots we found and the heads
691 /* Find all the nodes in between the roots we found and the heads
692 * and add them to the reachable set */
692 * and add them to the reachable set */
693 if (includepath == 1) {
693 if (includepath == 1) {
694 long minidx = minroot;
694 long minidx = minroot;
695 if (minidx < 0)
695 if (minidx < 0)
696 minidx = 0;
696 minidx = 0;
697 for (i = minidx; i < len; i++) {
697 for (i = minidx; i < len; i++) {
698 if (!(revstates[i + 1] & RS_SEEN))
698 if (!(revstates[i + 1] & RS_SEEN))
699 continue;
699 continue;
700 r = index_get_parents(self, i, parents, (int)len - 1);
700 r = index_get_parents(self, i, parents, (int)len - 1);
701 /* Corrupted index file, error is set from
701 /* Corrupted index file, error is set from
702 * index_get_parents */
702 * index_get_parents */
703 if (r < 0)
703 if (r < 0)
704 goto bail;
704 goto bail;
705 if (((revstates[parents[0] + 1] |
705 if (((revstates[parents[0] + 1] |
706 revstates[parents[1] + 1]) &
706 revstates[parents[1] + 1]) &
707 RS_REACHABLE) &&
707 RS_REACHABLE) &&
708 !(revstates[i + 1] & RS_REACHABLE)) {
708 !(revstates[i + 1] & RS_REACHABLE)) {
709 revstates[i + 1] |= RS_REACHABLE;
709 revstates[i + 1] |= RS_REACHABLE;
710 val = PyInt_FromSsize_t(i);
710 val = PyInt_FromSsize_t(i);
711 if (val == NULL)
711 if (val == NULL)
712 goto bail;
712 goto bail;
713 r = PyList_Append(reachable, val);
713 r = PyList_Append(reachable, val);
714 Py_DECREF(val);
714 Py_DECREF(val);
715 if (r < 0)
715 if (r < 0)
716 goto bail;
716 goto bail;
717 }
717 }
718 }
718 }
719 }
719 }
720
720
721 free(revstates);
721 free(revstates);
722 free(tovisit);
722 free(tovisit);
723 return reachable;
723 return reachable;
724 bail:
724 bail:
725 Py_XDECREF(reachable);
725 Py_XDECREF(reachable);
726 free(revstates);
726 free(revstates);
727 free(tovisit);
727 free(tovisit);
728 return NULL;
728 return NULL;
729 }
729 }
730
730
731 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
731 static PyObject *compute_phases_map_sets(indexObject *self, PyObject *args)
732 {
732 {
733 PyObject *roots = Py_None;
733 PyObject *roots = Py_None;
734 PyObject *ret = NULL;
734 PyObject *ret = NULL;
735 PyObject *phasessize = NULL;
735 PyObject *phasessize = NULL;
736 PyObject *phaseroots = NULL;
736 PyObject *phaseroots = NULL;
737 PyObject *phaseset = NULL;
737 PyObject *phaseset = NULL;
738 PyObject *phasessetlist = NULL;
738 PyObject *phasessetlist = NULL;
739 PyObject *rev = NULL;
739 PyObject *rev = NULL;
740 Py_ssize_t len = index_length(self);
740 Py_ssize_t len = index_length(self);
741 Py_ssize_t numphase = 0;
741 Py_ssize_t numphase = 0;
742 Py_ssize_t minrevallphases = 0;
742 Py_ssize_t minrevallphases = 0;
743 Py_ssize_t minrevphase = 0;
743 Py_ssize_t minrevphase = 0;
744 Py_ssize_t i = 0;
744 Py_ssize_t i = 0;
745 char *phases = NULL;
745 char *phases = NULL;
746 long phase;
746 long phase;
747
747
748 if (!PyArg_ParseTuple(args, "O", &roots))
748 if (!PyArg_ParseTuple(args, "O", &roots))
749 goto done;
749 goto done;
750 if (roots == NULL || !PyList_Check(roots)) {
750 if (roots == NULL || !PyList_Check(roots)) {
751 PyErr_SetString(PyExc_TypeError, "roots must be a list");
751 PyErr_SetString(PyExc_TypeError, "roots must be a list");
752 goto done;
752 goto done;
753 }
753 }
754
754
755 phases = calloc(
755 phases = calloc(
756 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
756 len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
757 if (phases == NULL) {
757 if (phases == NULL) {
758 PyErr_NoMemory();
758 PyErr_NoMemory();
759 goto done;
759 goto done;
760 }
760 }
761 /* Put the phase information of all the roots in phases */
761 /* Put the phase information of all the roots in phases */
762 numphase = PyList_GET_SIZE(roots) + 1;
762 numphase = PyList_GET_SIZE(roots) + 1;
763 minrevallphases = len + 1;
763 minrevallphases = len + 1;
764 phasessetlist = PyList_New(numphase);
764 phasessetlist = PyList_New(numphase);
765 if (phasessetlist == NULL)
765 if (phasessetlist == NULL)
766 goto done;
766 goto done;
767
767
768 PyList_SET_ITEM(phasessetlist, 0, Py_None);
768 PyList_SET_ITEM(phasessetlist, 0, Py_None);
769 Py_INCREF(Py_None);
769 Py_INCREF(Py_None);
770
770
771 for (i = 0; i < numphase - 1; i++) {
771 for (i = 0; i < numphase - 1; i++) {
772 phaseroots = PyList_GET_ITEM(roots, i);
772 phaseroots = PyList_GET_ITEM(roots, i);
773 phaseset = PySet_New(NULL);
773 phaseset = PySet_New(NULL);
774 if (phaseset == NULL)
774 if (phaseset == NULL)
775 goto release;
775 goto release;
776 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
776 PyList_SET_ITEM(phasessetlist, i + 1, phaseset);
777 if (!PyList_Check(phaseroots)) {
777 if (!PyList_Check(phaseroots)) {
778 PyErr_SetString(PyExc_TypeError,
778 PyErr_SetString(PyExc_TypeError,
779 "roots item must be a list");
779 "roots item must be a list");
780 goto release;
780 goto release;
781 }
781 }
782 minrevphase =
782 minrevphase =
783 add_roots_get_min(self, phaseroots, i + 1, phases);
783 add_roots_get_min(self, phaseroots, i + 1, phases);
784 if (minrevphase == -2) /* Error from add_roots_get_min */
784 if (minrevphase == -2) /* Error from add_roots_get_min */
785 goto release;
785 goto release;
786 minrevallphases = MIN(minrevallphases, minrevphase);
786 minrevallphases = MIN(minrevallphases, minrevphase);
787 }
787 }
788 /* Propagate the phase information from the roots to the revs */
788 /* Propagate the phase information from the roots to the revs */
789 if (minrevallphases != -1) {
789 if (minrevallphases != -1) {
790 int parents[2];
790 int parents[2];
791 for (i = minrevallphases; i < len; i++) {
791 for (i = minrevallphases; i < len; i++) {
792 if (index_get_parents(self, i, parents, (int)len - 1) <
792 if (index_get_parents(self, i, parents, (int)len - 1) <
793 0)
793 0)
794 goto release;
794 goto release;
795 set_phase_from_parents(phases, parents[0], parents[1],
795 set_phase_from_parents(phases, parents[0], parents[1],
796 i);
796 i);
797 }
797 }
798 }
798 }
799 /* Transform phase list to a python list */
799 /* Transform phase list to a python list */
800 phasessize = PyInt_FromSsize_t(len);
800 phasessize = PyInt_FromSsize_t(len);
801 if (phasessize == NULL)
801 if (phasessize == NULL)
802 goto release;
802 goto release;
803 for (i = 0; i < len; i++) {
803 for (i = 0; i < len; i++) {
804 phase = phases[i];
804 phase = phases[i];
805 /* We only store the sets of phase for non public phase, the
805 /* We only store the sets of phase for non public phase, the
806 * public phase is computed as a difference */
806 * public phase is computed as a difference */
807 if (phase != 0) {
807 if (phase != 0) {
808 phaseset = PyList_GET_ITEM(phasessetlist, phase);
808 phaseset = PyList_GET_ITEM(phasessetlist, phase);
809 rev = PyInt_FromSsize_t(i);
809 rev = PyInt_FromSsize_t(i);
810 if (rev == NULL)
810 if (rev == NULL)
811 goto release;
811 goto release;
812 PySet_Add(phaseset, rev);
812 PySet_Add(phaseset, rev);
813 Py_XDECREF(rev);
813 Py_XDECREF(rev);
814 }
814 }
815 }
815 }
816 ret = PyTuple_Pack(2, phasessize, phasessetlist);
816 ret = PyTuple_Pack(2, phasessize, phasessetlist);
817
817
818 release:
818 release:
819 Py_XDECREF(phasessize);
819 Py_XDECREF(phasessize);
820 Py_XDECREF(phasessetlist);
820 Py_XDECREF(phasessetlist);
821 done:
821 done:
822 free(phases);
822 free(phases);
823 return ret;
823 return ret;
824 }
824 }
825
825
826 static PyObject *index_headrevs(indexObject *self, PyObject *args)
826 static PyObject *index_headrevs(indexObject *self, PyObject *args)
827 {
827 {
828 Py_ssize_t i, j, len;
828 Py_ssize_t i, j, len;
829 char *nothead = NULL;
829 char *nothead = NULL;
830 PyObject *heads = NULL;
830 PyObject *heads = NULL;
831 PyObject *filter = NULL;
831 PyObject *filter = NULL;
832 PyObject *filteredrevs = Py_None;
832 PyObject *filteredrevs = Py_None;
833
833
834 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
834 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
835 return NULL;
835 return NULL;
836 }
836 }
837
837
838 if (self->headrevs && filteredrevs == self->filteredrevs)
838 if (self->headrevs && filteredrevs == self->filteredrevs)
839 return list_copy(self->headrevs);
839 return list_copy(self->headrevs);
840
840
841 Py_DECREF(self->filteredrevs);
841 Py_DECREF(self->filteredrevs);
842 self->filteredrevs = filteredrevs;
842 self->filteredrevs = filteredrevs;
843 Py_INCREF(filteredrevs);
843 Py_INCREF(filteredrevs);
844
844
845 if (filteredrevs != Py_None) {
845 if (filteredrevs != Py_None) {
846 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
846 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
847 if (!filter) {
847 if (!filter) {
848 PyErr_SetString(
848 PyErr_SetString(
849 PyExc_TypeError,
849 PyExc_TypeError,
850 "filteredrevs has no attribute __contains__");
850 "filteredrevs has no attribute __contains__");
851 goto bail;
851 goto bail;
852 }
852 }
853 }
853 }
854
854
855 len = index_length(self);
855 len = index_length(self);
856 heads = PyList_New(0);
856 heads = PyList_New(0);
857 if (heads == NULL)
857 if (heads == NULL)
858 goto bail;
858 goto bail;
859 if (len == 0) {
859 if (len == 0) {
860 PyObject *nullid = PyInt_FromLong(-1);
860 PyObject *nullid = PyInt_FromLong(-1);
861 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
861 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
862 Py_XDECREF(nullid);
862 Py_XDECREF(nullid);
863 goto bail;
863 goto bail;
864 }
864 }
865 goto done;
865 goto done;
866 }
866 }
867
867
868 nothead = calloc(len, 1);
868 nothead = calloc(len, 1);
869 if (nothead == NULL) {
869 if (nothead == NULL) {
870 PyErr_NoMemory();
870 PyErr_NoMemory();
871 goto bail;
871 goto bail;
872 }
872 }
873
873
874 for (i = len - 1; i >= 0; i--) {
874 for (i = len - 1; i >= 0; i--) {
875 int isfiltered;
875 int isfiltered;
876 int parents[2];
876 int parents[2];
877
877
878 /* If nothead[i] == 1, it means we've seen an unfiltered child
878 /* If nothead[i] == 1, it means we've seen an unfiltered child
879 * of this node already, and therefore this node is not
879 * of this node already, and therefore this node is not
880 * filtered. So we can skip the expensive check_filter step.
880 * filtered. So we can skip the expensive check_filter step.
881 */
881 */
882 if (nothead[i] != 1) {
882 if (nothead[i] != 1) {
883 isfiltered = check_filter(filter, i);
883 isfiltered = check_filter(filter, i);
884 if (isfiltered == -1) {
884 if (isfiltered == -1) {
885 PyErr_SetString(PyExc_TypeError,
885 PyErr_SetString(PyExc_TypeError,
886 "unable to check filter");
886 "unable to check filter");
887 goto bail;
887 goto bail;
888 }
888 }
889
889
890 if (isfiltered) {
890 if (isfiltered) {
891 nothead[i] = 1;
891 nothead[i] = 1;
892 continue;
892 continue;
893 }
893 }
894 }
894 }
895
895
896 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
896 if (index_get_parents(self, i, parents, (int)len - 1) < 0)
897 goto bail;
897 goto bail;
898 for (j = 0; j < 2; j++) {
898 for (j = 0; j < 2; j++) {
899 if (parents[j] >= 0)
899 if (parents[j] >= 0)
900 nothead[parents[j]] = 1;
900 nothead[parents[j]] = 1;
901 }
901 }
902 }
902 }
903
903
904 for (i = 0; i < len; i++) {
904 for (i = 0; i < len; i++) {
905 PyObject *head;
905 PyObject *head;
906
906
907 if (nothead[i])
907 if (nothead[i])
908 continue;
908 continue;
909 head = PyInt_FromSsize_t(i);
909 head = PyInt_FromSsize_t(i);
910 if (head == NULL || PyList_Append(heads, head) == -1) {
910 if (head == NULL || PyList_Append(heads, head) == -1) {
911 Py_XDECREF(head);
911 Py_XDECREF(head);
912 goto bail;
912 goto bail;
913 }
913 }
914 }
914 }
915
915
916 done:
916 done:
917 self->headrevs = heads;
917 self->headrevs = heads;
918 Py_XDECREF(filter);
918 Py_XDECREF(filter);
919 free(nothead);
919 free(nothead);
920 return list_copy(self->headrevs);
920 return list_copy(self->headrevs);
921 bail:
921 bail:
922 Py_XDECREF(filter);
922 Py_XDECREF(filter);
923 Py_XDECREF(heads);
923 Py_XDECREF(heads);
924 free(nothead);
924 free(nothead);
925 return NULL;
925 return NULL;
926 }
926 }
927
927
928 /**
928 /**
929 * Obtain the base revision index entry.
929 * Obtain the base revision index entry.
930 *
930 *
931 * Callers must ensure that rev >= 0 or illegal memory access may occur.
931 * Callers must ensure that rev >= 0 or illegal memory access may occur.
932 */
932 */
933 static inline int index_baserev(indexObject *self, int rev)
933 static inline int index_baserev(indexObject *self, int rev)
934 {
934 {
935 const char *data;
935 const char *data;
936
936
937 if (rev >= self->length) {
937 if (rev >= self->length) {
938 PyObject *tuple =
938 PyObject *tuple =
939 PyList_GET_ITEM(self->added, rev - self->length);
939 PyList_GET_ITEM(self->added, rev - self->length);
940 long ret;
940 long ret;
941 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
941 if (!pylong_to_long(PyTuple_GET_ITEM(tuple, 3), &ret)) {
942 return -2;
942 return -2;
943 }
943 }
944 return (int)ret;
944 return (int)ret;
945 } else {
945 } else {
946 data = index_deref(self, rev);
946 data = index_deref(self, rev);
947 if (data == NULL) {
947 if (data == NULL) {
948 return -2;
948 return -2;
949 }
949 }
950
950
951 return getbe32(data + 16);
951 return getbe32(data + 16);
952 }
952 }
953 }
953 }
954
954
955 static PyObject *index_deltachain(indexObject *self, PyObject *args)
955 static PyObject *index_deltachain(indexObject *self, PyObject *args)
956 {
956 {
957 int rev, generaldelta;
957 int rev, generaldelta;
958 PyObject *stoparg;
958 PyObject *stoparg;
959 int stoprev, iterrev, baserev = -1;
959 int stoprev, iterrev, baserev = -1;
960 int stopped;
960 int stopped;
961 PyObject *chain = NULL, *result = NULL;
961 PyObject *chain = NULL, *result = NULL;
962 const Py_ssize_t length = index_length(self);
962 const Py_ssize_t length = index_length(self);
963
963
964 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
964 if (!PyArg_ParseTuple(args, "iOi", &rev, &stoparg, &generaldelta)) {
965 return NULL;
965 return NULL;
966 }
966 }
967
967
968 if (PyInt_Check(stoparg)) {
968 if (PyInt_Check(stoparg)) {
969 stoprev = (int)PyInt_AsLong(stoparg);
969 stoprev = (int)PyInt_AsLong(stoparg);
970 if (stoprev == -1 && PyErr_Occurred()) {
970 if (stoprev == -1 && PyErr_Occurred()) {
971 return NULL;
971 return NULL;
972 }
972 }
973 } else if (stoparg == Py_None) {
973 } else if (stoparg == Py_None) {
974 stoprev = -2;
974 stoprev = -2;
975 } else {
975 } else {
976 PyErr_SetString(PyExc_ValueError,
976 PyErr_SetString(PyExc_ValueError,
977 "stoprev must be integer or None");
977 "stoprev must be integer or None");
978 return NULL;
978 return NULL;
979 }
979 }
980
980
981 if (rev < 0 || rev >= length) {
981 if (rev < 0 || rev >= length) {
982 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
982 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
983 return NULL;
983 return NULL;
984 }
984 }
985
985
986 chain = PyList_New(0);
986 chain = PyList_New(0);
987 if (chain == NULL) {
987 if (chain == NULL) {
988 return NULL;
988 return NULL;
989 }
989 }
990
990
991 baserev = index_baserev(self, rev);
991 baserev = index_baserev(self, rev);
992
992
993 /* This should never happen. */
993 /* This should never happen. */
994 if (baserev <= -2) {
994 if (baserev <= -2) {
995 /* Error should be set by index_deref() */
995 /* Error should be set by index_deref() */
996 assert(PyErr_Occurred());
996 assert(PyErr_Occurred());
997 goto bail;
997 goto bail;
998 }
998 }
999
999
1000 iterrev = rev;
1000 iterrev = rev;
1001
1001
1002 while (iterrev != baserev && iterrev != stoprev) {
1002 while (iterrev != baserev && iterrev != stoprev) {
1003 PyObject *value = PyInt_FromLong(iterrev);
1003 PyObject *value = PyInt_FromLong(iterrev);
1004 if (value == NULL) {
1004 if (value == NULL) {
1005 goto bail;
1005 goto bail;
1006 }
1006 }
1007 if (PyList_Append(chain, value)) {
1007 if (PyList_Append(chain, value)) {
1008 Py_DECREF(value);
1008 Py_DECREF(value);
1009 goto bail;
1009 goto bail;
1010 }
1010 }
1011 Py_DECREF(value);
1011 Py_DECREF(value);
1012
1012
1013 if (generaldelta) {
1013 if (generaldelta) {
1014 iterrev = baserev;
1014 iterrev = baserev;
1015 } else {
1015 } else {
1016 iterrev--;
1016 iterrev--;
1017 }
1017 }
1018
1018
1019 if (iterrev < 0) {
1019 if (iterrev < 0) {
1020 break;
1020 break;
1021 }
1021 }
1022
1022
1023 if (iterrev >= length) {
1023 if (iterrev >= length) {
1024 PyErr_SetString(PyExc_IndexError,
1024 PyErr_SetString(PyExc_IndexError,
1025 "revision outside index");
1025 "revision outside index");
1026 return NULL;
1026 return NULL;
1027 }
1027 }
1028
1028
1029 baserev = index_baserev(self, iterrev);
1029 baserev = index_baserev(self, iterrev);
1030
1030
1031 /* This should never happen. */
1031 /* This should never happen. */
1032 if (baserev <= -2) {
1032 if (baserev <= -2) {
1033 /* Error should be set by index_deref() */
1033 /* Error should be set by index_deref() */
1034 assert(PyErr_Occurred());
1034 assert(PyErr_Occurred());
1035 goto bail;
1035 goto bail;
1036 }
1036 }
1037 }
1037 }
1038
1038
1039 if (iterrev == stoprev) {
1039 if (iterrev == stoprev) {
1040 stopped = 1;
1040 stopped = 1;
1041 } else {
1041 } else {
1042 PyObject *value = PyInt_FromLong(iterrev);
1042 PyObject *value = PyInt_FromLong(iterrev);
1043 if (value == NULL) {
1043 if (value == NULL) {
1044 goto bail;
1044 goto bail;
1045 }
1045 }
1046 if (PyList_Append(chain, value)) {
1046 if (PyList_Append(chain, value)) {
1047 Py_DECREF(value);
1047 Py_DECREF(value);
1048 goto bail;
1048 goto bail;
1049 }
1049 }
1050 Py_DECREF(value);
1050 Py_DECREF(value);
1051
1051
1052 stopped = 0;
1052 stopped = 0;
1053 }
1053 }
1054
1054
1055 if (PyList_Reverse(chain)) {
1055 if (PyList_Reverse(chain)) {
1056 goto bail;
1056 goto bail;
1057 }
1057 }
1058
1058
1059 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1059 result = Py_BuildValue("OO", chain, stopped ? Py_True : Py_False);
1060 Py_DECREF(chain);
1060 Py_DECREF(chain);
1061 return result;
1061 return result;
1062
1062
1063 bail:
1063 bail:
1064 Py_DECREF(chain);
1064 Py_DECREF(chain);
1065 return NULL;
1065 return NULL;
1066 }
1066 }
1067
1067
1068 static inline int64_t
1068 static inline int64_t
1069 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1069 index_segment_span(indexObject *self, Py_ssize_t start_rev, Py_ssize_t end_rev)
1070 {
1070 {
1071 int64_t start_offset;
1071 int64_t start_offset;
1072 int64_t end_offset;
1072 int64_t end_offset;
1073 int end_size;
1073 int end_size;
1074 start_offset = index_get_start(self, start_rev);
1074 start_offset = index_get_start(self, start_rev);
1075 if (start_offset < 0) {
1075 if (start_offset < 0) {
1076 return -1;
1076 return -1;
1077 }
1077 }
1078 end_offset = index_get_start(self, end_rev);
1078 end_offset = index_get_start(self, end_rev);
1079 if (end_offset < 0) {
1079 if (end_offset < 0) {
1080 return -1;
1080 return -1;
1081 }
1081 }
1082 end_size = index_get_length(self, end_rev);
1082 end_size = index_get_length(self, end_rev);
1083 if (end_size < 0) {
1083 if (end_size < 0) {
1084 return -1;
1084 return -1;
1085 }
1085 }
1086 if (end_offset < start_offset) {
1086 if (end_offset < start_offset) {
1087 PyErr_Format(PyExc_ValueError,
1087 PyErr_Format(PyExc_ValueError,
1088 "corrupted revlog index: inconsistent offset "
1088 "corrupted revlog index: inconsistent offset "
1089 "between revisions (%zd) and (%zd)",
1089 "between revisions (%zd) and (%zd)",
1090 start_rev, end_rev);
1090 start_rev, end_rev);
1091 return -1;
1091 return -1;
1092 }
1092 }
1093 return (end_offset - start_offset) + (int64_t)end_size;
1093 return (end_offset - start_offset) + (int64_t)end_size;
1094 }
1094 }
1095
1095
1096 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1096 /* returns endidx so that revs[startidx:endidx] has no empty trailing revs */
1097 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1097 static Py_ssize_t trim_endidx(indexObject *self, const Py_ssize_t *revs,
1098 Py_ssize_t startidx, Py_ssize_t endidx)
1098 Py_ssize_t startidx, Py_ssize_t endidx)
1099 {
1099 {
1100 int length;
1100 int length;
1101 while (endidx > 1 && endidx > startidx) {
1101 while (endidx > 1 && endidx > startidx) {
1102 length = index_get_length(self, revs[endidx - 1]);
1102 length = index_get_length(self, revs[endidx - 1]);
1103 if (length < 0) {
1103 if (length < 0) {
1104 return -1;
1104 return -1;
1105 }
1105 }
1106 if (length != 0) {
1106 if (length != 0) {
1107 break;
1107 break;
1108 }
1108 }
1109 endidx -= 1;
1109 endidx -= 1;
1110 }
1110 }
1111 return endidx;
1111 return endidx;
1112 }
1112 }
1113
1113
1114 struct Gap {
1114 struct Gap {
1115 int64_t size;
1115 int64_t size;
1116 Py_ssize_t idx;
1116 Py_ssize_t idx;
1117 };
1117 };
1118
1118
1119 static int gap_compare(const void *left, const void *right)
1119 static int gap_compare(const void *left, const void *right)
1120 {
1120 {
1121 const struct Gap *l_left = ((const struct Gap *)left);
1121 const struct Gap *l_left = ((const struct Gap *)left);
1122 const struct Gap *l_right = ((const struct Gap *)right);
1122 const struct Gap *l_right = ((const struct Gap *)right);
1123 if (l_left->size < l_right->size) {
1123 if (l_left->size < l_right->size) {
1124 return -1;
1124 return -1;
1125 } else if (l_left->size > l_right->size) {
1125 } else if (l_left->size > l_right->size) {
1126 return 1;
1126 return 1;
1127 }
1127 }
1128 return 0;
1128 return 0;
1129 }
1129 }
1130 static int Py_ssize_t_compare(const void *left, const void *right)
1130 static int Py_ssize_t_compare(const void *left, const void *right)
1131 {
1131 {
1132 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1132 const Py_ssize_t l_left = *(const Py_ssize_t *)left;
1133 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1133 const Py_ssize_t l_right = *(const Py_ssize_t *)right;
1134 if (l_left < l_right) {
1134 if (l_left < l_right) {
1135 return -1;
1135 return -1;
1136 } else if (l_left > l_right) {
1136 } else if (l_left > l_right) {
1137 return 1;
1137 return 1;
1138 }
1138 }
1139 return 0;
1139 return 0;
1140 }
1140 }
1141
1141
1142 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1142 static PyObject *index_slicechunktodensity(indexObject *self, PyObject *args)
1143 {
1143 {
1144 /* method arguments */
1144 /* method arguments */
1145 PyObject *list_revs = NULL; /* revisions in the chain */
1145 PyObject *list_revs = NULL; /* revisions in the chain */
1146 double targetdensity = 0; /* min density to achieve */
1146 double targetdensity = 0; /* min density to achieve */
1147 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1147 Py_ssize_t mingapsize = 0; /* threshold to ignore gaps */
1148
1148
1149 /* other core variables */
1149 /* other core variables */
1150 Py_ssize_t idxlen = index_length(self);
1150 Py_ssize_t idxlen = index_length(self);
1151 Py_ssize_t i; /* used for various iteration */
1151 Py_ssize_t i; /* used for various iteration */
1152 PyObject *result = NULL; /* the final return of the function */
1152 PyObject *result = NULL; /* the final return of the function */
1153
1153
1154 /* generic information about the delta chain being slice */
1154 /* generic information about the delta chain being slice */
1155 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1155 Py_ssize_t num_revs = 0; /* size of the full delta chain */
1156 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1156 Py_ssize_t *revs = NULL; /* native array of revision in the chain */
1157 int64_t chainpayload = 0; /* sum of all delta in the chain */
1157 int64_t chainpayload = 0; /* sum of all delta in the chain */
1158 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1158 int64_t deltachainspan = 0; /* distance from first byte to last byte */
1159
1159
1160 /* variable used for slicing the delta chain */
1160 /* variable used for slicing the delta chain */
1161 int64_t readdata = 0; /* amount of data currently planned to be read */
1161 int64_t readdata = 0; /* amount of data currently planned to be read */
1162 double density = 0; /* ration of payload data compared to read ones */
1162 double density = 0; /* ration of payload data compared to read ones */
1163 int64_t previous_end;
1163 int64_t previous_end;
1164 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1164 struct Gap *gaps = NULL; /* array of notable gap in the chain */
1165 Py_ssize_t num_gaps =
1165 Py_ssize_t num_gaps =
1166 0; /* total number of notable gap recorded so far */
1166 0; /* total number of notable gap recorded so far */
1167 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1167 Py_ssize_t *selected_indices = NULL; /* indices of gap skipped over */
1168 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1168 Py_ssize_t num_selected = 0; /* number of gaps skipped */
1169 PyObject *chunk = NULL; /* individual slice */
1169 PyObject *chunk = NULL; /* individual slice */
1170 PyObject *allchunks = NULL; /* all slices */
1170 PyObject *allchunks = NULL; /* all slices */
1171 Py_ssize_t previdx;
1171 Py_ssize_t previdx;
1172
1172
1173 /* parsing argument */
1173 /* parsing argument */
1174 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1174 if (!PyArg_ParseTuple(args, "O!dn", &PyList_Type, &list_revs,
1175 &targetdensity, &mingapsize)) {
1175 &targetdensity, &mingapsize)) {
1176 goto bail;
1176 goto bail;
1177 }
1177 }
1178
1178
1179 /* If the delta chain contains a single element, we do not need slicing
1179 /* If the delta chain contains a single element, we do not need slicing
1180 */
1180 */
1181 num_revs = PyList_GET_SIZE(list_revs);
1181 num_revs = PyList_GET_SIZE(list_revs);
1182 if (num_revs <= 1) {
1182 if (num_revs <= 1) {
1183 result = PyTuple_Pack(1, list_revs);
1183 result = PyTuple_Pack(1, list_revs);
1184 goto done;
1184 goto done;
1185 }
1185 }
1186
1186
1187 /* Turn the python list into a native integer array (for efficiency) */
1187 /* Turn the python list into a native integer array (for efficiency) */
1188 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1188 revs = (Py_ssize_t *)calloc(num_revs, sizeof(Py_ssize_t));
1189 if (revs == NULL) {
1189 if (revs == NULL) {
1190 PyErr_NoMemory();
1190 PyErr_NoMemory();
1191 goto bail;
1191 goto bail;
1192 }
1192 }
1193 for (i = 0; i < num_revs; i++) {
1193 for (i = 0; i < num_revs; i++) {
1194 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1194 Py_ssize_t revnum = PyInt_AsLong(PyList_GET_ITEM(list_revs, i));
1195 if (revnum == -1 && PyErr_Occurred()) {
1195 if (revnum == -1 && PyErr_Occurred()) {
1196 goto bail;
1196 goto bail;
1197 }
1197 }
1198 if (revnum < 0 || revnum >= idxlen) {
1198 if (revnum < 0 || revnum >= idxlen) {
1199 PyErr_Format(PyExc_IndexError,
1199 PyErr_Format(PyExc_IndexError,
1200 "index out of range: %zd", revnum);
1200 "index out of range: %zd", revnum);
1201 goto bail;
1201 goto bail;
1202 }
1202 }
1203 revs[i] = revnum;
1203 revs[i] = revnum;
1204 }
1204 }
1205
1205
1206 /* Compute and check various property of the unsliced delta chain */
1206 /* Compute and check various property of the unsliced delta chain */
1207 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1207 deltachainspan = index_segment_span(self, revs[0], revs[num_revs - 1]);
1208 if (deltachainspan < 0) {
1208 if (deltachainspan < 0) {
1209 goto bail;
1209 goto bail;
1210 }
1210 }
1211
1211
1212 if (deltachainspan <= mingapsize) {
1212 if (deltachainspan <= mingapsize) {
1213 result = PyTuple_Pack(1, list_revs);
1213 result = PyTuple_Pack(1, list_revs);
1214 goto done;
1214 goto done;
1215 }
1215 }
1216 chainpayload = 0;
1216 chainpayload = 0;
1217 for (i = 0; i < num_revs; i++) {
1217 for (i = 0; i < num_revs; i++) {
1218 int tmp = index_get_length(self, revs[i]);
1218 int tmp = index_get_length(self, revs[i]);
1219 if (tmp < 0) {
1219 if (tmp < 0) {
1220 goto bail;
1220 goto bail;
1221 }
1221 }
1222 chainpayload += tmp;
1222 chainpayload += tmp;
1223 }
1223 }
1224
1224
1225 readdata = deltachainspan;
1225 readdata = deltachainspan;
1226 density = 1.0;
1226 density = 1.0;
1227
1227
1228 if (0 < deltachainspan) {
1228 if (0 < deltachainspan) {
1229 density = (double)chainpayload / (double)deltachainspan;
1229 density = (double)chainpayload / (double)deltachainspan;
1230 }
1230 }
1231
1231
1232 if (density >= targetdensity) {
1232 if (density >= targetdensity) {
1233 result = PyTuple_Pack(1, list_revs);
1233 result = PyTuple_Pack(1, list_revs);
1234 goto done;
1234 goto done;
1235 }
1235 }
1236
1236
1237 /* if chain is too sparse, look for relevant gaps */
1237 /* if chain is too sparse, look for relevant gaps */
1238 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1238 gaps = (struct Gap *)calloc(num_revs, sizeof(struct Gap));
1239 if (gaps == NULL) {
1239 if (gaps == NULL) {
1240 PyErr_NoMemory();
1240 PyErr_NoMemory();
1241 goto bail;
1241 goto bail;
1242 }
1242 }
1243
1243
1244 previous_end = -1;
1244 previous_end = -1;
1245 for (i = 0; i < num_revs; i++) {
1245 for (i = 0; i < num_revs; i++) {
1246 int64_t revstart;
1246 int64_t revstart;
1247 int revsize;
1247 int revsize;
1248 revstart = index_get_start(self, revs[i]);
1248 revstart = index_get_start(self, revs[i]);
1249 if (revstart < 0) {
1249 if (revstart < 0) {
1250 goto bail;
1250 goto bail;
1251 };
1251 };
1252 revsize = index_get_length(self, revs[i]);
1252 revsize = index_get_length(self, revs[i]);
1253 if (revsize < 0) {
1253 if (revsize < 0) {
1254 goto bail;
1254 goto bail;
1255 };
1255 };
1256 if (revsize == 0) {
1256 if (revsize == 0) {
1257 continue;
1257 continue;
1258 }
1258 }
1259 if (previous_end >= 0) {
1259 if (previous_end >= 0) {
1260 int64_t gapsize = revstart - previous_end;
1260 int64_t gapsize = revstart - previous_end;
1261 if (gapsize > mingapsize) {
1261 if (gapsize > mingapsize) {
1262 gaps[num_gaps].size = gapsize;
1262 gaps[num_gaps].size = gapsize;
1263 gaps[num_gaps].idx = i;
1263 gaps[num_gaps].idx = i;
1264 num_gaps += 1;
1264 num_gaps += 1;
1265 }
1265 }
1266 }
1266 }
1267 previous_end = revstart + revsize;
1267 previous_end = revstart + revsize;
1268 }
1268 }
1269 if (num_gaps == 0) {
1269 if (num_gaps == 0) {
1270 result = PyTuple_Pack(1, list_revs);
1270 result = PyTuple_Pack(1, list_revs);
1271 goto done;
1271 goto done;
1272 }
1272 }
1273 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1273 qsort(gaps, num_gaps, sizeof(struct Gap), &gap_compare);
1274
1274
1275 /* Slice the largest gap first, they improve the density the most */
1275 /* Slice the largest gap first, they improve the density the most */
1276 selected_indices =
1276 selected_indices =
1277 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1277 (Py_ssize_t *)malloc((num_gaps + 1) * sizeof(Py_ssize_t));
1278 if (selected_indices == NULL) {
1278 if (selected_indices == NULL) {
1279 PyErr_NoMemory();
1279 PyErr_NoMemory();
1280 goto bail;
1280 goto bail;
1281 }
1281 }
1282
1282
1283 for (i = num_gaps - 1; i >= 0; i--) {
1283 for (i = num_gaps - 1; i >= 0; i--) {
1284 selected_indices[num_selected] = gaps[i].idx;
1284 selected_indices[num_selected] = gaps[i].idx;
1285 readdata -= gaps[i].size;
1285 readdata -= gaps[i].size;
1286 num_selected += 1;
1286 num_selected += 1;
1287 if (readdata <= 0) {
1287 if (readdata <= 0) {
1288 density = 1.0;
1288 density = 1.0;
1289 } else {
1289 } else {
1290 density = (double)chainpayload / (double)readdata;
1290 density = (double)chainpayload / (double)readdata;
1291 }
1291 }
1292 if (density >= targetdensity) {
1292 if (density >= targetdensity) {
1293 break;
1293 break;
1294 }
1294 }
1295 }
1295 }
1296 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1296 qsort(selected_indices, num_selected, sizeof(Py_ssize_t),
1297 &Py_ssize_t_compare);
1297 &Py_ssize_t_compare);
1298
1298
1299 /* create the resulting slice */
1299 /* create the resulting slice */
1300 allchunks = PyList_New(0);
1300 allchunks = PyList_New(0);
1301 if (allchunks == NULL) {
1301 if (allchunks == NULL) {
1302 goto bail;
1302 goto bail;
1303 }
1303 }
1304 previdx = 0;
1304 previdx = 0;
1305 selected_indices[num_selected] = num_revs;
1305 selected_indices[num_selected] = num_revs;
1306 for (i = 0; i <= num_selected; i++) {
1306 for (i = 0; i <= num_selected; i++) {
1307 Py_ssize_t idx = selected_indices[i];
1307 Py_ssize_t idx = selected_indices[i];
1308 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1308 Py_ssize_t endidx = trim_endidx(self, revs, previdx, idx);
1309 if (endidx < 0) {
1309 if (endidx < 0) {
1310 goto bail;
1310 goto bail;
1311 }
1311 }
1312 if (previdx < endidx) {
1312 if (previdx < endidx) {
1313 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1313 chunk = PyList_GetSlice(list_revs, previdx, endidx);
1314 if (chunk == NULL) {
1314 if (chunk == NULL) {
1315 goto bail;
1315 goto bail;
1316 }
1316 }
1317 if (PyList_Append(allchunks, chunk) == -1) {
1317 if (PyList_Append(allchunks, chunk) == -1) {
1318 goto bail;
1318 goto bail;
1319 }
1319 }
1320 Py_DECREF(chunk);
1320 Py_DECREF(chunk);
1321 chunk = NULL;
1321 chunk = NULL;
1322 }
1322 }
1323 previdx = idx;
1323 previdx = idx;
1324 }
1324 }
1325 result = allchunks;
1325 result = allchunks;
1326 goto done;
1326 goto done;
1327
1327
1328 bail:
1328 bail:
1329 Py_XDECREF(allchunks);
1329 Py_XDECREF(allchunks);
1330 Py_XDECREF(chunk);
1330 Py_XDECREF(chunk);
1331 done:
1331 done:
1332 free(revs);
1332 free(revs);
1333 free(gaps);
1333 free(gaps);
1334 free(selected_indices);
1334 free(selected_indices);
1335 return result;
1335 return result;
1336 }
1336 }
1337
1337
1338 static inline int nt_level(const char *node, Py_ssize_t level)
1338 static inline int nt_level(const char *node, Py_ssize_t level)
1339 {
1339 {
1340 int v = node[level >> 1];
1340 int v = node[level >> 1];
1341 if (!(level & 1))
1341 if (!(level & 1))
1342 v >>= 4;
1342 v >>= 4;
1343 return v & 0xf;
1343 return v & 0xf;
1344 }
1344 }
1345
1345
1346 /*
1346 /*
1347 * Return values:
1347 * Return values:
1348 *
1348 *
1349 * -4: match is ambiguous (multiple candidates)
1349 * -4: match is ambiguous (multiple candidates)
1350 * -2: not found
1350 * -2: not found
1351 * rest: valid rev
1351 * rest: valid rev
1352 */
1352 */
1353 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1353 static int nt_find(nodetree *self, const char *node, Py_ssize_t nodelen,
1354 int hex)
1354 int hex)
1355 {
1355 {
1356 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1356 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1357 int level, maxlevel, off;
1357 int level, maxlevel, off;
1358
1358
1359 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1359 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1360 return -1;
1360 return -1;
1361
1361
1362 if (hex)
1362 if (hex)
1363 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1363 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1364 else
1364 else
1365 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1365 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1366
1366
1367 for (level = off = 0; level < maxlevel; level++) {
1367 for (level = off = 0; level < maxlevel; level++) {
1368 int k = getnybble(node, level);
1368 int k = getnybble(node, level);
1369 nodetreenode *n = &self->nodes[off];
1369 nodetreenode *n = &self->nodes[off];
1370 int v = n->children[k];
1370 int v = n->children[k];
1371
1371
1372 if (v < 0) {
1372 if (v < 0) {
1373 const char *n;
1373 const char *n;
1374 Py_ssize_t i;
1374 Py_ssize_t i;
1375
1375
1376 v = -(v + 2);
1376 v = -(v + 2);
1377 n = index_node(self->index, v);
1377 n = index_node(self->index, v);
1378 if (n == NULL)
1378 if (n == NULL)
1379 return -2;
1379 return -2;
1380 for (i = level; i < maxlevel; i++)
1380 for (i = level; i < maxlevel; i++)
1381 if (getnybble(node, i) != nt_level(n, i))
1381 if (getnybble(node, i) != nt_level(n, i))
1382 return -2;
1382 return -2;
1383 return v;
1383 return v;
1384 }
1384 }
1385 if (v == 0)
1385 if (v == 0)
1386 return -2;
1386 return -2;
1387 off = v;
1387 off = v;
1388 }
1388 }
1389 /* multiple matches against an ambiguous prefix */
1389 /* multiple matches against an ambiguous prefix */
1390 return -4;
1390 return -4;
1391 }
1391 }
1392
1392
1393 static int nt_new(nodetree *self)
1393 static int nt_new(nodetree *self)
1394 {
1394 {
1395 if (self->length == self->capacity) {
1395 if (self->length == self->capacity) {
1396 unsigned newcapacity;
1396 unsigned newcapacity;
1397 nodetreenode *newnodes;
1397 nodetreenode *newnodes;
1398 newcapacity = self->capacity * 2;
1398 newcapacity = self->capacity * 2;
1399 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1399 if (newcapacity >= INT_MAX / sizeof(nodetreenode)) {
1400 PyErr_SetString(PyExc_MemoryError,
1400 PyErr_SetString(PyExc_MemoryError,
1401 "overflow in nt_new");
1401 "overflow in nt_new");
1402 return -1;
1402 return -1;
1403 }
1403 }
1404 newnodes =
1404 newnodes =
1405 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1405 realloc(self->nodes, newcapacity * sizeof(nodetreenode));
1406 if (newnodes == NULL) {
1406 if (newnodes == NULL) {
1407 PyErr_SetString(PyExc_MemoryError, "out of memory");
1407 PyErr_SetString(PyExc_MemoryError, "out of memory");
1408 return -1;
1408 return -1;
1409 }
1409 }
1410 self->capacity = newcapacity;
1410 self->capacity = newcapacity;
1411 self->nodes = newnodes;
1411 self->nodes = newnodes;
1412 memset(&self->nodes[self->length], 0,
1412 memset(&self->nodes[self->length], 0,
1413 sizeof(nodetreenode) * (self->capacity - self->length));
1413 sizeof(nodetreenode) * (self->capacity - self->length));
1414 }
1414 }
1415 return self->length++;
1415 return self->length++;
1416 }
1416 }
1417
1417
1418 static int nt_insert(nodetree *self, const char *node, int rev)
1418 static int nt_insert(nodetree *self, const char *node, int rev)
1419 {
1419 {
1420 int level = 0;
1420 int level = 0;
1421 int off = 0;
1421 int off = 0;
1422
1422
1423 while (level < 40) {
1423 while (level < 40) {
1424 int k = nt_level(node, level);
1424 int k = nt_level(node, level);
1425 nodetreenode *n;
1425 nodetreenode *n;
1426 int v;
1426 int v;
1427
1427
1428 n = &self->nodes[off];
1428 n = &self->nodes[off];
1429 v = n->children[k];
1429 v = n->children[k];
1430
1430
1431 if (v == 0) {
1431 if (v == 0) {
1432 n->children[k] = -rev - 2;
1432 n->children[k] = -rev - 2;
1433 return 0;
1433 return 0;
1434 }
1434 }
1435 if (v < 0) {
1435 if (v < 0) {
1436 const char *oldnode =
1436 const char *oldnode =
1437 index_node_existing(self->index, -(v + 2));
1437 index_node_existing(self->index, -(v + 2));
1438 int noff;
1438 int noff;
1439
1439
1440 if (oldnode == NULL)
1440 if (oldnode == NULL)
1441 return -1;
1441 return -1;
1442 if (!memcmp(oldnode, node, 20)) {
1442 if (!memcmp(oldnode, node, 20)) {
1443 n->children[k] = -rev - 2;
1443 n->children[k] = -rev - 2;
1444 return 0;
1444 return 0;
1445 }
1445 }
1446 noff = nt_new(self);
1446 noff = nt_new(self);
1447 if (noff == -1)
1447 if (noff == -1)
1448 return -1;
1448 return -1;
1449 /* self->nodes may have been changed by realloc */
1449 /* self->nodes may have been changed by realloc */
1450 self->nodes[off].children[k] = noff;
1450 self->nodes[off].children[k] = noff;
1451 off = noff;
1451 off = noff;
1452 n = &self->nodes[off];
1452 n = &self->nodes[off];
1453 n->children[nt_level(oldnode, ++level)] = v;
1453 n->children[nt_level(oldnode, ++level)] = v;
1454 if (level > self->depth)
1454 if (level > self->depth)
1455 self->depth = level;
1455 self->depth = level;
1456 self->splits += 1;
1456 self->splits += 1;
1457 } else {
1457 } else {
1458 level += 1;
1458 level += 1;
1459 off = v;
1459 off = v;
1460 }
1460 }
1461 }
1461 }
1462
1462
1463 return -1;
1463 return -1;
1464 }
1464 }
1465
1465
1466 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1466 static PyObject *ntobj_insert(nodetreeObject *self, PyObject *args)
1467 {
1467 {
1468 Py_ssize_t rev;
1468 Py_ssize_t rev;
1469 const char *node;
1469 const char *node;
1470 Py_ssize_t length;
1470 Py_ssize_t length;
1471 if (!PyArg_ParseTuple(args, "n", &rev))
1471 if (!PyArg_ParseTuple(args, "n", &rev))
1472 return NULL;
1472 return NULL;
1473 length = index_length(self->nt.index);
1473 length = index_length(self->nt.index);
1474 if (rev < 0 || rev >= length) {
1474 if (rev < 0 || rev >= length) {
1475 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1475 PyErr_SetString(PyExc_ValueError, "revlog index out of range");
1476 return NULL;
1476 return NULL;
1477 }
1477 }
1478 node = index_node_existing(self->nt.index, rev);
1478 node = index_node_existing(self->nt.index, rev);
1479 if (nt_insert(&self->nt, node, (int)rev) == -1)
1479 if (nt_insert(&self->nt, node, (int)rev) == -1)
1480 return NULL;
1480 return NULL;
1481 Py_RETURN_NONE;
1481 Py_RETURN_NONE;
1482 }
1482 }
1483
1483
1484 static int nt_delete_node(nodetree *self, const char *node)
1484 static int nt_delete_node(nodetree *self, const char *node)
1485 {
1485 {
1486 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1486 /* rev==-2 happens to get encoded as 0, which is interpreted as not set
1487 */
1487 */
1488 return nt_insert(self, node, -2);
1488 return nt_insert(self, node, -2);
1489 }
1489 }
1490
1490
1491 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1491 static int nt_init(nodetree *self, indexObject *index, unsigned capacity)
1492 {
1492 {
1493 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1493 /* Initialize before overflow-checking to avoid nt_dealloc() crash. */
1494 self->nodes = NULL;
1494 self->nodes = NULL;
1495
1495
1496 self->index = index;
1496 self->index = index;
1497 /* The input capacity is in terms of revisions, while the field is in
1497 /* The input capacity is in terms of revisions, while the field is in
1498 * terms of nodetree nodes. */
1498 * terms of nodetree nodes. */
1499 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1499 self->capacity = (capacity < 4 ? 4 : capacity / 2);
1500 self->depth = 0;
1500 self->depth = 0;
1501 self->splits = 0;
1501 self->splits = 0;
1502 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1502 if ((size_t)self->capacity > INT_MAX / sizeof(nodetreenode)) {
1503 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1503 PyErr_SetString(PyExc_ValueError, "overflow in init_nt");
1504 return -1;
1504 return -1;
1505 }
1505 }
1506 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1506 self->nodes = calloc(self->capacity, sizeof(nodetreenode));
1507 if (self->nodes == NULL) {
1507 if (self->nodes == NULL) {
1508 PyErr_NoMemory();
1508 PyErr_NoMemory();
1509 return -1;
1509 return -1;
1510 }
1510 }
1511 self->length = 1;
1511 self->length = 1;
1512 return 0;
1512 return 0;
1513 }
1513 }
1514
1514
1515 static int ntobj_init(nodetreeObject *self, PyObject *args)
1515 static int ntobj_init(nodetreeObject *self, PyObject *args)
1516 {
1516 {
1517 PyObject *index;
1517 PyObject *index;
1518 unsigned capacity;
1518 unsigned capacity;
1519 if (!PyArg_ParseTuple(args, "O!I", &indexType, &index, &capacity))
1519 if (!PyArg_ParseTuple(args, "O!I", &HgRevlogIndex_Type, &index,
1520 &capacity))
1520 return -1;
1521 return -1;
1521 Py_INCREF(index);
1522 Py_INCREF(index);
1522 return nt_init(&self->nt, (indexObject *)index, capacity);
1523 return nt_init(&self->nt, (indexObject *)index, capacity);
1523 }
1524 }
1524
1525
1525 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1526 static int nt_partialmatch(nodetree *self, const char *node, Py_ssize_t nodelen)
1526 {
1527 {
1527 return nt_find(self, node, nodelen, 1);
1528 return nt_find(self, node, nodelen, 1);
1528 }
1529 }
1529
1530
1530 /*
1531 /*
1531 * Find the length of the shortest unique prefix of node.
1532 * Find the length of the shortest unique prefix of node.
1532 *
1533 *
1533 * Return values:
1534 * Return values:
1534 *
1535 *
1535 * -3: error (exception set)
1536 * -3: error (exception set)
1536 * -2: not found (no exception set)
1537 * -2: not found (no exception set)
1537 * rest: length of shortest prefix
1538 * rest: length of shortest prefix
1538 */
1539 */
1539 static int nt_shortest(nodetree *self, const char *node)
1540 static int nt_shortest(nodetree *self, const char *node)
1540 {
1541 {
1541 int level, off;
1542 int level, off;
1542
1543
1543 for (level = off = 0; level < 40; level++) {
1544 for (level = off = 0; level < 40; level++) {
1544 int k, v;
1545 int k, v;
1545 nodetreenode *n = &self->nodes[off];
1546 nodetreenode *n = &self->nodes[off];
1546 k = nt_level(node, level);
1547 k = nt_level(node, level);
1547 v = n->children[k];
1548 v = n->children[k];
1548 if (v < 0) {
1549 if (v < 0) {
1549 const char *n;
1550 const char *n;
1550 v = -(v + 2);
1551 v = -(v + 2);
1551 n = index_node_existing(self->index, v);
1552 n = index_node_existing(self->index, v);
1552 if (n == NULL)
1553 if (n == NULL)
1553 return -3;
1554 return -3;
1554 if (memcmp(node, n, 20) != 0)
1555 if (memcmp(node, n, 20) != 0)
1555 /*
1556 /*
1556 * Found a unique prefix, but it wasn't for the
1557 * Found a unique prefix, but it wasn't for the
1557 * requested node (i.e the requested node does
1558 * requested node (i.e the requested node does
1558 * not exist).
1559 * not exist).
1559 */
1560 */
1560 return -2;
1561 return -2;
1561 return level + 1;
1562 return level + 1;
1562 }
1563 }
1563 if (v == 0)
1564 if (v == 0)
1564 return -2;
1565 return -2;
1565 off = v;
1566 off = v;
1566 }
1567 }
1567 /*
1568 /*
1568 * The node was still not unique after 40 hex digits, so this won't
1569 * The node was still not unique after 40 hex digits, so this won't
1569 * happen. Also, if we get here, then there's a programming error in
1570 * happen. Also, if we get here, then there's a programming error in
1570 * this file that made us insert a node longer than 40 hex digits.
1571 * this file that made us insert a node longer than 40 hex digits.
1571 */
1572 */
1572 PyErr_SetString(PyExc_Exception, "broken node tree");
1573 PyErr_SetString(PyExc_Exception, "broken node tree");
1573 return -3;
1574 return -3;
1574 }
1575 }
1575
1576
1576 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1577 static PyObject *ntobj_shortest(nodetreeObject *self, PyObject *args)
1577 {
1578 {
1578 PyObject *val;
1579 PyObject *val;
1579 char *node;
1580 char *node;
1580 int length;
1581 int length;
1581
1582
1582 if (!PyArg_ParseTuple(args, "O", &val))
1583 if (!PyArg_ParseTuple(args, "O", &val))
1583 return NULL;
1584 return NULL;
1584 if (node_check(val, &node) == -1)
1585 if (node_check(val, &node) == -1)
1585 return NULL;
1586 return NULL;
1586
1587
1587 length = nt_shortest(&self->nt, node);
1588 length = nt_shortest(&self->nt, node);
1588 if (length == -3)
1589 if (length == -3)
1589 return NULL;
1590 return NULL;
1590 if (length == -2) {
1591 if (length == -2) {
1591 raise_revlog_error();
1592 raise_revlog_error();
1592 return NULL;
1593 return NULL;
1593 }
1594 }
1594 return PyInt_FromLong(length);
1595 return PyInt_FromLong(length);
1595 }
1596 }
1596
1597
1597 static void nt_dealloc(nodetree *self)
1598 static void nt_dealloc(nodetree *self)
1598 {
1599 {
1599 free(self->nodes);
1600 free(self->nodes);
1600 self->nodes = NULL;
1601 self->nodes = NULL;
1601 }
1602 }
1602
1603
1603 static void ntobj_dealloc(nodetreeObject *self)
1604 static void ntobj_dealloc(nodetreeObject *self)
1604 {
1605 {
1605 Py_XDECREF(self->nt.index);
1606 Py_XDECREF(self->nt.index);
1606 nt_dealloc(&self->nt);
1607 nt_dealloc(&self->nt);
1607 PyObject_Del(self);
1608 PyObject_Del(self);
1608 }
1609 }
1609
1610
1610 static PyMethodDef ntobj_methods[] = {
1611 static PyMethodDef ntobj_methods[] = {
1611 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1612 {"insert", (PyCFunction)ntobj_insert, METH_VARARGS,
1612 "insert an index entry"},
1613 "insert an index entry"},
1613 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1614 {"shortest", (PyCFunction)ntobj_shortest, METH_VARARGS,
1614 "find length of shortest hex nodeid of a binary ID"},
1615 "find length of shortest hex nodeid of a binary ID"},
1615 {NULL} /* Sentinel */
1616 {NULL} /* Sentinel */
1616 };
1617 };
1617
1618
1618 static PyTypeObject nodetreeType = {
1619 static PyTypeObject nodetreeType = {
1619 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1620 PyVarObject_HEAD_INIT(NULL, 0) /* header */
1620 "parsers.nodetree", /* tp_name */
1621 "parsers.nodetree", /* tp_name */
1621 sizeof(nodetreeObject), /* tp_basicsize */
1622 sizeof(nodetreeObject), /* tp_basicsize */
1622 0, /* tp_itemsize */
1623 0, /* tp_itemsize */
1623 (destructor)ntobj_dealloc, /* tp_dealloc */
1624 (destructor)ntobj_dealloc, /* tp_dealloc */
1624 0, /* tp_print */
1625 0, /* tp_print */
1625 0, /* tp_getattr */
1626 0, /* tp_getattr */
1626 0, /* tp_setattr */
1627 0, /* tp_setattr */
1627 0, /* tp_compare */
1628 0, /* tp_compare */
1628 0, /* tp_repr */
1629 0, /* tp_repr */
1629 0, /* tp_as_number */
1630 0, /* tp_as_number */
1630 0, /* tp_as_sequence */
1631 0, /* tp_as_sequence */
1631 0, /* tp_as_mapping */
1632 0, /* tp_as_mapping */
1632 0, /* tp_hash */
1633 0, /* tp_hash */
1633 0, /* tp_call */
1634 0, /* tp_call */
1634 0, /* tp_str */
1635 0, /* tp_str */
1635 0, /* tp_getattro */
1636 0, /* tp_getattro */
1636 0, /* tp_setattro */
1637 0, /* tp_setattro */
1637 0, /* tp_as_buffer */
1638 0, /* tp_as_buffer */
1638 Py_TPFLAGS_DEFAULT, /* tp_flags */
1639 Py_TPFLAGS_DEFAULT, /* tp_flags */
1639 "nodetree", /* tp_doc */
1640 "nodetree", /* tp_doc */
1640 0, /* tp_traverse */
1641 0, /* tp_traverse */
1641 0, /* tp_clear */
1642 0, /* tp_clear */
1642 0, /* tp_richcompare */
1643 0, /* tp_richcompare */
1643 0, /* tp_weaklistoffset */
1644 0, /* tp_weaklistoffset */
1644 0, /* tp_iter */
1645 0, /* tp_iter */
1645 0, /* tp_iternext */
1646 0, /* tp_iternext */
1646 ntobj_methods, /* tp_methods */
1647 ntobj_methods, /* tp_methods */
1647 0, /* tp_members */
1648 0, /* tp_members */
1648 0, /* tp_getset */
1649 0, /* tp_getset */
1649 0, /* tp_base */
1650 0, /* tp_base */
1650 0, /* tp_dict */
1651 0, /* tp_dict */
1651 0, /* tp_descr_get */
1652 0, /* tp_descr_get */
1652 0, /* tp_descr_set */
1653 0, /* tp_descr_set */
1653 0, /* tp_dictoffset */
1654 0, /* tp_dictoffset */
1654 (initproc)ntobj_init, /* tp_init */
1655 (initproc)ntobj_init, /* tp_init */
1655 0, /* tp_alloc */
1656 0, /* tp_alloc */
1656 };
1657 };
1657
1658
1658 static int index_init_nt(indexObject *self)
1659 static int index_init_nt(indexObject *self)
1659 {
1660 {
1660 if (!self->ntinitialized) {
1661 if (!self->ntinitialized) {
1661 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1662 if (nt_init(&self->nt, self, (int)self->raw_length) == -1) {
1662 nt_dealloc(&self->nt);
1663 nt_dealloc(&self->nt);
1663 return -1;
1664 return -1;
1664 }
1665 }
1665 if (nt_insert(&self->nt, nullid, -1) == -1) {
1666 if (nt_insert(&self->nt, nullid, -1) == -1) {
1666 nt_dealloc(&self->nt);
1667 nt_dealloc(&self->nt);
1667 return -1;
1668 return -1;
1668 }
1669 }
1669 self->ntinitialized = 1;
1670 self->ntinitialized = 1;
1670 self->ntrev = (int)index_length(self);
1671 self->ntrev = (int)index_length(self);
1671 self->ntlookups = 1;
1672 self->ntlookups = 1;
1672 self->ntmisses = 0;
1673 self->ntmisses = 0;
1673 }
1674 }
1674 return 0;
1675 return 0;
1675 }
1676 }
1676
1677
1677 /*
1678 /*
1678 * Return values:
1679 * Return values:
1679 *
1680 *
1680 * -3: error (exception set)
1681 * -3: error (exception set)
1681 * -2: not found (no exception set)
1682 * -2: not found (no exception set)
1682 * rest: valid rev
1683 * rest: valid rev
1683 */
1684 */
1684 static int index_find_node(indexObject *self, const char *node,
1685 static int index_find_node(indexObject *self, const char *node,
1685 Py_ssize_t nodelen)
1686 Py_ssize_t nodelen)
1686 {
1687 {
1687 int rev;
1688 int rev;
1688
1689
1689 if (index_init_nt(self) == -1)
1690 if (index_init_nt(self) == -1)
1690 return -3;
1691 return -3;
1691
1692
1692 self->ntlookups++;
1693 self->ntlookups++;
1693 rev = nt_find(&self->nt, node, nodelen, 0);
1694 rev = nt_find(&self->nt, node, nodelen, 0);
1694 if (rev >= -1)
1695 if (rev >= -1)
1695 return rev;
1696 return rev;
1696
1697
1697 /*
1698 /*
1698 * For the first handful of lookups, we scan the entire index,
1699 * For the first handful of lookups, we scan the entire index,
1699 * and cache only the matching nodes. This optimizes for cases
1700 * and cache only the matching nodes. This optimizes for cases
1700 * like "hg tip", where only a few nodes are accessed.
1701 * like "hg tip", where only a few nodes are accessed.
1701 *
1702 *
1702 * After that, we cache every node we visit, using a single
1703 * After that, we cache every node we visit, using a single
1703 * scan amortized over multiple lookups. This gives the best
1704 * scan amortized over multiple lookups. This gives the best
1704 * bulk performance, e.g. for "hg log".
1705 * bulk performance, e.g. for "hg log".
1705 */
1706 */
1706 if (self->ntmisses++ < 4) {
1707 if (self->ntmisses++ < 4) {
1707 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1708 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1708 const char *n = index_node_existing(self, rev);
1709 const char *n = index_node_existing(self, rev);
1709 if (n == NULL)
1710 if (n == NULL)
1710 return -3;
1711 return -3;
1711 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1712 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1712 if (nt_insert(&self->nt, n, rev) == -1)
1713 if (nt_insert(&self->nt, n, rev) == -1)
1713 return -3;
1714 return -3;
1714 break;
1715 break;
1715 }
1716 }
1716 }
1717 }
1717 } else {
1718 } else {
1718 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1719 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1719 const char *n = index_node_existing(self, rev);
1720 const char *n = index_node_existing(self, rev);
1720 if (n == NULL)
1721 if (n == NULL)
1721 return -3;
1722 return -3;
1722 if (nt_insert(&self->nt, n, rev) == -1) {
1723 if (nt_insert(&self->nt, n, rev) == -1) {
1723 self->ntrev = rev + 1;
1724 self->ntrev = rev + 1;
1724 return -3;
1725 return -3;
1725 }
1726 }
1726 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1727 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1727 break;
1728 break;
1728 }
1729 }
1729 }
1730 }
1730 self->ntrev = rev;
1731 self->ntrev = rev;
1731 }
1732 }
1732
1733
1733 if (rev >= 0)
1734 if (rev >= 0)
1734 return rev;
1735 return rev;
1735 return -2;
1736 return -2;
1736 }
1737 }
1737
1738
1738 static PyObject *index_getitem(indexObject *self, PyObject *value)
1739 static PyObject *index_getitem(indexObject *self, PyObject *value)
1739 {
1740 {
1740 char *node;
1741 char *node;
1741 int rev;
1742 int rev;
1742
1743
1743 if (PyInt_Check(value)) {
1744 if (PyInt_Check(value)) {
1744 long idx;
1745 long idx;
1745 if (!pylong_to_long(value, &idx)) {
1746 if (!pylong_to_long(value, &idx)) {
1746 return NULL;
1747 return NULL;
1747 }
1748 }
1748 return index_get(self, idx);
1749 return index_get(self, idx);
1749 }
1750 }
1750
1751
1751 if (node_check(value, &node) == -1)
1752 if (node_check(value, &node) == -1)
1752 return NULL;
1753 return NULL;
1753 rev = index_find_node(self, node, 20);
1754 rev = index_find_node(self, node, 20);
1754 if (rev >= -1)
1755 if (rev >= -1)
1755 return PyInt_FromLong(rev);
1756 return PyInt_FromLong(rev);
1756 if (rev == -2)
1757 if (rev == -2)
1757 raise_revlog_error();
1758 raise_revlog_error();
1758 return NULL;
1759 return NULL;
1759 }
1760 }
1760
1761
1761 /*
1762 /*
1762 * Fully populate the radix tree.
1763 * Fully populate the radix tree.
1763 */
1764 */
1764 static int index_populate_nt(indexObject *self)
1765 static int index_populate_nt(indexObject *self)
1765 {
1766 {
1766 int rev;
1767 int rev;
1767 if (self->ntrev > 0) {
1768 if (self->ntrev > 0) {
1768 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1769 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1769 const char *n = index_node_existing(self, rev);
1770 const char *n = index_node_existing(self, rev);
1770 if (n == NULL)
1771 if (n == NULL)
1771 return -1;
1772 return -1;
1772 if (nt_insert(&self->nt, n, rev) == -1)
1773 if (nt_insert(&self->nt, n, rev) == -1)
1773 return -1;
1774 return -1;
1774 }
1775 }
1775 self->ntrev = -1;
1776 self->ntrev = -1;
1776 }
1777 }
1777 return 0;
1778 return 0;
1778 }
1779 }
1779
1780
1780 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1781 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1781 {
1782 {
1782 const char *fullnode;
1783 const char *fullnode;
1783 int nodelen;
1784 int nodelen;
1784 char *node;
1785 char *node;
1785 int rev, i;
1786 int rev, i;
1786
1787
1787 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1788 if (!PyArg_ParseTuple(args, PY23("s#", "y#"), &node, &nodelen))
1788 return NULL;
1789 return NULL;
1789
1790
1790 if (nodelen < 1) {
1791 if (nodelen < 1) {
1791 PyErr_SetString(PyExc_ValueError, "key too short");
1792 PyErr_SetString(PyExc_ValueError, "key too short");
1792 return NULL;
1793 return NULL;
1793 }
1794 }
1794
1795
1795 if (nodelen > 40) {
1796 if (nodelen > 40) {
1796 PyErr_SetString(PyExc_ValueError, "key too long");
1797 PyErr_SetString(PyExc_ValueError, "key too long");
1797 return NULL;
1798 return NULL;
1798 }
1799 }
1799
1800
1800 for (i = 0; i < nodelen; i++)
1801 for (i = 0; i < nodelen; i++)
1801 hexdigit(node, i);
1802 hexdigit(node, i);
1802 if (PyErr_Occurred()) {
1803 if (PyErr_Occurred()) {
1803 /* input contains non-hex characters */
1804 /* input contains non-hex characters */
1804 PyErr_Clear();
1805 PyErr_Clear();
1805 Py_RETURN_NONE;
1806 Py_RETURN_NONE;
1806 }
1807 }
1807
1808
1808 if (index_init_nt(self) == -1)
1809 if (index_init_nt(self) == -1)
1809 return NULL;
1810 return NULL;
1810 if (index_populate_nt(self) == -1)
1811 if (index_populate_nt(self) == -1)
1811 return NULL;
1812 return NULL;
1812 rev = nt_partialmatch(&self->nt, node, nodelen);
1813 rev = nt_partialmatch(&self->nt, node, nodelen);
1813
1814
1814 switch (rev) {
1815 switch (rev) {
1815 case -4:
1816 case -4:
1816 raise_revlog_error();
1817 raise_revlog_error();
1817 return NULL;
1818 return NULL;
1818 case -2:
1819 case -2:
1819 Py_RETURN_NONE;
1820 Py_RETURN_NONE;
1820 case -1:
1821 case -1:
1821 return PyBytes_FromStringAndSize(nullid, 20);
1822 return PyBytes_FromStringAndSize(nullid, 20);
1822 }
1823 }
1823
1824
1824 fullnode = index_node_existing(self, rev);
1825 fullnode = index_node_existing(self, rev);
1825 if (fullnode == NULL) {
1826 if (fullnode == NULL) {
1826 return NULL;
1827 return NULL;
1827 }
1828 }
1828 return PyBytes_FromStringAndSize(fullnode, 20);
1829 return PyBytes_FromStringAndSize(fullnode, 20);
1829 }
1830 }
1830
1831
1831 static PyObject *index_shortest(indexObject *self, PyObject *args)
1832 static PyObject *index_shortest(indexObject *self, PyObject *args)
1832 {
1833 {
1833 PyObject *val;
1834 PyObject *val;
1834 char *node;
1835 char *node;
1835 int length;
1836 int length;
1836
1837
1837 if (!PyArg_ParseTuple(args, "O", &val))
1838 if (!PyArg_ParseTuple(args, "O", &val))
1838 return NULL;
1839 return NULL;
1839 if (node_check(val, &node) == -1)
1840 if (node_check(val, &node) == -1)
1840 return NULL;
1841 return NULL;
1841
1842
1842 self->ntlookups++;
1843 self->ntlookups++;
1843 if (index_init_nt(self) == -1)
1844 if (index_init_nt(self) == -1)
1844 return NULL;
1845 return NULL;
1845 if (index_populate_nt(self) == -1)
1846 if (index_populate_nt(self) == -1)
1846 return NULL;
1847 return NULL;
1847 length = nt_shortest(&self->nt, node);
1848 length = nt_shortest(&self->nt, node);
1848 if (length == -3)
1849 if (length == -3)
1849 return NULL;
1850 return NULL;
1850 if (length == -2) {
1851 if (length == -2) {
1851 raise_revlog_error();
1852 raise_revlog_error();
1852 return NULL;
1853 return NULL;
1853 }
1854 }
1854 return PyInt_FromLong(length);
1855 return PyInt_FromLong(length);
1855 }
1856 }
1856
1857
1857 static PyObject *index_m_get(indexObject *self, PyObject *args)
1858 static PyObject *index_m_get(indexObject *self, PyObject *args)
1858 {
1859 {
1859 PyObject *val;
1860 PyObject *val;
1860 char *node;
1861 char *node;
1861 int rev;
1862 int rev;
1862
1863
1863 if (!PyArg_ParseTuple(args, "O", &val))
1864 if (!PyArg_ParseTuple(args, "O", &val))
1864 return NULL;
1865 return NULL;
1865 if (node_check(val, &node) == -1)
1866 if (node_check(val, &node) == -1)
1866 return NULL;
1867 return NULL;
1867 rev = index_find_node(self, node, 20);
1868 rev = index_find_node(self, node, 20);
1868 if (rev == -3)
1869 if (rev == -3)
1869 return NULL;
1870 return NULL;
1870 if (rev == -2)
1871 if (rev == -2)
1871 Py_RETURN_NONE;
1872 Py_RETURN_NONE;
1872 return PyInt_FromLong(rev);
1873 return PyInt_FromLong(rev);
1873 }
1874 }
1874
1875
1875 static int index_contains(indexObject *self, PyObject *value)
1876 static int index_contains(indexObject *self, PyObject *value)
1876 {
1877 {
1877 char *node;
1878 char *node;
1878
1879
1879 if (PyInt_Check(value)) {
1880 if (PyInt_Check(value)) {
1880 long rev;
1881 long rev;
1881 if (!pylong_to_long(value, &rev)) {
1882 if (!pylong_to_long(value, &rev)) {
1882 return -1;
1883 return -1;
1883 }
1884 }
1884 return rev >= -1 && rev < index_length(self);
1885 return rev >= -1 && rev < index_length(self);
1885 }
1886 }
1886
1887
1887 if (node_check(value, &node) == -1)
1888 if (node_check(value, &node) == -1)
1888 return -1;
1889 return -1;
1889
1890
1890 switch (index_find_node(self, node, 20)) {
1891 switch (index_find_node(self, node, 20)) {
1891 case -3:
1892 case -3:
1892 return -1;
1893 return -1;
1893 case -2:
1894 case -2:
1894 return 0;
1895 return 0;
1895 default:
1896 default:
1896 return 1;
1897 return 1;
1897 }
1898 }
1898 }
1899 }
1899
1900
1900 typedef uint64_t bitmask;
1901 typedef uint64_t bitmask;
1901
1902
1902 /*
1903 /*
1903 * Given a disjoint set of revs, return all candidates for the
1904 * Given a disjoint set of revs, return all candidates for the
1904 * greatest common ancestor. In revset notation, this is the set
1905 * greatest common ancestor. In revset notation, this is the set
1905 * "heads(::a and ::b and ...)"
1906 * "heads(::a and ::b and ...)"
1906 */
1907 */
1907 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1908 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1908 int revcount)
1909 int revcount)
1909 {
1910 {
1910 const bitmask allseen = (1ull << revcount) - 1;
1911 const bitmask allseen = (1ull << revcount) - 1;
1911 const bitmask poison = 1ull << revcount;
1912 const bitmask poison = 1ull << revcount;
1912 PyObject *gca = PyList_New(0);
1913 PyObject *gca = PyList_New(0);
1913 int i, v, interesting;
1914 int i, v, interesting;
1914 int maxrev = -1;
1915 int maxrev = -1;
1915 bitmask sp;
1916 bitmask sp;
1916 bitmask *seen;
1917 bitmask *seen;
1917
1918
1918 if (gca == NULL)
1919 if (gca == NULL)
1919 return PyErr_NoMemory();
1920 return PyErr_NoMemory();
1920
1921
1921 for (i = 0; i < revcount; i++) {
1922 for (i = 0; i < revcount; i++) {
1922 if (revs[i] > maxrev)
1923 if (revs[i] > maxrev)
1923 maxrev = revs[i];
1924 maxrev = revs[i];
1924 }
1925 }
1925
1926
1926 seen = calloc(sizeof(*seen), maxrev + 1);
1927 seen = calloc(sizeof(*seen), maxrev + 1);
1927 if (seen == NULL) {
1928 if (seen == NULL) {
1928 Py_DECREF(gca);
1929 Py_DECREF(gca);
1929 return PyErr_NoMemory();
1930 return PyErr_NoMemory();
1930 }
1931 }
1931
1932
1932 for (i = 0; i < revcount; i++)
1933 for (i = 0; i < revcount; i++)
1933 seen[revs[i]] = 1ull << i;
1934 seen[revs[i]] = 1ull << i;
1934
1935
1935 interesting = revcount;
1936 interesting = revcount;
1936
1937
1937 for (v = maxrev; v >= 0 && interesting; v--) {
1938 for (v = maxrev; v >= 0 && interesting; v--) {
1938 bitmask sv = seen[v];
1939 bitmask sv = seen[v];
1939 int parents[2];
1940 int parents[2];
1940
1941
1941 if (!sv)
1942 if (!sv)
1942 continue;
1943 continue;
1943
1944
1944 if (sv < poison) {
1945 if (sv < poison) {
1945 interesting -= 1;
1946 interesting -= 1;
1946 if (sv == allseen) {
1947 if (sv == allseen) {
1947 PyObject *obj = PyInt_FromLong(v);
1948 PyObject *obj = PyInt_FromLong(v);
1948 if (obj == NULL)
1949 if (obj == NULL)
1949 goto bail;
1950 goto bail;
1950 if (PyList_Append(gca, obj) == -1) {
1951 if (PyList_Append(gca, obj) == -1) {
1951 Py_DECREF(obj);
1952 Py_DECREF(obj);
1952 goto bail;
1953 goto bail;
1953 }
1954 }
1954 sv |= poison;
1955 sv |= poison;
1955 for (i = 0; i < revcount; i++) {
1956 for (i = 0; i < revcount; i++) {
1956 if (revs[i] == v)
1957 if (revs[i] == v)
1957 goto done;
1958 goto done;
1958 }
1959 }
1959 }
1960 }
1960 }
1961 }
1961 if (index_get_parents(self, v, parents, maxrev) < 0)
1962 if (index_get_parents(self, v, parents, maxrev) < 0)
1962 goto bail;
1963 goto bail;
1963
1964
1964 for (i = 0; i < 2; i++) {
1965 for (i = 0; i < 2; i++) {
1965 int p = parents[i];
1966 int p = parents[i];
1966 if (p == -1)
1967 if (p == -1)
1967 continue;
1968 continue;
1968 sp = seen[p];
1969 sp = seen[p];
1969 if (sv < poison) {
1970 if (sv < poison) {
1970 if (sp == 0) {
1971 if (sp == 0) {
1971 seen[p] = sv;
1972 seen[p] = sv;
1972 interesting++;
1973 interesting++;
1973 } else if (sp != sv)
1974 } else if (sp != sv)
1974 seen[p] |= sv;
1975 seen[p] |= sv;
1975 } else {
1976 } else {
1976 if (sp && sp < poison)
1977 if (sp && sp < poison)
1977 interesting--;
1978 interesting--;
1978 seen[p] = sv;
1979 seen[p] = sv;
1979 }
1980 }
1980 }
1981 }
1981 }
1982 }
1982
1983
1983 done:
1984 done:
1984 free(seen);
1985 free(seen);
1985 return gca;
1986 return gca;
1986 bail:
1987 bail:
1987 free(seen);
1988 free(seen);
1988 Py_XDECREF(gca);
1989 Py_XDECREF(gca);
1989 return NULL;
1990 return NULL;
1990 }
1991 }
1991
1992
1992 /*
1993 /*
1993 * Given a disjoint set of revs, return the subset with the longest
1994 * Given a disjoint set of revs, return the subset with the longest
1994 * path to the root.
1995 * path to the root.
1995 */
1996 */
1996 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1997 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1997 {
1998 {
1998 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1999 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1999 static const Py_ssize_t capacity = 24;
2000 static const Py_ssize_t capacity = 24;
2000 int *depth, *interesting = NULL;
2001 int *depth, *interesting = NULL;
2001 int i, j, v, ninteresting;
2002 int i, j, v, ninteresting;
2002 PyObject *dict = NULL, *keys = NULL;
2003 PyObject *dict = NULL, *keys = NULL;
2003 long *seen = NULL;
2004 long *seen = NULL;
2004 int maxrev = -1;
2005 int maxrev = -1;
2005 long final;
2006 long final;
2006
2007
2007 if (revcount > capacity) {
2008 if (revcount > capacity) {
2008 PyErr_Format(PyExc_OverflowError,
2009 PyErr_Format(PyExc_OverflowError,
2009 "bitset size (%ld) > capacity (%ld)",
2010 "bitset size (%ld) > capacity (%ld)",
2010 (long)revcount, (long)capacity);
2011 (long)revcount, (long)capacity);
2011 return NULL;
2012 return NULL;
2012 }
2013 }
2013
2014
2014 for (i = 0; i < revcount; i++) {
2015 for (i = 0; i < revcount; i++) {
2015 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2016 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2016 if (n > maxrev)
2017 if (n > maxrev)
2017 maxrev = n;
2018 maxrev = n;
2018 }
2019 }
2019
2020
2020 depth = calloc(sizeof(*depth), maxrev + 1);
2021 depth = calloc(sizeof(*depth), maxrev + 1);
2021 if (depth == NULL)
2022 if (depth == NULL)
2022 return PyErr_NoMemory();
2023 return PyErr_NoMemory();
2023
2024
2024 seen = calloc(sizeof(*seen), maxrev + 1);
2025 seen = calloc(sizeof(*seen), maxrev + 1);
2025 if (seen == NULL) {
2026 if (seen == NULL) {
2026 PyErr_NoMemory();
2027 PyErr_NoMemory();
2027 goto bail;
2028 goto bail;
2028 }
2029 }
2029
2030
2030 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2031 interesting = calloc(sizeof(*interesting), ((size_t)1) << revcount);
2031 if (interesting == NULL) {
2032 if (interesting == NULL) {
2032 PyErr_NoMemory();
2033 PyErr_NoMemory();
2033 goto bail;
2034 goto bail;
2034 }
2035 }
2035
2036
2036 if (PyList_Sort(revs) == -1)
2037 if (PyList_Sort(revs) == -1)
2037 goto bail;
2038 goto bail;
2038
2039
2039 for (i = 0; i < revcount; i++) {
2040 for (i = 0; i < revcount; i++) {
2040 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2041 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
2041 long b = 1l << i;
2042 long b = 1l << i;
2042 depth[n] = 1;
2043 depth[n] = 1;
2043 seen[n] = b;
2044 seen[n] = b;
2044 interesting[b] = 1;
2045 interesting[b] = 1;
2045 }
2046 }
2046
2047
2047 /* invariant: ninteresting is the number of non-zero entries in
2048 /* invariant: ninteresting is the number of non-zero entries in
2048 * interesting. */
2049 * interesting. */
2049 ninteresting = (int)revcount;
2050 ninteresting = (int)revcount;
2050
2051
2051 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2052 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
2052 int dv = depth[v];
2053 int dv = depth[v];
2053 int parents[2];
2054 int parents[2];
2054 long sv;
2055 long sv;
2055
2056
2056 if (dv == 0)
2057 if (dv == 0)
2057 continue;
2058 continue;
2058
2059
2059 sv = seen[v];
2060 sv = seen[v];
2060 if (index_get_parents(self, v, parents, maxrev) < 0)
2061 if (index_get_parents(self, v, parents, maxrev) < 0)
2061 goto bail;
2062 goto bail;
2062
2063
2063 for (i = 0; i < 2; i++) {
2064 for (i = 0; i < 2; i++) {
2064 int p = parents[i];
2065 int p = parents[i];
2065 long sp;
2066 long sp;
2066 int dp;
2067 int dp;
2067
2068
2068 if (p == -1)
2069 if (p == -1)
2069 continue;
2070 continue;
2070
2071
2071 dp = depth[p];
2072 dp = depth[p];
2072 sp = seen[p];
2073 sp = seen[p];
2073 if (dp <= dv) {
2074 if (dp <= dv) {
2074 depth[p] = dv + 1;
2075 depth[p] = dv + 1;
2075 if (sp != sv) {
2076 if (sp != sv) {
2076 interesting[sv] += 1;
2077 interesting[sv] += 1;
2077 seen[p] = sv;
2078 seen[p] = sv;
2078 if (sp) {
2079 if (sp) {
2079 interesting[sp] -= 1;
2080 interesting[sp] -= 1;
2080 if (interesting[sp] == 0)
2081 if (interesting[sp] == 0)
2081 ninteresting -= 1;
2082 ninteresting -= 1;
2082 }
2083 }
2083 }
2084 }
2084 } else if (dv == dp - 1) {
2085 } else if (dv == dp - 1) {
2085 long nsp = sp | sv;
2086 long nsp = sp | sv;
2086 if (nsp == sp)
2087 if (nsp == sp)
2087 continue;
2088 continue;
2088 seen[p] = nsp;
2089 seen[p] = nsp;
2089 interesting[sp] -= 1;
2090 interesting[sp] -= 1;
2090 if (interesting[sp] == 0)
2091 if (interesting[sp] == 0)
2091 ninteresting -= 1;
2092 ninteresting -= 1;
2092 if (interesting[nsp] == 0)
2093 if (interesting[nsp] == 0)
2093 ninteresting += 1;
2094 ninteresting += 1;
2094 interesting[nsp] += 1;
2095 interesting[nsp] += 1;
2095 }
2096 }
2096 }
2097 }
2097 interesting[sv] -= 1;
2098 interesting[sv] -= 1;
2098 if (interesting[sv] == 0)
2099 if (interesting[sv] == 0)
2099 ninteresting -= 1;
2100 ninteresting -= 1;
2100 }
2101 }
2101
2102
2102 final = 0;
2103 final = 0;
2103 j = ninteresting;
2104 j = ninteresting;
2104 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2105 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
2105 if (interesting[i] == 0)
2106 if (interesting[i] == 0)
2106 continue;
2107 continue;
2107 final |= i;
2108 final |= i;
2108 j -= 1;
2109 j -= 1;
2109 }
2110 }
2110 if (final == 0) {
2111 if (final == 0) {
2111 keys = PyList_New(0);
2112 keys = PyList_New(0);
2112 goto bail;
2113 goto bail;
2113 }
2114 }
2114
2115
2115 dict = PyDict_New();
2116 dict = PyDict_New();
2116 if (dict == NULL)
2117 if (dict == NULL)
2117 goto bail;
2118 goto bail;
2118
2119
2119 for (i = 0; i < revcount; i++) {
2120 for (i = 0; i < revcount; i++) {
2120 PyObject *key;
2121 PyObject *key;
2121
2122
2122 if ((final & (1 << i)) == 0)
2123 if ((final & (1 << i)) == 0)
2123 continue;
2124 continue;
2124
2125
2125 key = PyList_GET_ITEM(revs, i);
2126 key = PyList_GET_ITEM(revs, i);
2126 Py_INCREF(key);
2127 Py_INCREF(key);
2127 Py_INCREF(Py_None);
2128 Py_INCREF(Py_None);
2128 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2129 if (PyDict_SetItem(dict, key, Py_None) == -1) {
2129 Py_DECREF(key);
2130 Py_DECREF(key);
2130 Py_DECREF(Py_None);
2131 Py_DECREF(Py_None);
2131 goto bail;
2132 goto bail;
2132 }
2133 }
2133 }
2134 }
2134
2135
2135 keys = PyDict_Keys(dict);
2136 keys = PyDict_Keys(dict);
2136
2137
2137 bail:
2138 bail:
2138 free(depth);
2139 free(depth);
2139 free(seen);
2140 free(seen);
2140 free(interesting);
2141 free(interesting);
2141 Py_XDECREF(dict);
2142 Py_XDECREF(dict);
2142
2143
2143 return keys;
2144 return keys;
2144 }
2145 }
2145
2146
2146 /*
2147 /*
2147 * Given a (possibly overlapping) set of revs, return all the
2148 * Given a (possibly overlapping) set of revs, return all the
2148 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2149 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
2149 */
2150 */
2150 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2151 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
2151 {
2152 {
2152 PyObject *ret = NULL;
2153 PyObject *ret = NULL;
2153 Py_ssize_t argcount, i, len;
2154 Py_ssize_t argcount, i, len;
2154 bitmask repeat = 0;
2155 bitmask repeat = 0;
2155 int revcount = 0;
2156 int revcount = 0;
2156 int *revs;
2157 int *revs;
2157
2158
2158 argcount = PySequence_Length(args);
2159 argcount = PySequence_Length(args);
2159 revs = PyMem_Malloc(argcount * sizeof(*revs));
2160 revs = PyMem_Malloc(argcount * sizeof(*revs));
2160 if (argcount > 0 && revs == NULL)
2161 if (argcount > 0 && revs == NULL)
2161 return PyErr_NoMemory();
2162 return PyErr_NoMemory();
2162 len = index_length(self);
2163 len = index_length(self);
2163
2164
2164 for (i = 0; i < argcount; i++) {
2165 for (i = 0; i < argcount; i++) {
2165 static const int capacity = 24;
2166 static const int capacity = 24;
2166 PyObject *obj = PySequence_GetItem(args, i);
2167 PyObject *obj = PySequence_GetItem(args, i);
2167 bitmask x;
2168 bitmask x;
2168 long val;
2169 long val;
2169
2170
2170 if (!PyInt_Check(obj)) {
2171 if (!PyInt_Check(obj)) {
2171 PyErr_SetString(PyExc_TypeError,
2172 PyErr_SetString(PyExc_TypeError,
2172 "arguments must all be ints");
2173 "arguments must all be ints");
2173 Py_DECREF(obj);
2174 Py_DECREF(obj);
2174 goto bail;
2175 goto bail;
2175 }
2176 }
2176 val = PyInt_AsLong(obj);
2177 val = PyInt_AsLong(obj);
2177 Py_DECREF(obj);
2178 Py_DECREF(obj);
2178 if (val == -1) {
2179 if (val == -1) {
2179 ret = PyList_New(0);
2180 ret = PyList_New(0);
2180 goto done;
2181 goto done;
2181 }
2182 }
2182 if (val < 0 || val >= len) {
2183 if (val < 0 || val >= len) {
2183 PyErr_SetString(PyExc_IndexError, "index out of range");
2184 PyErr_SetString(PyExc_IndexError, "index out of range");
2184 goto bail;
2185 goto bail;
2185 }
2186 }
2186 /* this cheesy bloom filter lets us avoid some more
2187 /* this cheesy bloom filter lets us avoid some more
2187 * expensive duplicate checks in the common set-is-disjoint
2188 * expensive duplicate checks in the common set-is-disjoint
2188 * case */
2189 * case */
2189 x = 1ull << (val & 0x3f);
2190 x = 1ull << (val & 0x3f);
2190 if (repeat & x) {
2191 if (repeat & x) {
2191 int k;
2192 int k;
2192 for (k = 0; k < revcount; k++) {
2193 for (k = 0; k < revcount; k++) {
2193 if (val == revs[k])
2194 if (val == revs[k])
2194 goto duplicate;
2195 goto duplicate;
2195 }
2196 }
2196 } else
2197 } else
2197 repeat |= x;
2198 repeat |= x;
2198 if (revcount >= capacity) {
2199 if (revcount >= capacity) {
2199 PyErr_Format(PyExc_OverflowError,
2200 PyErr_Format(PyExc_OverflowError,
2200 "bitset size (%d) > capacity (%d)",
2201 "bitset size (%d) > capacity (%d)",
2201 revcount, capacity);
2202 revcount, capacity);
2202 goto bail;
2203 goto bail;
2203 }
2204 }
2204 revs[revcount++] = (int)val;
2205 revs[revcount++] = (int)val;
2205 duplicate:;
2206 duplicate:;
2206 }
2207 }
2207
2208
2208 if (revcount == 0) {
2209 if (revcount == 0) {
2209 ret = PyList_New(0);
2210 ret = PyList_New(0);
2210 goto done;
2211 goto done;
2211 }
2212 }
2212 if (revcount == 1) {
2213 if (revcount == 1) {
2213 PyObject *obj;
2214 PyObject *obj;
2214 ret = PyList_New(1);
2215 ret = PyList_New(1);
2215 if (ret == NULL)
2216 if (ret == NULL)
2216 goto bail;
2217 goto bail;
2217 obj = PyInt_FromLong(revs[0]);
2218 obj = PyInt_FromLong(revs[0]);
2218 if (obj == NULL)
2219 if (obj == NULL)
2219 goto bail;
2220 goto bail;
2220 PyList_SET_ITEM(ret, 0, obj);
2221 PyList_SET_ITEM(ret, 0, obj);
2221 goto done;
2222 goto done;
2222 }
2223 }
2223
2224
2224 ret = find_gca_candidates(self, revs, revcount);
2225 ret = find_gca_candidates(self, revs, revcount);
2225 if (ret == NULL)
2226 if (ret == NULL)
2226 goto bail;
2227 goto bail;
2227
2228
2228 done:
2229 done:
2229 PyMem_Free(revs);
2230 PyMem_Free(revs);
2230 return ret;
2231 return ret;
2231
2232
2232 bail:
2233 bail:
2233 PyMem_Free(revs);
2234 PyMem_Free(revs);
2234 Py_XDECREF(ret);
2235 Py_XDECREF(ret);
2235 return NULL;
2236 return NULL;
2236 }
2237 }
2237
2238
2238 /*
2239 /*
2239 * Given a (possibly overlapping) set of revs, return the greatest
2240 * Given a (possibly overlapping) set of revs, return the greatest
2240 * common ancestors: those with the longest path to the root.
2241 * common ancestors: those with the longest path to the root.
2241 */
2242 */
2242 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2243 static PyObject *index_ancestors(indexObject *self, PyObject *args)
2243 {
2244 {
2244 PyObject *ret;
2245 PyObject *ret;
2245 PyObject *gca = index_commonancestorsheads(self, args);
2246 PyObject *gca = index_commonancestorsheads(self, args);
2246 if (gca == NULL)
2247 if (gca == NULL)
2247 return NULL;
2248 return NULL;
2248
2249
2249 if (PyList_GET_SIZE(gca) <= 1) {
2250 if (PyList_GET_SIZE(gca) <= 1) {
2250 return gca;
2251 return gca;
2251 }
2252 }
2252
2253
2253 ret = find_deepest(self, gca);
2254 ret = find_deepest(self, gca);
2254 Py_DECREF(gca);
2255 Py_DECREF(gca);
2255 return ret;
2256 return ret;
2256 }
2257 }
2257
2258
2258 /*
2259 /*
2259 * Invalidate any trie entries introduced by added revs.
2260 * Invalidate any trie entries introduced by added revs.
2260 */
2261 */
2261 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2262 static void index_invalidate_added(indexObject *self, Py_ssize_t start)
2262 {
2263 {
2263 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2264 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
2264
2265
2265 for (i = start; i < len; i++) {
2266 for (i = start; i < len; i++) {
2266 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2267 PyObject *tuple = PyList_GET_ITEM(self->added, i);
2267 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2268 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
2268
2269
2269 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2270 nt_delete_node(&self->nt, PyBytes_AS_STRING(node));
2270 }
2271 }
2271
2272
2272 if (start == 0)
2273 if (start == 0)
2273 Py_CLEAR(self->added);
2274 Py_CLEAR(self->added);
2274 }
2275 }
2275
2276
2276 /*
2277 /*
2277 * Delete a numeric range of revs, which must be at the end of the
2278 * Delete a numeric range of revs, which must be at the end of the
2278 * range, but exclude the sentinel nullid entry.
2279 * range, but exclude the sentinel nullid entry.
2279 */
2280 */
2280 static int index_slice_del(indexObject *self, PyObject *item)
2281 static int index_slice_del(indexObject *self, PyObject *item)
2281 {
2282 {
2282 Py_ssize_t start, stop, step, slicelength;
2283 Py_ssize_t start, stop, step, slicelength;
2283 Py_ssize_t length = index_length(self) + 1;
2284 Py_ssize_t length = index_length(self) + 1;
2284 int ret = 0;
2285 int ret = 0;
2285
2286
2286 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2287 /* Argument changed from PySliceObject* to PyObject* in Python 3. */
2287 #ifdef IS_PY3K
2288 #ifdef IS_PY3K
2288 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2289 if (PySlice_GetIndicesEx(item, length, &start, &stop, &step,
2289 &slicelength) < 0)
2290 &slicelength) < 0)
2290 #else
2291 #else
2291 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2292 if (PySlice_GetIndicesEx((PySliceObject *)item, length, &start, &stop,
2292 &step, &slicelength) < 0)
2293 &step, &slicelength) < 0)
2293 #endif
2294 #endif
2294 return -1;
2295 return -1;
2295
2296
2296 if (slicelength <= 0)
2297 if (slicelength <= 0)
2297 return 0;
2298 return 0;
2298
2299
2299 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2300 if ((step < 0 && start < stop) || (step > 0 && start > stop))
2300 stop = start;
2301 stop = start;
2301
2302
2302 if (step < 0) {
2303 if (step < 0) {
2303 stop = start + 1;
2304 stop = start + 1;
2304 start = stop + step * (slicelength - 1) - 1;
2305 start = stop + step * (slicelength - 1) - 1;
2305 step = -step;
2306 step = -step;
2306 }
2307 }
2307
2308
2308 if (step != 1) {
2309 if (step != 1) {
2309 PyErr_SetString(PyExc_ValueError,
2310 PyErr_SetString(PyExc_ValueError,
2310 "revlog index delete requires step size of 1");
2311 "revlog index delete requires step size of 1");
2311 return -1;
2312 return -1;
2312 }
2313 }
2313
2314
2314 if (stop != length - 1) {
2315 if (stop != length - 1) {
2315 PyErr_SetString(PyExc_IndexError,
2316 PyErr_SetString(PyExc_IndexError,
2316 "revlog index deletion indices are invalid");
2317 "revlog index deletion indices are invalid");
2317 return -1;
2318 return -1;
2318 }
2319 }
2319
2320
2320 if (start < self->length) {
2321 if (start < self->length) {
2321 if (self->ntinitialized) {
2322 if (self->ntinitialized) {
2322 Py_ssize_t i;
2323 Py_ssize_t i;
2323
2324
2324 for (i = start + 1; i < self->length; i++) {
2325 for (i = start + 1; i < self->length; i++) {
2325 const char *node = index_node_existing(self, i);
2326 const char *node = index_node_existing(self, i);
2326 if (node == NULL)
2327 if (node == NULL)
2327 return -1;
2328 return -1;
2328
2329
2329 nt_delete_node(&self->nt, node);
2330 nt_delete_node(&self->nt, node);
2330 }
2331 }
2331 if (self->added)
2332 if (self->added)
2332 index_invalidate_added(self, 0);
2333 index_invalidate_added(self, 0);
2333 if (self->ntrev > start)
2334 if (self->ntrev > start)
2334 self->ntrev = (int)start;
2335 self->ntrev = (int)start;
2335 }
2336 }
2336 self->length = start;
2337 self->length = start;
2337 if (start < self->raw_length) {
2338 if (start < self->raw_length) {
2338 if (self->cache) {
2339 if (self->cache) {
2339 Py_ssize_t i;
2340 Py_ssize_t i;
2340 for (i = start; i < self->raw_length; i++)
2341 for (i = start; i < self->raw_length; i++)
2341 Py_CLEAR(self->cache[i]);
2342 Py_CLEAR(self->cache[i]);
2342 }
2343 }
2343 self->raw_length = start;
2344 self->raw_length = start;
2344 }
2345 }
2345 goto done;
2346 goto done;
2346 }
2347 }
2347
2348
2348 if (self->ntinitialized) {
2349 if (self->ntinitialized) {
2349 index_invalidate_added(self, start - self->length);
2350 index_invalidate_added(self, start - self->length);
2350 if (self->ntrev > start)
2351 if (self->ntrev > start)
2351 self->ntrev = (int)start;
2352 self->ntrev = (int)start;
2352 }
2353 }
2353 if (self->added)
2354 if (self->added)
2354 ret = PyList_SetSlice(self->added, start - self->length,
2355 ret = PyList_SetSlice(self->added, start - self->length,
2355 PyList_GET_SIZE(self->added), NULL);
2356 PyList_GET_SIZE(self->added), NULL);
2356 done:
2357 done:
2357 Py_CLEAR(self->headrevs);
2358 Py_CLEAR(self->headrevs);
2358 return ret;
2359 return ret;
2359 }
2360 }
2360
2361
2361 /*
2362 /*
2362 * Supported ops:
2363 * Supported ops:
2363 *
2364 *
2364 * slice deletion
2365 * slice deletion
2365 * string assignment (extend node->rev mapping)
2366 * string assignment (extend node->rev mapping)
2366 * string deletion (shrink node->rev mapping)
2367 * string deletion (shrink node->rev mapping)
2367 */
2368 */
2368 static int index_assign_subscript(indexObject *self, PyObject *item,
2369 static int index_assign_subscript(indexObject *self, PyObject *item,
2369 PyObject *value)
2370 PyObject *value)
2370 {
2371 {
2371 char *node;
2372 char *node;
2372 long rev;
2373 long rev;
2373
2374
2374 if (PySlice_Check(item) && value == NULL)
2375 if (PySlice_Check(item) && value == NULL)
2375 return index_slice_del(self, item);
2376 return index_slice_del(self, item);
2376
2377
2377 if (node_check(item, &node) == -1)
2378 if (node_check(item, &node) == -1)
2378 return -1;
2379 return -1;
2379
2380
2380 if (value == NULL)
2381 if (value == NULL)
2381 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2382 return self->ntinitialized ? nt_delete_node(&self->nt, node)
2382 : 0;
2383 : 0;
2383 rev = PyInt_AsLong(value);
2384 rev = PyInt_AsLong(value);
2384 if (rev > INT_MAX || rev < 0) {
2385 if (rev > INT_MAX || rev < 0) {
2385 if (!PyErr_Occurred())
2386 if (!PyErr_Occurred())
2386 PyErr_SetString(PyExc_ValueError, "rev out of range");
2387 PyErr_SetString(PyExc_ValueError, "rev out of range");
2387 return -1;
2388 return -1;
2388 }
2389 }
2389
2390
2390 if (index_init_nt(self) == -1)
2391 if (index_init_nt(self) == -1)
2391 return -1;
2392 return -1;
2392 return nt_insert(&self->nt, node, (int)rev);
2393 return nt_insert(&self->nt, node, (int)rev);
2393 }
2394 }
2394
2395
2395 /*
2396 /*
2396 * Find all RevlogNG entries in an index that has inline data. Update
2397 * Find all RevlogNG entries in an index that has inline data. Update
2397 * the optional "offsets" table with those entries.
2398 * the optional "offsets" table with those entries.
2398 */
2399 */
2399 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2400 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2400 {
2401 {
2401 const char *data = (const char *)self->buf.buf;
2402 const char *data = (const char *)self->buf.buf;
2402 Py_ssize_t pos = 0;
2403 Py_ssize_t pos = 0;
2403 Py_ssize_t end = self->buf.len;
2404 Py_ssize_t end = self->buf.len;
2404 long incr = v1_hdrsize;
2405 long incr = v1_hdrsize;
2405 Py_ssize_t len = 0;
2406 Py_ssize_t len = 0;
2406
2407
2407 while (pos + v1_hdrsize <= end && pos >= 0) {
2408 while (pos + v1_hdrsize <= end && pos >= 0) {
2408 uint32_t comp_len;
2409 uint32_t comp_len;
2409 /* 3rd element of header is length of compressed inline data */
2410 /* 3rd element of header is length of compressed inline data */
2410 comp_len = getbe32(data + pos + 8);
2411 comp_len = getbe32(data + pos + 8);
2411 incr = v1_hdrsize + comp_len;
2412 incr = v1_hdrsize + comp_len;
2412 if (offsets)
2413 if (offsets)
2413 offsets[len] = data + pos;
2414 offsets[len] = data + pos;
2414 len++;
2415 len++;
2415 pos += incr;
2416 pos += incr;
2416 }
2417 }
2417
2418
2418 if (pos != end) {
2419 if (pos != end) {
2419 if (!PyErr_Occurred())
2420 if (!PyErr_Occurred())
2420 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2421 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2421 return -1;
2422 return -1;
2422 }
2423 }
2423
2424
2424 return len;
2425 return len;
2425 }
2426 }
2426
2427
2427 static int index_init(indexObject *self, PyObject *args)
2428 static int index_init(indexObject *self, PyObject *args)
2428 {
2429 {
2429 PyObject *data_obj, *inlined_obj;
2430 PyObject *data_obj, *inlined_obj;
2430 Py_ssize_t size;
2431 Py_ssize_t size;
2431
2432
2432 /* Initialize before argument-checking to avoid index_dealloc() crash.
2433 /* Initialize before argument-checking to avoid index_dealloc() crash.
2433 */
2434 */
2434 self->raw_length = 0;
2435 self->raw_length = 0;
2435 self->added = NULL;
2436 self->added = NULL;
2436 self->cache = NULL;
2437 self->cache = NULL;
2437 self->data = NULL;
2438 self->data = NULL;
2438 memset(&self->buf, 0, sizeof(self->buf));
2439 memset(&self->buf, 0, sizeof(self->buf));
2439 self->headrevs = NULL;
2440 self->headrevs = NULL;
2440 self->filteredrevs = Py_None;
2441 self->filteredrevs = Py_None;
2441 Py_INCREF(Py_None);
2442 Py_INCREF(Py_None);
2442 self->ntinitialized = 0;
2443 self->ntinitialized = 0;
2443 self->offsets = NULL;
2444 self->offsets = NULL;
2444
2445
2445 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2446 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2446 return -1;
2447 return -1;
2447 if (!PyObject_CheckBuffer(data_obj)) {
2448 if (!PyObject_CheckBuffer(data_obj)) {
2448 PyErr_SetString(PyExc_TypeError,
2449 PyErr_SetString(PyExc_TypeError,
2449 "data does not support buffer interface");
2450 "data does not support buffer interface");
2450 return -1;
2451 return -1;
2451 }
2452 }
2452
2453
2453 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2454 if (PyObject_GetBuffer(data_obj, &self->buf, PyBUF_SIMPLE) == -1)
2454 return -1;
2455 return -1;
2455 size = self->buf.len;
2456 size = self->buf.len;
2456
2457
2457 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2458 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2458 self->data = data_obj;
2459 self->data = data_obj;
2459
2460
2460 self->ntlookups = self->ntmisses = 0;
2461 self->ntlookups = self->ntmisses = 0;
2461 self->ntrev = -1;
2462 self->ntrev = -1;
2462 Py_INCREF(self->data);
2463 Py_INCREF(self->data);
2463
2464
2464 if (self->inlined) {
2465 if (self->inlined) {
2465 Py_ssize_t len = inline_scan(self, NULL);
2466 Py_ssize_t len = inline_scan(self, NULL);
2466 if (len == -1)
2467 if (len == -1)
2467 goto bail;
2468 goto bail;
2468 self->raw_length = len;
2469 self->raw_length = len;
2469 self->length = len;
2470 self->length = len;
2470 } else {
2471 } else {
2471 if (size % v1_hdrsize) {
2472 if (size % v1_hdrsize) {
2472 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2473 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2473 goto bail;
2474 goto bail;
2474 }
2475 }
2475 self->raw_length = size / v1_hdrsize;
2476 self->raw_length = size / v1_hdrsize;
2476 self->length = self->raw_length;
2477 self->length = self->raw_length;
2477 }
2478 }
2478
2479
2479 return 0;
2480 return 0;
2480 bail:
2481 bail:
2481 return -1;
2482 return -1;
2482 }
2483 }
2483
2484
2484 static PyObject *index_nodemap(indexObject *self)
2485 static PyObject *index_nodemap(indexObject *self)
2485 {
2486 {
2486 Py_INCREF(self);
2487 Py_INCREF(self);
2487 return (PyObject *)self;
2488 return (PyObject *)self;
2488 }
2489 }
2489
2490
2490 static void _index_clearcaches(indexObject *self)
2491 static void _index_clearcaches(indexObject *self)
2491 {
2492 {
2492 if (self->cache) {
2493 if (self->cache) {
2493 Py_ssize_t i;
2494 Py_ssize_t i;
2494
2495
2495 for (i = 0; i < self->raw_length; i++)
2496 for (i = 0; i < self->raw_length; i++)
2496 Py_CLEAR(self->cache[i]);
2497 Py_CLEAR(self->cache[i]);
2497 free(self->cache);
2498 free(self->cache);
2498 self->cache = NULL;
2499 self->cache = NULL;
2499 }
2500 }
2500 if (self->offsets) {
2501 if (self->offsets) {
2501 PyMem_Free((void *)self->offsets);
2502 PyMem_Free((void *)self->offsets);
2502 self->offsets = NULL;
2503 self->offsets = NULL;
2503 }
2504 }
2504 if (self->ntinitialized) {
2505 if (self->ntinitialized) {
2505 nt_dealloc(&self->nt);
2506 nt_dealloc(&self->nt);
2506 }
2507 }
2507 self->ntinitialized = 0;
2508 self->ntinitialized = 0;
2508 Py_CLEAR(self->headrevs);
2509 Py_CLEAR(self->headrevs);
2509 }
2510 }
2510
2511
2511 static PyObject *index_clearcaches(indexObject *self)
2512 static PyObject *index_clearcaches(indexObject *self)
2512 {
2513 {
2513 _index_clearcaches(self);
2514 _index_clearcaches(self);
2514 self->ntrev = -1;
2515 self->ntrev = -1;
2515 self->ntlookups = self->ntmisses = 0;
2516 self->ntlookups = self->ntmisses = 0;
2516 Py_RETURN_NONE;
2517 Py_RETURN_NONE;
2517 }
2518 }
2518
2519
2519 static void index_dealloc(indexObject *self)
2520 static void index_dealloc(indexObject *self)
2520 {
2521 {
2521 _index_clearcaches(self);
2522 _index_clearcaches(self);
2522 Py_XDECREF(self->filteredrevs);
2523 Py_XDECREF(self->filteredrevs);
2523 if (self->buf.buf) {
2524 if (self->buf.buf) {
2524 PyBuffer_Release(&self->buf);
2525 PyBuffer_Release(&self->buf);
2525 memset(&self->buf, 0, sizeof(self->buf));
2526 memset(&self->buf, 0, sizeof(self->buf));
2526 }
2527 }
2527 Py_XDECREF(self->data);
2528 Py_XDECREF(self->data);
2528 Py_XDECREF(self->added);
2529 Py_XDECREF(self->added);
2529 PyObject_Del(self);
2530 PyObject_Del(self);
2530 }
2531 }
2531
2532
2532 static PySequenceMethods index_sequence_methods = {
2533 static PySequenceMethods index_sequence_methods = {
2533 (lenfunc)index_length, /* sq_length */
2534 (lenfunc)index_length, /* sq_length */
2534 0, /* sq_concat */
2535 0, /* sq_concat */
2535 0, /* sq_repeat */
2536 0, /* sq_repeat */
2536 (ssizeargfunc)index_get, /* sq_item */
2537 (ssizeargfunc)index_get, /* sq_item */
2537 0, /* sq_slice */
2538 0, /* sq_slice */
2538 0, /* sq_ass_item */
2539 0, /* sq_ass_item */
2539 0, /* sq_ass_slice */
2540 0, /* sq_ass_slice */
2540 (objobjproc)index_contains, /* sq_contains */
2541 (objobjproc)index_contains, /* sq_contains */
2541 };
2542 };
2542
2543
2543 static PyMappingMethods index_mapping_methods = {
2544 static PyMappingMethods index_mapping_methods = {
2544 (lenfunc)index_length, /* mp_length */
2545 (lenfunc)index_length, /* mp_length */
2545 (binaryfunc)index_getitem, /* mp_subscript */
2546 (binaryfunc)index_getitem, /* mp_subscript */
2546 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2547 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2547 };
2548 };
2548
2549
2549 static PyMethodDef index_methods[] = {
2550 static PyMethodDef index_methods[] = {
2550 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2551 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2551 "return the gca set of the given revs"},
2552 "return the gca set of the given revs"},
2552 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2553 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2553 METH_VARARGS,
2554 METH_VARARGS,
2554 "return the heads of the common ancestors of the given revs"},
2555 "return the heads of the common ancestors of the given revs"},
2555 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2556 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2556 "clear the index caches"},
2557 "clear the index caches"},
2557 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2558 {"get", (PyCFunction)index_m_get, METH_VARARGS, "get an index entry"},
2558 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2559 {"computephasesmapsets", (PyCFunction)compute_phases_map_sets, METH_VARARGS,
2559 "compute phases"},
2560 "compute phases"},
2560 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2561 {"reachableroots2", (PyCFunction)reachableroots2, METH_VARARGS,
2561 "reachableroots"},
2562 "reachableroots"},
2562 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2563 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2563 "get head revisions"}, /* Can do filtering since 3.2 */
2564 "get head revisions"}, /* Can do filtering since 3.2 */
2564 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2565 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2565 "get filtered head revisions"}, /* Can always do filtering */
2566 "get filtered head revisions"}, /* Can always do filtering */
2566 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2567 {"deltachain", (PyCFunction)index_deltachain, METH_VARARGS,
2567 "determine revisions with deltas to reconstruct fulltext"},
2568 "determine revisions with deltas to reconstruct fulltext"},
2568 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2569 {"slicechunktodensity", (PyCFunction)index_slicechunktodensity,
2569 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2570 METH_VARARGS, "determine revisions with deltas to reconstruct fulltext"},
2570 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2571 {"append", (PyCFunction)index_append, METH_O, "append an index entry"},
2571 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2572 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2572 "match a potentially ambiguous node ID"},
2573 "match a potentially ambiguous node ID"},
2573 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2574 {"shortest", (PyCFunction)index_shortest, METH_VARARGS,
2574 "find length of shortest hex nodeid of a binary ID"},
2575 "find length of shortest hex nodeid of a binary ID"},
2575 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2576 {"stats", (PyCFunction)index_stats, METH_NOARGS, "stats for the index"},
2576 {NULL} /* Sentinel */
2577 {NULL} /* Sentinel */
2577 };
2578 };
2578
2579
2579 static PyGetSetDef index_getset[] = {
2580 static PyGetSetDef index_getset[] = {
2580 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2581 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2581 {NULL} /* Sentinel */
2582 {NULL} /* Sentinel */
2582 };
2583 };
2583
2584
2584 PyTypeObject indexType = {
2585 PyTypeObject HgRevlogIndex_Type = {
2585 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2586 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2586 "parsers.index", /* tp_name */
2587 "parsers.index", /* tp_name */
2587 sizeof(indexObject), /* tp_basicsize */
2588 sizeof(indexObject), /* tp_basicsize */
2588 0, /* tp_itemsize */
2589 0, /* tp_itemsize */
2589 (destructor)index_dealloc, /* tp_dealloc */
2590 (destructor)index_dealloc, /* tp_dealloc */
2590 0, /* tp_print */
2591 0, /* tp_print */
2591 0, /* tp_getattr */
2592 0, /* tp_getattr */
2592 0, /* tp_setattr */
2593 0, /* tp_setattr */
2593 0, /* tp_compare */
2594 0, /* tp_compare */
2594 0, /* tp_repr */
2595 0, /* tp_repr */
2595 0, /* tp_as_number */
2596 0, /* tp_as_number */
2596 &index_sequence_methods, /* tp_as_sequence */
2597 &index_sequence_methods, /* tp_as_sequence */
2597 &index_mapping_methods, /* tp_as_mapping */
2598 &index_mapping_methods, /* tp_as_mapping */
2598 0, /* tp_hash */
2599 0, /* tp_hash */
2599 0, /* tp_call */
2600 0, /* tp_call */
2600 0, /* tp_str */
2601 0, /* tp_str */
2601 0, /* tp_getattro */
2602 0, /* tp_getattro */
2602 0, /* tp_setattro */
2603 0, /* tp_setattro */
2603 0, /* tp_as_buffer */
2604 0, /* tp_as_buffer */
2604 Py_TPFLAGS_DEFAULT, /* tp_flags */
2605 Py_TPFLAGS_DEFAULT, /* tp_flags */
2605 "revlog index", /* tp_doc */
2606 "revlog index", /* tp_doc */
2606 0, /* tp_traverse */
2607 0, /* tp_traverse */
2607 0, /* tp_clear */
2608 0, /* tp_clear */
2608 0, /* tp_richcompare */
2609 0, /* tp_richcompare */
2609 0, /* tp_weaklistoffset */
2610 0, /* tp_weaklistoffset */
2610 0, /* tp_iter */
2611 0, /* tp_iter */
2611 0, /* tp_iternext */
2612 0, /* tp_iternext */
2612 index_methods, /* tp_methods */
2613 index_methods, /* tp_methods */
2613 0, /* tp_members */
2614 0, /* tp_members */
2614 index_getset, /* tp_getset */
2615 index_getset, /* tp_getset */
2615 0, /* tp_base */
2616 0, /* tp_base */
2616 0, /* tp_dict */
2617 0, /* tp_dict */
2617 0, /* tp_descr_get */
2618 0, /* tp_descr_get */
2618 0, /* tp_descr_set */
2619 0, /* tp_descr_set */
2619 0, /* tp_dictoffset */
2620 0, /* tp_dictoffset */
2620 (initproc)index_init, /* tp_init */
2621 (initproc)index_init, /* tp_init */
2621 0, /* tp_alloc */
2622 0, /* tp_alloc */
2622 };
2623 };
2623
2624
2624 /*
2625 /*
2625 * returns a tuple of the form (index, index, cache) with elements as
2626 * returns a tuple of the form (index, index, cache) with elements as
2626 * follows:
2627 * follows:
2627 *
2628 *
2628 * index: an index object that lazily parses RevlogNG records
2629 * index: an index object that lazily parses RevlogNG records
2629 * cache: if data is inlined, a tuple (0, index_file_content), else None
2630 * cache: if data is inlined, a tuple (0, index_file_content), else None
2630 * index_file_content could be a string, or a buffer
2631 * index_file_content could be a string, or a buffer
2631 *
2632 *
2632 * added complications are for backwards compatibility
2633 * added complications are for backwards compatibility
2633 */
2634 */
2634 PyObject *parse_index2(PyObject *self, PyObject *args)
2635 PyObject *parse_index2(PyObject *self, PyObject *args)
2635 {
2636 {
2636 PyObject *tuple = NULL, *cache = NULL;
2637 PyObject *tuple = NULL, *cache = NULL;
2637 indexObject *idx;
2638 indexObject *idx;
2638 int ret;
2639 int ret;
2639
2640
2640 idx = PyObject_New(indexObject, &indexType);
2641 idx = PyObject_New(indexObject, &HgRevlogIndex_Type);
2641 if (idx == NULL)
2642 if (idx == NULL)
2642 goto bail;
2643 goto bail;
2643
2644
2644 ret = index_init(idx, args);
2645 ret = index_init(idx, args);
2645 if (ret == -1)
2646 if (ret == -1)
2646 goto bail;
2647 goto bail;
2647
2648
2648 if (idx->inlined) {
2649 if (idx->inlined) {
2649 cache = Py_BuildValue("iO", 0, idx->data);
2650 cache = Py_BuildValue("iO", 0, idx->data);
2650 if (cache == NULL)
2651 if (cache == NULL)
2651 goto bail;
2652 goto bail;
2652 } else {
2653 } else {
2653 cache = Py_None;
2654 cache = Py_None;
2654 Py_INCREF(cache);
2655 Py_INCREF(cache);
2655 }
2656 }
2656
2657
2657 tuple = Py_BuildValue("NN", idx, cache);
2658 tuple = Py_BuildValue("NN", idx, cache);
2658 if (!tuple)
2659 if (!tuple)
2659 goto bail;
2660 goto bail;
2660 return tuple;
2661 return tuple;
2661
2662
2662 bail:
2663 bail:
2663 Py_XDECREF(idx);
2664 Py_XDECREF(idx);
2664 Py_XDECREF(cache);
2665 Py_XDECREF(cache);
2665 Py_XDECREF(tuple);
2666 Py_XDECREF(tuple);
2666 return NULL;
2667 return NULL;
2667 }
2668 }
2668
2669
2669 #ifdef WITH_RUST
2670 #ifdef WITH_RUST
2670
2671
2671 /* rustlazyancestors: iteration over ancestors implemented in Rust
2672 /* rustlazyancestors: iteration over ancestors implemented in Rust
2672 *
2673 *
2673 * This class holds a reference to an index and to the Rust iterator.
2674 * This class holds a reference to an index and to the Rust iterator.
2674 */
2675 */
2675 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject;
2676 typedef struct rustlazyancestorsObjectStruct rustlazyancestorsObject;
2676
2677
2677 struct rustlazyancestorsObjectStruct {
2678 struct rustlazyancestorsObjectStruct {
2678 PyObject_HEAD
2679 PyObject_HEAD
2679 /* Type-specific fields go here. */
2680 /* Type-specific fields go here. */
2680 indexObject *index; /* Ref kept to avoid GC'ing the index */
2681 indexObject *index; /* Ref kept to avoid GC'ing the index */
2681 void *iter; /* Rust iterator */
2682 void *iter; /* Rust iterator */
2682 };
2683 };
2683
2684
2684 /* FFI exposed from Rust code */
2685 /* FFI exposed from Rust code */
2685 rustlazyancestorsObject *
2686 rustlazyancestorsObject *
2686 rustlazyancestors_init(indexObject *index,
2687 rustlazyancestors_init(indexObject *index,
2687 /* to pass index_get_parents() */
2688 /* to pass index_get_parents() */
2688 int (*)(indexObject *, Py_ssize_t, int *, int),
2689 int (*)(indexObject *, Py_ssize_t, int *, int),
2689 /* intrevs vector */
2690 /* intrevs vector */
2690 Py_ssize_t initrevslen, long *initrevs, long stoprev,
2691 Py_ssize_t initrevslen, long *initrevs, long stoprev,
2691 int inclusive);
2692 int inclusive);
2692 void rustlazyancestors_drop(rustlazyancestorsObject *self);
2693 void rustlazyancestors_drop(rustlazyancestorsObject *self);
2693 int rustlazyancestors_next(rustlazyancestorsObject *self);
2694 int rustlazyancestors_next(rustlazyancestorsObject *self);
2694 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
2695 int rustlazyancestors_contains(rustlazyancestorsObject *self, long rev);
2695
2696
2696 static int index_get_parents_checked(indexObject *self, Py_ssize_t rev, int *ps,
2697 static int index_get_parents_checked(indexObject *self, Py_ssize_t rev, int *ps,
2697 int maxrev)
2698 int maxrev)
2698 {
2699 {
2699 if (rev < 0 || rev >= index_length(self)) {
2700 if (rev < 0 || rev >= index_length(self)) {
2700 PyErr_SetString(PyExc_ValueError, "rev out of range");
2701 PyErr_SetString(PyExc_ValueError, "rev out of range");
2701 return -1;
2702 return -1;
2702 }
2703 }
2703 return index_get_parents(self, rev, ps, maxrev);
2704 return index_get_parents(self, rev, ps, maxrev);
2704 }
2705 }
2705
2706
2706 /* CPython instance methods */
2707 /* CPython instance methods */
2707 static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
2708 static int rustla_init(rustlazyancestorsObject *self, PyObject *args)
2708 {
2709 {
2709 PyObject *initrevsarg = NULL;
2710 PyObject *initrevsarg = NULL;
2710 PyObject *inclusivearg = NULL;
2711 PyObject *inclusivearg = NULL;
2711 long stoprev = 0;
2712 long stoprev = 0;
2712 long *initrevs = NULL;
2713 long *initrevs = NULL;
2713 int inclusive = 0;
2714 int inclusive = 0;
2714 Py_ssize_t i;
2715 Py_ssize_t i;
2715
2716
2716 indexObject *index;
2717 indexObject *index;
2717 if (!PyArg_ParseTuple(args, "O!O!lO!", &indexType, &index, &PyList_Type,
2718 if (!PyArg_ParseTuple(args, "O!O!lO!", &HgRevlogIndex_Type, &index,
2718 &initrevsarg, &stoprev, &PyBool_Type,
2719 &PyList_Type, &initrevsarg, &stoprev,
2719 &inclusivearg))
2720 &PyBool_Type, &inclusivearg))
2720 return -1;
2721 return -1;
2721
2722
2722 Py_INCREF(index);
2723 Py_INCREF(index);
2723 self->index = index;
2724 self->index = index;
2724
2725
2725 if (inclusivearg == Py_True)
2726 if (inclusivearg == Py_True)
2726 inclusive = 1;
2727 inclusive = 1;
2727
2728
2728 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg);
2729 Py_ssize_t linit = PyList_GET_SIZE(initrevsarg);
2729
2730
2730 initrevs = (long *)calloc(linit, sizeof(long));
2731 initrevs = (long *)calloc(linit, sizeof(long));
2731
2732
2732 if (initrevs == NULL) {
2733 if (initrevs == NULL) {
2733 PyErr_NoMemory();
2734 PyErr_NoMemory();
2734 goto bail;
2735 goto bail;
2735 }
2736 }
2736
2737
2737 for (i = 0; i < linit; i++) {
2738 for (i = 0; i < linit; i++) {
2738 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
2739 initrevs[i] = PyInt_AsLong(PyList_GET_ITEM(initrevsarg, i));
2739 }
2740 }
2740 if (PyErr_Occurred())
2741 if (PyErr_Occurred())
2741 goto bail;
2742 goto bail;
2742
2743
2743 self->iter = rustlazyancestors_init(index, index_get_parents, linit,
2744 self->iter = rustlazyancestors_init(index, index_get_parents, linit,
2744 initrevs, stoprev, inclusive);
2745 initrevs, stoprev, inclusive);
2745 if (self->iter == NULL) {
2746 if (self->iter == NULL) {
2746 /* if this is because of GraphError::ParentOutOfRange
2747 /* if this is because of GraphError::ParentOutOfRange
2747 * index_get_parents_checked() has already set the proper
2748 * index_get_parents_checked() has already set the proper
2748 * ValueError */
2749 * ValueError */
2749 goto bail;
2750 goto bail;
2750 }
2751 }
2751
2752
2752 free(initrevs);
2753 free(initrevs);
2753 return 0;
2754 return 0;
2754
2755
2755 bail:
2756 bail:
2756 free(initrevs);
2757 free(initrevs);
2757 return -1;
2758 return -1;
2758 };
2759 };
2759
2760
2760 static void rustla_dealloc(rustlazyancestorsObject *self)
2761 static void rustla_dealloc(rustlazyancestorsObject *self)
2761 {
2762 {
2762 Py_XDECREF(self->index);
2763 Py_XDECREF(self->index);
2763 if (self->iter != NULL) { /* can happen if rustla_init failed */
2764 if (self->iter != NULL) { /* can happen if rustla_init failed */
2764 rustlazyancestors_drop(self->iter);
2765 rustlazyancestors_drop(self->iter);
2765 }
2766 }
2766 PyObject_Del(self);
2767 PyObject_Del(self);
2767 }
2768 }
2768
2769
2769 static PyObject *rustla_next(rustlazyancestorsObject *self)
2770 static PyObject *rustla_next(rustlazyancestorsObject *self)
2770 {
2771 {
2771 int res = rustlazyancestors_next(self->iter);
2772 int res = rustlazyancestors_next(self->iter);
2772 if (res == -1) {
2773 if (res == -1) {
2773 /* Setting an explicit exception seems unnecessary
2774 /* Setting an explicit exception seems unnecessary
2774 * as examples from Python source code (Objects/rangeobjets.c
2775 * as examples from Python source code (Objects/rangeobjets.c
2775 * and Modules/_io/stringio.c) seem to demonstrate.
2776 * and Modules/_io/stringio.c) seem to demonstrate.
2776 */
2777 */
2777 return NULL;
2778 return NULL;
2778 }
2779 }
2779 return PyInt_FromLong(res);
2780 return PyInt_FromLong(res);
2780 }
2781 }
2781
2782
2782 static int rustla_contains(rustlazyancestorsObject *self, PyObject *rev)
2783 static int rustla_contains(rustlazyancestorsObject *self, PyObject *rev)
2783 {
2784 {
2784 long lrev;
2785 long lrev;
2785 if (!pylong_to_long(rev, &lrev)) {
2786 if (!pylong_to_long(rev, &lrev)) {
2786 PyErr_Clear();
2787 PyErr_Clear();
2787 return 0;
2788 return 0;
2788 }
2789 }
2789 return rustlazyancestors_contains(self->iter, lrev);
2790 return rustlazyancestors_contains(self->iter, lrev);
2790 }
2791 }
2791
2792
2792 static PySequenceMethods rustla_sequence_methods = {
2793 static PySequenceMethods rustla_sequence_methods = {
2793 0, /* sq_length */
2794 0, /* sq_length */
2794 0, /* sq_concat */
2795 0, /* sq_concat */
2795 0, /* sq_repeat */
2796 0, /* sq_repeat */
2796 0, /* sq_item */
2797 0, /* sq_item */
2797 0, /* sq_slice */
2798 0, /* sq_slice */
2798 0, /* sq_ass_item */
2799 0, /* sq_ass_item */
2799 0, /* sq_ass_slice */
2800 0, /* sq_ass_slice */
2800 (objobjproc)rustla_contains, /* sq_contains */
2801 (objobjproc)rustla_contains, /* sq_contains */
2801 };
2802 };
2802
2803
2803 static PyTypeObject rustlazyancestorsType = {
2804 static PyTypeObject rustlazyancestorsType = {
2804 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2805 PyVarObject_HEAD_INIT(NULL, 0) /* header */
2805 "parsers.rustlazyancestors", /* tp_name */
2806 "parsers.rustlazyancestors", /* tp_name */
2806 sizeof(rustlazyancestorsObject), /* tp_basicsize */
2807 sizeof(rustlazyancestorsObject), /* tp_basicsize */
2807 0, /* tp_itemsize */
2808 0, /* tp_itemsize */
2808 (destructor)rustla_dealloc, /* tp_dealloc */
2809 (destructor)rustla_dealloc, /* tp_dealloc */
2809 0, /* tp_print */
2810 0, /* tp_print */
2810 0, /* tp_getattr */
2811 0, /* tp_getattr */
2811 0, /* tp_setattr */
2812 0, /* tp_setattr */
2812 0, /* tp_compare */
2813 0, /* tp_compare */
2813 0, /* tp_repr */
2814 0, /* tp_repr */
2814 0, /* tp_as_number */
2815 0, /* tp_as_number */
2815 &rustla_sequence_methods, /* tp_as_sequence */
2816 &rustla_sequence_methods, /* tp_as_sequence */
2816 0, /* tp_as_mapping */
2817 0, /* tp_as_mapping */
2817 0, /* tp_hash */
2818 0, /* tp_hash */
2818 0, /* tp_call */
2819 0, /* tp_call */
2819 0, /* tp_str */
2820 0, /* tp_str */
2820 0, /* tp_getattro */
2821 0, /* tp_getattro */
2821 0, /* tp_setattro */
2822 0, /* tp_setattro */
2822 0, /* tp_as_buffer */
2823 0, /* tp_as_buffer */
2823 Py_TPFLAGS_DEFAULT, /* tp_flags */
2824 Py_TPFLAGS_DEFAULT, /* tp_flags */
2824 "Iterator over ancestors, implemented in Rust", /* tp_doc */
2825 "Iterator over ancestors, implemented in Rust", /* tp_doc */
2825 0, /* tp_traverse */
2826 0, /* tp_traverse */
2826 0, /* tp_clear */
2827 0, /* tp_clear */
2827 0, /* tp_richcompare */
2828 0, /* tp_richcompare */
2828 0, /* tp_weaklistoffset */
2829 0, /* tp_weaklistoffset */
2829 0, /* tp_iter */
2830 0, /* tp_iter */
2830 (iternextfunc)rustla_next, /* tp_iternext */
2831 (iternextfunc)rustla_next, /* tp_iternext */
2831 0, /* tp_methods */
2832 0, /* tp_methods */
2832 0, /* tp_members */
2833 0, /* tp_members */
2833 0, /* tp_getset */
2834 0, /* tp_getset */
2834 0, /* tp_base */
2835 0, /* tp_base */
2835 0, /* tp_dict */
2836 0, /* tp_dict */
2836 0, /* tp_descr_get */
2837 0, /* tp_descr_get */
2837 0, /* tp_descr_set */
2838 0, /* tp_descr_set */
2838 0, /* tp_dictoffset */
2839 0, /* tp_dictoffset */
2839 (initproc)rustla_init, /* tp_init */
2840 (initproc)rustla_init, /* tp_init */
2840 0, /* tp_alloc */
2841 0, /* tp_alloc */
2841 };
2842 };
2842 #endif /* WITH_RUST */
2843 #endif /* WITH_RUST */
2843
2844
2844 void revlog_module_init(PyObject *mod)
2845 void revlog_module_init(PyObject *mod)
2845 {
2846 {
2846 indexType.tp_new = PyType_GenericNew;
2847 HgRevlogIndex_Type.tp_new = PyType_GenericNew;
2847 if (PyType_Ready(&indexType) < 0)
2848 if (PyType_Ready(&HgRevlogIndex_Type) < 0)
2848 return;
2849 return;
2849 Py_INCREF(&indexType);
2850 Py_INCREF(&HgRevlogIndex_Type);
2850 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2851 PyModule_AddObject(mod, "index", (PyObject *)&HgRevlogIndex_Type);
2851
2852
2852 nodetreeType.tp_new = PyType_GenericNew;
2853 nodetreeType.tp_new = PyType_GenericNew;
2853 if (PyType_Ready(&nodetreeType) < 0)
2854 if (PyType_Ready(&nodetreeType) < 0)
2854 return;
2855 return;
2855 Py_INCREF(&nodetreeType);
2856 Py_INCREF(&nodetreeType);
2856 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
2857 PyModule_AddObject(mod, "nodetree", (PyObject *)&nodetreeType);
2857
2858
2858 if (!nullentry) {
2859 if (!nullentry) {
2859 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0,
2860 nullentry = Py_BuildValue(PY23("iiiiiiis#", "iiiiiiiy#"), 0, 0,
2860 0, -1, -1, -1, -1, nullid, 20);
2861 0, -1, -1, -1, -1, nullid, 20);
2861 }
2862 }
2862 if (nullentry)
2863 if (nullentry)
2863 PyObject_GC_UnTrack(nullentry);
2864 PyObject_GC_UnTrack(nullentry);
2864
2865
2865 #ifdef WITH_RUST
2866 #ifdef WITH_RUST
2866 rustlazyancestorsType.tp_new = PyType_GenericNew;
2867 rustlazyancestorsType.tp_new = PyType_GenericNew;
2867 if (PyType_Ready(&rustlazyancestorsType) < 0)
2868 if (PyType_Ready(&rustlazyancestorsType) < 0)
2868 return;
2869 return;
2869 Py_INCREF(&rustlazyancestorsType);
2870 Py_INCREF(&rustlazyancestorsType);
2870 PyModule_AddObject(mod, "rustlazyancestors",
2871 PyModule_AddObject(mod, "rustlazyancestors",
2871 (PyObject *)&rustlazyancestorsType);
2872 (PyObject *)&rustlazyancestorsType);
2872 #endif
2873 #endif
2873 }
2874 }
@@ -1,15 +1,15 b''
1 /*
1 /*
2 revlog.h - efficient revlog parsing
2 revlog.h - efficient revlog parsing
3
3
4 This software may be used and distributed according to the terms of
4 This software may be used and distributed according to the terms of
5 the GNU General Public License, incorporated herein by reference.
5 the GNU General Public License, incorporated herein by reference.
6 */
6 */
7
7
8 #ifndef _HG_REVLOG_H_
8 #ifndef _HG_REVLOG_H_
9 #define _HG_REVLOG_H_
9 #define _HG_REVLOG_H_
10
10
11 #include <Python.h>
11 #include <Python.h>
12
12
13 extern PyTypeObject indexType;
13 extern PyTypeObject HgRevlogIndex_Type;
14
14
15 #endif /* _HG_REVLOG_H_ */
15 #endif /* _HG_REVLOG_H_ */
General Comments 0
You need to be logged in to leave comments. Login now