##// END OF EJS Templates
parsers: make _asciilower a generic _asciitransform function...
Siddharth Agarwal -
r24576:fe173106 default
parent child Browse files
Show More
@@ -1,2526 +1,2527
1 /*
1 /*
2 parsers.c - efficient content parsing
2 parsers.c - efficient content parsing
3
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 #include <Python.h>
10 #include <Python.h>
11 #include <ctype.h>
11 #include <ctype.h>
12 #include <stddef.h>
12 #include <stddef.h>
13 #include <string.h>
13 #include <string.h>
14
14
15 #include "util.h"
15 #include "util.h"
16
16
17 static char *versionerrortext = "Python minor version mismatch";
17 static char *versionerrortext = "Python minor version mismatch";
18
18
19 static int8_t hextable[256] = {
19 static int8_t hextable[256] = {
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
20 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
21 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
22 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
23 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /* 0-9 */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
24 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* A-F */
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
25 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
26 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* a-f */
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
27 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
28 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
29 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
30 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
31 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
32 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
33 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
34 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
35 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
36 };
36 };
37
37
38 static char lowertable[128] = {
38 static char lowertable[128] = {
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
39 '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
40 '\x08', '\x09', '\x0a', '\x0b', '\x0c', '\x0d', '\x0e', '\x0f',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
41 '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
42 '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
43 '\x20', '\x21', '\x22', '\x23', '\x24', '\x25', '\x26', '\x27',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
44 '\x28', '\x29', '\x2a', '\x2b', '\x2c', '\x2d', '\x2e', '\x2f',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
45 '\x30', '\x31', '\x32', '\x33', '\x34', '\x35', '\x36', '\x37',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
46 '\x38', '\x39', '\x3a', '\x3b', '\x3c', '\x3d', '\x3e', '\x3f',
47 '\x40',
47 '\x40',
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
48 '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67', /* A-G */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
49 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f', /* H-O */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
50 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77', /* P-W */
51 '\x78', '\x79', '\x7a', /* X-Z */
51 '\x78', '\x79', '\x7a', /* X-Z */
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
52 '\x5b', '\x5c', '\x5d', '\x5e', '\x5f',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
53 '\x60', '\x61', '\x62', '\x63', '\x64', '\x65', '\x66', '\x67',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
54 '\x68', '\x69', '\x6a', '\x6b', '\x6c', '\x6d', '\x6e', '\x6f',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
55 '\x70', '\x71', '\x72', '\x73', '\x74', '\x75', '\x76', '\x77',
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
56 '\x78', '\x79', '\x7a', '\x7b', '\x7c', '\x7d', '\x7e', '\x7f'
57 };
57 };
58
58
59 static inline int hexdigit(const char *p, Py_ssize_t off)
59 static inline int hexdigit(const char *p, Py_ssize_t off)
60 {
60 {
61 int8_t val = hextable[(unsigned char)p[off]];
61 int8_t val = hextable[(unsigned char)p[off]];
62
62
63 if (val >= 0) {
63 if (val >= 0) {
64 return val;
64 return val;
65 }
65 }
66
66
67 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
67 PyErr_SetString(PyExc_ValueError, "input contains non-hex character");
68 return 0;
68 return 0;
69 }
69 }
70
70
71 /*
71 /*
72 * Turn a hex-encoded string into binary.
72 * Turn a hex-encoded string into binary.
73 */
73 */
74 PyObject *unhexlify(const char *str, int len)
74 PyObject *unhexlify(const char *str, int len)
75 {
75 {
76 PyObject *ret;
76 PyObject *ret;
77 char *d;
77 char *d;
78 int i;
78 int i;
79
79
80 ret = PyBytes_FromStringAndSize(NULL, len / 2);
80 ret = PyBytes_FromStringAndSize(NULL, len / 2);
81
81
82 if (!ret)
82 if (!ret)
83 return NULL;
83 return NULL;
84
84
85 d = PyBytes_AsString(ret);
85 d = PyBytes_AsString(ret);
86
86
87 for (i = 0; i < len;) {
87 for (i = 0; i < len;) {
88 int hi = hexdigit(str, i++);
88 int hi = hexdigit(str, i++);
89 int lo = hexdigit(str, i++);
89 int lo = hexdigit(str, i++);
90 *d++ = (hi << 4) | lo;
90 *d++ = (hi << 4) | lo;
91 }
91 }
92
92
93 return ret;
93 return ret;
94 }
94 }
95
95
96 static inline PyObject *_asciilower(PyObject *str_obj)
96 static inline PyObject *_asciitransform(PyObject *str_obj,
97 const char table[128])
97 {
98 {
98 char *str, *newstr;
99 char *str, *newstr;
99 Py_ssize_t i, len;
100 Py_ssize_t i, len;
100 PyObject *newobj = NULL;
101 PyObject *newobj = NULL;
101 PyObject *ret = NULL;
102 PyObject *ret = NULL;
102
103
103 str = PyBytes_AS_STRING(str_obj);
104 str = PyBytes_AS_STRING(str_obj);
104 len = PyBytes_GET_SIZE(str_obj);
105 len = PyBytes_GET_SIZE(str_obj);
105
106
106 newobj = PyBytes_FromStringAndSize(NULL, len);
107 newobj = PyBytes_FromStringAndSize(NULL, len);
107 if (!newobj)
108 if (!newobj)
108 goto quit;
109 goto quit;
109
110
110 newstr = PyBytes_AS_STRING(newobj);
111 newstr = PyBytes_AS_STRING(newobj);
111
112
112 for (i = 0; i < len; i++) {
113 for (i = 0; i < len; i++) {
113 char c = str[i];
114 char c = str[i];
114 if (c & 0x80) {
115 if (c & 0x80) {
115 PyObject *err = PyUnicodeDecodeError_Create(
116 PyObject *err = PyUnicodeDecodeError_Create(
116 "ascii", str, len, i, (i + 1),
117 "ascii", str, len, i, (i + 1),
117 "unexpected code byte");
118 "unexpected code byte");
118 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
119 PyErr_SetObject(PyExc_UnicodeDecodeError, err);
119 Py_XDECREF(err);
120 Py_XDECREF(err);
120 goto quit;
121 goto quit;
121 }
122 }
122 newstr[i] = lowertable[(unsigned char)c];
123 newstr[i] = table[(unsigned char)c];
123 }
124 }
124
125
125 ret = newobj;
126 ret = newobj;
126 Py_INCREF(ret);
127 Py_INCREF(ret);
127 quit:
128 quit:
128 Py_XDECREF(newobj);
129 Py_XDECREF(newobj);
129 return ret;
130 return ret;
130 }
131 }
131
132
132 static PyObject *asciilower(PyObject *self, PyObject *args)
133 static PyObject *asciilower(PyObject *self, PyObject *args)
133 {
134 {
134 PyObject *str_obj;
135 PyObject *str_obj;
135 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
136 if (!PyArg_ParseTuple(args, "O!:asciilower", &PyBytes_Type, &str_obj))
136 return NULL;
137 return NULL;
137 return _asciilower(str_obj);
138 return _asciitransform(str_obj, lowertable);
138 }
139 }
139
140
140 /*
141 /*
141 * This code assumes that a manifest is stitched together with newline
142 * This code assumes that a manifest is stitched together with newline
142 * ('\n') characters.
143 * ('\n') characters.
143 */
144 */
144 static PyObject *parse_manifest(PyObject *self, PyObject *args)
145 static PyObject *parse_manifest(PyObject *self, PyObject *args)
145 {
146 {
146 PyObject *mfdict, *fdict;
147 PyObject *mfdict, *fdict;
147 char *str, *start, *end;
148 char *str, *start, *end;
148 int len;
149 int len;
149
150
150 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
151 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
151 &PyDict_Type, &mfdict,
152 &PyDict_Type, &mfdict,
152 &PyDict_Type, &fdict,
153 &PyDict_Type, &fdict,
153 &str, &len))
154 &str, &len))
154 goto quit;
155 goto quit;
155
156
156 start = str;
157 start = str;
157 end = str + len;
158 end = str + len;
158 while (start < end) {
159 while (start < end) {
159 PyObject *file = NULL, *node = NULL;
160 PyObject *file = NULL, *node = NULL;
160 PyObject *flags = NULL;
161 PyObject *flags = NULL;
161 char *zero = NULL, *newline = NULL;
162 char *zero = NULL, *newline = NULL;
162 ptrdiff_t nlen;
163 ptrdiff_t nlen;
163
164
164 zero = memchr(start, '\0', end - start);
165 zero = memchr(start, '\0', end - start);
165 if (!zero) {
166 if (!zero) {
166 PyErr_SetString(PyExc_ValueError,
167 PyErr_SetString(PyExc_ValueError,
167 "manifest entry has no separator");
168 "manifest entry has no separator");
168 goto quit;
169 goto quit;
169 }
170 }
170
171
171 newline = memchr(zero + 1, '\n', end - (zero + 1));
172 newline = memchr(zero + 1, '\n', end - (zero + 1));
172 if (!newline) {
173 if (!newline) {
173 PyErr_SetString(PyExc_ValueError,
174 PyErr_SetString(PyExc_ValueError,
174 "manifest contains trailing garbage");
175 "manifest contains trailing garbage");
175 goto quit;
176 goto quit;
176 }
177 }
177
178
178 file = PyBytes_FromStringAndSize(start, zero - start);
179 file = PyBytes_FromStringAndSize(start, zero - start);
179
180
180 if (!file)
181 if (!file)
181 goto bail;
182 goto bail;
182
183
183 nlen = newline - zero - 1;
184 nlen = newline - zero - 1;
184
185
185 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
186 node = unhexlify(zero + 1, nlen > 40 ? 40 : (int)nlen);
186 if (!node)
187 if (!node)
187 goto bail;
188 goto bail;
188
189
189 if (nlen > 40) {
190 if (nlen > 40) {
190 flags = PyBytes_FromStringAndSize(zero + 41,
191 flags = PyBytes_FromStringAndSize(zero + 41,
191 nlen - 40);
192 nlen - 40);
192 if (!flags)
193 if (!flags)
193 goto bail;
194 goto bail;
194
195
195 if (PyDict_SetItem(fdict, file, flags) == -1)
196 if (PyDict_SetItem(fdict, file, flags) == -1)
196 goto bail;
197 goto bail;
197 }
198 }
198
199
199 if (PyDict_SetItem(mfdict, file, node) == -1)
200 if (PyDict_SetItem(mfdict, file, node) == -1)
200 goto bail;
201 goto bail;
201
202
202 start = newline + 1;
203 start = newline + 1;
203
204
204 Py_XDECREF(flags);
205 Py_XDECREF(flags);
205 Py_XDECREF(node);
206 Py_XDECREF(node);
206 Py_XDECREF(file);
207 Py_XDECREF(file);
207 continue;
208 continue;
208 bail:
209 bail:
209 Py_XDECREF(flags);
210 Py_XDECREF(flags);
210 Py_XDECREF(node);
211 Py_XDECREF(node);
211 Py_XDECREF(file);
212 Py_XDECREF(file);
212 goto quit;
213 goto quit;
213 }
214 }
214
215
215 Py_INCREF(Py_None);
216 Py_INCREF(Py_None);
216 return Py_None;
217 return Py_None;
217 quit:
218 quit:
218 return NULL;
219 return NULL;
219 }
220 }
220
221
221 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
222 static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode,
222 int size, int mtime)
223 int size, int mtime)
223 {
224 {
224 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
225 dirstateTupleObject *t = PyObject_New(dirstateTupleObject,
225 &dirstateTupleType);
226 &dirstateTupleType);
226 if (!t)
227 if (!t)
227 return NULL;
228 return NULL;
228 t->state = state;
229 t->state = state;
229 t->mode = mode;
230 t->mode = mode;
230 t->size = size;
231 t->size = size;
231 t->mtime = mtime;
232 t->mtime = mtime;
232 return t;
233 return t;
233 }
234 }
234
235
235 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
236 static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args,
236 PyObject *kwds)
237 PyObject *kwds)
237 {
238 {
238 /* We do all the initialization here and not a tp_init function because
239 /* We do all the initialization here and not a tp_init function because
239 * dirstate_tuple is immutable. */
240 * dirstate_tuple is immutable. */
240 dirstateTupleObject *t;
241 dirstateTupleObject *t;
241 char state;
242 char state;
242 int size, mode, mtime;
243 int size, mode, mtime;
243 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
244 if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime))
244 return NULL;
245 return NULL;
245
246
246 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
247 t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1);
247 if (!t)
248 if (!t)
248 return NULL;
249 return NULL;
249 t->state = state;
250 t->state = state;
250 t->mode = mode;
251 t->mode = mode;
251 t->size = size;
252 t->size = size;
252 t->mtime = mtime;
253 t->mtime = mtime;
253
254
254 return (PyObject *)t;
255 return (PyObject *)t;
255 }
256 }
256
257
257 static void dirstate_tuple_dealloc(PyObject *o)
258 static void dirstate_tuple_dealloc(PyObject *o)
258 {
259 {
259 PyObject_Del(o);
260 PyObject_Del(o);
260 }
261 }
261
262
262 static Py_ssize_t dirstate_tuple_length(PyObject *o)
263 static Py_ssize_t dirstate_tuple_length(PyObject *o)
263 {
264 {
264 return 4;
265 return 4;
265 }
266 }
266
267
267 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
268 static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i)
268 {
269 {
269 dirstateTupleObject *t = (dirstateTupleObject *)o;
270 dirstateTupleObject *t = (dirstateTupleObject *)o;
270 switch (i) {
271 switch (i) {
271 case 0:
272 case 0:
272 return PyBytes_FromStringAndSize(&t->state, 1);
273 return PyBytes_FromStringAndSize(&t->state, 1);
273 case 1:
274 case 1:
274 return PyInt_FromLong(t->mode);
275 return PyInt_FromLong(t->mode);
275 case 2:
276 case 2:
276 return PyInt_FromLong(t->size);
277 return PyInt_FromLong(t->size);
277 case 3:
278 case 3:
278 return PyInt_FromLong(t->mtime);
279 return PyInt_FromLong(t->mtime);
279 default:
280 default:
280 PyErr_SetString(PyExc_IndexError, "index out of range");
281 PyErr_SetString(PyExc_IndexError, "index out of range");
281 return NULL;
282 return NULL;
282 }
283 }
283 }
284 }
284
285
285 static PySequenceMethods dirstate_tuple_sq = {
286 static PySequenceMethods dirstate_tuple_sq = {
286 dirstate_tuple_length, /* sq_length */
287 dirstate_tuple_length, /* sq_length */
287 0, /* sq_concat */
288 0, /* sq_concat */
288 0, /* sq_repeat */
289 0, /* sq_repeat */
289 dirstate_tuple_item, /* sq_item */
290 dirstate_tuple_item, /* sq_item */
290 0, /* sq_ass_item */
291 0, /* sq_ass_item */
291 0, /* sq_contains */
292 0, /* sq_contains */
292 0, /* sq_inplace_concat */
293 0, /* sq_inplace_concat */
293 0 /* sq_inplace_repeat */
294 0 /* sq_inplace_repeat */
294 };
295 };
295
296
296 PyTypeObject dirstateTupleType = {
297 PyTypeObject dirstateTupleType = {
297 PyVarObject_HEAD_INIT(NULL, 0)
298 PyVarObject_HEAD_INIT(NULL, 0)
298 "dirstate_tuple", /* tp_name */
299 "dirstate_tuple", /* tp_name */
299 sizeof(dirstateTupleObject),/* tp_basicsize */
300 sizeof(dirstateTupleObject),/* tp_basicsize */
300 0, /* tp_itemsize */
301 0, /* tp_itemsize */
301 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
302 (destructor)dirstate_tuple_dealloc, /* tp_dealloc */
302 0, /* tp_print */
303 0, /* tp_print */
303 0, /* tp_getattr */
304 0, /* tp_getattr */
304 0, /* tp_setattr */
305 0, /* tp_setattr */
305 0, /* tp_compare */
306 0, /* tp_compare */
306 0, /* tp_repr */
307 0, /* tp_repr */
307 0, /* tp_as_number */
308 0, /* tp_as_number */
308 &dirstate_tuple_sq, /* tp_as_sequence */
309 &dirstate_tuple_sq, /* tp_as_sequence */
309 0, /* tp_as_mapping */
310 0, /* tp_as_mapping */
310 0, /* tp_hash */
311 0, /* tp_hash */
311 0, /* tp_call */
312 0, /* tp_call */
312 0, /* tp_str */
313 0, /* tp_str */
313 0, /* tp_getattro */
314 0, /* tp_getattro */
314 0, /* tp_setattro */
315 0, /* tp_setattro */
315 0, /* tp_as_buffer */
316 0, /* tp_as_buffer */
316 Py_TPFLAGS_DEFAULT, /* tp_flags */
317 Py_TPFLAGS_DEFAULT, /* tp_flags */
317 "dirstate tuple", /* tp_doc */
318 "dirstate tuple", /* tp_doc */
318 0, /* tp_traverse */
319 0, /* tp_traverse */
319 0, /* tp_clear */
320 0, /* tp_clear */
320 0, /* tp_richcompare */
321 0, /* tp_richcompare */
321 0, /* tp_weaklistoffset */
322 0, /* tp_weaklistoffset */
322 0, /* tp_iter */
323 0, /* tp_iter */
323 0, /* tp_iternext */
324 0, /* tp_iternext */
324 0, /* tp_methods */
325 0, /* tp_methods */
325 0, /* tp_members */
326 0, /* tp_members */
326 0, /* tp_getset */
327 0, /* tp_getset */
327 0, /* tp_base */
328 0, /* tp_base */
328 0, /* tp_dict */
329 0, /* tp_dict */
329 0, /* tp_descr_get */
330 0, /* tp_descr_get */
330 0, /* tp_descr_set */
331 0, /* tp_descr_set */
331 0, /* tp_dictoffset */
332 0, /* tp_dictoffset */
332 0, /* tp_init */
333 0, /* tp_init */
333 0, /* tp_alloc */
334 0, /* tp_alloc */
334 dirstate_tuple_new, /* tp_new */
335 dirstate_tuple_new, /* tp_new */
335 };
336 };
336
337
337 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
338 static PyObject *parse_dirstate(PyObject *self, PyObject *args)
338 {
339 {
339 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
340 PyObject *dmap, *cmap, *parents = NULL, *ret = NULL;
340 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
341 PyObject *fname = NULL, *cname = NULL, *entry = NULL;
341 char state, *cur, *str, *cpos;
342 char state, *cur, *str, *cpos;
342 int mode, size, mtime;
343 int mode, size, mtime;
343 unsigned int flen, len, pos = 40;
344 unsigned int flen, len, pos = 40;
344 int readlen;
345 int readlen;
345
346
346 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
347 if (!PyArg_ParseTuple(args, "O!O!s#:parse_dirstate",
347 &PyDict_Type, &dmap,
348 &PyDict_Type, &dmap,
348 &PyDict_Type, &cmap,
349 &PyDict_Type, &cmap,
349 &str, &readlen))
350 &str, &readlen))
350 goto quit;
351 goto quit;
351
352
352 if (readlen < 0)
353 if (readlen < 0)
353 goto quit;
354 goto quit;
354
355
355 len = readlen;
356 len = readlen;
356
357
357 /* read parents */
358 /* read parents */
358 if (len < 40)
359 if (len < 40)
359 goto quit;
360 goto quit;
360
361
361 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
362 parents = Py_BuildValue("s#s#", str, 20, str + 20, 20);
362 if (!parents)
363 if (!parents)
363 goto quit;
364 goto quit;
364
365
365 /* read filenames */
366 /* read filenames */
366 while (pos >= 40 && pos < len) {
367 while (pos >= 40 && pos < len) {
367 cur = str + pos;
368 cur = str + pos;
368 /* unpack header */
369 /* unpack header */
369 state = *cur;
370 state = *cur;
370 mode = getbe32(cur + 1);
371 mode = getbe32(cur + 1);
371 size = getbe32(cur + 5);
372 size = getbe32(cur + 5);
372 mtime = getbe32(cur + 9);
373 mtime = getbe32(cur + 9);
373 flen = getbe32(cur + 13);
374 flen = getbe32(cur + 13);
374 pos += 17;
375 pos += 17;
375 cur += 17;
376 cur += 17;
376 if (flen > len - pos) {
377 if (flen > len - pos) {
377 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
378 PyErr_SetString(PyExc_ValueError, "overflow in dirstate");
378 goto quit;
379 goto quit;
379 }
380 }
380
381
381 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
382 entry = (PyObject *)make_dirstate_tuple(state, mode, size,
382 mtime);
383 mtime);
383 cpos = memchr(cur, 0, flen);
384 cpos = memchr(cur, 0, flen);
384 if (cpos) {
385 if (cpos) {
385 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
386 fname = PyBytes_FromStringAndSize(cur, cpos - cur);
386 cname = PyBytes_FromStringAndSize(cpos + 1,
387 cname = PyBytes_FromStringAndSize(cpos + 1,
387 flen - (cpos - cur) - 1);
388 flen - (cpos - cur) - 1);
388 if (!fname || !cname ||
389 if (!fname || !cname ||
389 PyDict_SetItem(cmap, fname, cname) == -1 ||
390 PyDict_SetItem(cmap, fname, cname) == -1 ||
390 PyDict_SetItem(dmap, fname, entry) == -1)
391 PyDict_SetItem(dmap, fname, entry) == -1)
391 goto quit;
392 goto quit;
392 Py_DECREF(cname);
393 Py_DECREF(cname);
393 } else {
394 } else {
394 fname = PyBytes_FromStringAndSize(cur, flen);
395 fname = PyBytes_FromStringAndSize(cur, flen);
395 if (!fname ||
396 if (!fname ||
396 PyDict_SetItem(dmap, fname, entry) == -1)
397 PyDict_SetItem(dmap, fname, entry) == -1)
397 goto quit;
398 goto quit;
398 }
399 }
399 Py_DECREF(fname);
400 Py_DECREF(fname);
400 Py_DECREF(entry);
401 Py_DECREF(entry);
401 fname = cname = entry = NULL;
402 fname = cname = entry = NULL;
402 pos += flen;
403 pos += flen;
403 }
404 }
404
405
405 ret = parents;
406 ret = parents;
406 Py_INCREF(ret);
407 Py_INCREF(ret);
407 quit:
408 quit:
408 Py_XDECREF(fname);
409 Py_XDECREF(fname);
409 Py_XDECREF(cname);
410 Py_XDECREF(cname);
410 Py_XDECREF(entry);
411 Py_XDECREF(entry);
411 Py_XDECREF(parents);
412 Py_XDECREF(parents);
412 return ret;
413 return ret;
413 }
414 }
414
415
415 /*
416 /*
416 * Efficiently pack a dirstate object into its on-disk format.
417 * Efficiently pack a dirstate object into its on-disk format.
417 */
418 */
418 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
419 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
419 {
420 {
420 PyObject *packobj = NULL;
421 PyObject *packobj = NULL;
421 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
422 PyObject *map, *copymap, *pl, *mtime_unset = NULL;
422 Py_ssize_t nbytes, pos, l;
423 Py_ssize_t nbytes, pos, l;
423 PyObject *k, *v = NULL, *pn;
424 PyObject *k, *v = NULL, *pn;
424 char *p, *s;
425 char *p, *s;
425 double now;
426 double now;
426
427
427 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
428 if (!PyArg_ParseTuple(args, "O!O!Od:pack_dirstate",
428 &PyDict_Type, &map, &PyDict_Type, &copymap,
429 &PyDict_Type, &map, &PyDict_Type, &copymap,
429 &pl, &now))
430 &pl, &now))
430 return NULL;
431 return NULL;
431
432
432 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
433 if (!PySequence_Check(pl) || PySequence_Size(pl) != 2) {
433 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
434 PyErr_SetString(PyExc_TypeError, "expected 2-element sequence");
434 return NULL;
435 return NULL;
435 }
436 }
436
437
437 /* Figure out how much we need to allocate. */
438 /* Figure out how much we need to allocate. */
438 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
439 for (nbytes = 40, pos = 0; PyDict_Next(map, &pos, &k, &v);) {
439 PyObject *c;
440 PyObject *c;
440 if (!PyString_Check(k)) {
441 if (!PyString_Check(k)) {
441 PyErr_SetString(PyExc_TypeError, "expected string key");
442 PyErr_SetString(PyExc_TypeError, "expected string key");
442 goto bail;
443 goto bail;
443 }
444 }
444 nbytes += PyString_GET_SIZE(k) + 17;
445 nbytes += PyString_GET_SIZE(k) + 17;
445 c = PyDict_GetItem(copymap, k);
446 c = PyDict_GetItem(copymap, k);
446 if (c) {
447 if (c) {
447 if (!PyString_Check(c)) {
448 if (!PyString_Check(c)) {
448 PyErr_SetString(PyExc_TypeError,
449 PyErr_SetString(PyExc_TypeError,
449 "expected string key");
450 "expected string key");
450 goto bail;
451 goto bail;
451 }
452 }
452 nbytes += PyString_GET_SIZE(c) + 1;
453 nbytes += PyString_GET_SIZE(c) + 1;
453 }
454 }
454 }
455 }
455
456
456 packobj = PyString_FromStringAndSize(NULL, nbytes);
457 packobj = PyString_FromStringAndSize(NULL, nbytes);
457 if (packobj == NULL)
458 if (packobj == NULL)
458 goto bail;
459 goto bail;
459
460
460 p = PyString_AS_STRING(packobj);
461 p = PyString_AS_STRING(packobj);
461
462
462 pn = PySequence_ITEM(pl, 0);
463 pn = PySequence_ITEM(pl, 0);
463 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
464 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
464 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
465 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
465 goto bail;
466 goto bail;
466 }
467 }
467 memcpy(p, s, l);
468 memcpy(p, s, l);
468 p += 20;
469 p += 20;
469 pn = PySequence_ITEM(pl, 1);
470 pn = PySequence_ITEM(pl, 1);
470 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
471 if (PyString_AsStringAndSize(pn, &s, &l) == -1 || l != 20) {
471 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
472 PyErr_SetString(PyExc_TypeError, "expected a 20-byte hash");
472 goto bail;
473 goto bail;
473 }
474 }
474 memcpy(p, s, l);
475 memcpy(p, s, l);
475 p += 20;
476 p += 20;
476
477
477 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
478 for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) {
478 dirstateTupleObject *tuple;
479 dirstateTupleObject *tuple;
479 char state;
480 char state;
480 uint32_t mode, size, mtime;
481 uint32_t mode, size, mtime;
481 Py_ssize_t len, l;
482 Py_ssize_t len, l;
482 PyObject *o;
483 PyObject *o;
483 char *t;
484 char *t;
484
485
485 if (!dirstate_tuple_check(v)) {
486 if (!dirstate_tuple_check(v)) {
486 PyErr_SetString(PyExc_TypeError,
487 PyErr_SetString(PyExc_TypeError,
487 "expected a dirstate tuple");
488 "expected a dirstate tuple");
488 goto bail;
489 goto bail;
489 }
490 }
490 tuple = (dirstateTupleObject *)v;
491 tuple = (dirstateTupleObject *)v;
491
492
492 state = tuple->state;
493 state = tuple->state;
493 mode = tuple->mode;
494 mode = tuple->mode;
494 size = tuple->size;
495 size = tuple->size;
495 mtime = tuple->mtime;
496 mtime = tuple->mtime;
496 if (state == 'n' && mtime == (uint32_t)now) {
497 if (state == 'n' && mtime == (uint32_t)now) {
497 /* See pure/parsers.py:pack_dirstate for why we do
498 /* See pure/parsers.py:pack_dirstate for why we do
498 * this. */
499 * this. */
499 mtime = -1;
500 mtime = -1;
500 mtime_unset = (PyObject *)make_dirstate_tuple(
501 mtime_unset = (PyObject *)make_dirstate_tuple(
501 state, mode, size, mtime);
502 state, mode, size, mtime);
502 if (!mtime_unset)
503 if (!mtime_unset)
503 goto bail;
504 goto bail;
504 if (PyDict_SetItem(map, k, mtime_unset) == -1)
505 if (PyDict_SetItem(map, k, mtime_unset) == -1)
505 goto bail;
506 goto bail;
506 Py_DECREF(mtime_unset);
507 Py_DECREF(mtime_unset);
507 mtime_unset = NULL;
508 mtime_unset = NULL;
508 }
509 }
509 *p++ = state;
510 *p++ = state;
510 putbe32(mode, p);
511 putbe32(mode, p);
511 putbe32(size, p + 4);
512 putbe32(size, p + 4);
512 putbe32(mtime, p + 8);
513 putbe32(mtime, p + 8);
513 t = p + 12;
514 t = p + 12;
514 p += 16;
515 p += 16;
515 len = PyString_GET_SIZE(k);
516 len = PyString_GET_SIZE(k);
516 memcpy(p, PyString_AS_STRING(k), len);
517 memcpy(p, PyString_AS_STRING(k), len);
517 p += len;
518 p += len;
518 o = PyDict_GetItem(copymap, k);
519 o = PyDict_GetItem(copymap, k);
519 if (o) {
520 if (o) {
520 *p++ = '\0';
521 *p++ = '\0';
521 l = PyString_GET_SIZE(o);
522 l = PyString_GET_SIZE(o);
522 memcpy(p, PyString_AS_STRING(o), l);
523 memcpy(p, PyString_AS_STRING(o), l);
523 p += l;
524 p += l;
524 len += l + 1;
525 len += l + 1;
525 }
526 }
526 putbe32((uint32_t)len, t);
527 putbe32((uint32_t)len, t);
527 }
528 }
528
529
529 pos = p - PyString_AS_STRING(packobj);
530 pos = p - PyString_AS_STRING(packobj);
530 if (pos != nbytes) {
531 if (pos != nbytes) {
531 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
532 PyErr_Format(PyExc_SystemError, "bad dirstate size: %ld != %ld",
532 (long)pos, (long)nbytes);
533 (long)pos, (long)nbytes);
533 goto bail;
534 goto bail;
534 }
535 }
535
536
536 return packobj;
537 return packobj;
537 bail:
538 bail:
538 Py_XDECREF(mtime_unset);
539 Py_XDECREF(mtime_unset);
539 Py_XDECREF(packobj);
540 Py_XDECREF(packobj);
540 Py_XDECREF(v);
541 Py_XDECREF(v);
541 return NULL;
542 return NULL;
542 }
543 }
543
544
544 /*
545 /*
545 * A base-16 trie for fast node->rev mapping.
546 * A base-16 trie for fast node->rev mapping.
546 *
547 *
547 * Positive value is index of the next node in the trie
548 * Positive value is index of the next node in the trie
548 * Negative value is a leaf: -(rev + 1)
549 * Negative value is a leaf: -(rev + 1)
549 * Zero is empty
550 * Zero is empty
550 */
551 */
551 typedef struct {
552 typedef struct {
552 int children[16];
553 int children[16];
553 } nodetree;
554 } nodetree;
554
555
555 /*
556 /*
556 * This class has two behaviours.
557 * This class has two behaviours.
557 *
558 *
558 * When used in a list-like way (with integer keys), we decode an
559 * When used in a list-like way (with integer keys), we decode an
559 * entry in a RevlogNG index file on demand. Our last entry is a
560 * entry in a RevlogNG index file on demand. Our last entry is a
560 * sentinel, always a nullid. We have limited support for
561 * sentinel, always a nullid. We have limited support for
561 * integer-keyed insert and delete, only at elements right before the
562 * integer-keyed insert and delete, only at elements right before the
562 * sentinel.
563 * sentinel.
563 *
564 *
564 * With string keys, we lazily perform a reverse mapping from node to
565 * With string keys, we lazily perform a reverse mapping from node to
565 * rev, using a base-16 trie.
566 * rev, using a base-16 trie.
566 */
567 */
567 typedef struct {
568 typedef struct {
568 PyObject_HEAD
569 PyObject_HEAD
569 /* Type-specific fields go here. */
570 /* Type-specific fields go here. */
570 PyObject *data; /* raw bytes of index */
571 PyObject *data; /* raw bytes of index */
571 PyObject **cache; /* cached tuples */
572 PyObject **cache; /* cached tuples */
572 const char **offsets; /* populated on demand */
573 const char **offsets; /* populated on demand */
573 Py_ssize_t raw_length; /* original number of elements */
574 Py_ssize_t raw_length; /* original number of elements */
574 Py_ssize_t length; /* current number of elements */
575 Py_ssize_t length; /* current number of elements */
575 PyObject *added; /* populated on demand */
576 PyObject *added; /* populated on demand */
576 PyObject *headrevs; /* cache, invalidated on changes */
577 PyObject *headrevs; /* cache, invalidated on changes */
577 PyObject *filteredrevs;/* filtered revs set */
578 PyObject *filteredrevs;/* filtered revs set */
578 nodetree *nt; /* base-16 trie */
579 nodetree *nt; /* base-16 trie */
579 int ntlength; /* # nodes in use */
580 int ntlength; /* # nodes in use */
580 int ntcapacity; /* # nodes allocated */
581 int ntcapacity; /* # nodes allocated */
581 int ntdepth; /* maximum depth of tree */
582 int ntdepth; /* maximum depth of tree */
582 int ntsplits; /* # splits performed */
583 int ntsplits; /* # splits performed */
583 int ntrev; /* last rev scanned */
584 int ntrev; /* last rev scanned */
584 int ntlookups; /* # lookups */
585 int ntlookups; /* # lookups */
585 int ntmisses; /* # lookups that miss the cache */
586 int ntmisses; /* # lookups that miss the cache */
586 int inlined;
587 int inlined;
587 } indexObject;
588 } indexObject;
588
589
589 static Py_ssize_t index_length(const indexObject *self)
590 static Py_ssize_t index_length(const indexObject *self)
590 {
591 {
591 if (self->added == NULL)
592 if (self->added == NULL)
592 return self->length;
593 return self->length;
593 return self->length + PyList_GET_SIZE(self->added);
594 return self->length + PyList_GET_SIZE(self->added);
594 }
595 }
595
596
596 static PyObject *nullentry;
597 static PyObject *nullentry;
597 static const char nullid[20];
598 static const char nullid[20];
598
599
599 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
600 static Py_ssize_t inline_scan(indexObject *self, const char **offsets);
600
601
601 #if LONG_MAX == 0x7fffffffL
602 #if LONG_MAX == 0x7fffffffL
602 static char *tuple_format = "Kiiiiiis#";
603 static char *tuple_format = "Kiiiiiis#";
603 #else
604 #else
604 static char *tuple_format = "kiiiiiis#";
605 static char *tuple_format = "kiiiiiis#";
605 #endif
606 #endif
606
607
607 /* A RevlogNG v1 index entry is 64 bytes long. */
608 /* A RevlogNG v1 index entry is 64 bytes long. */
608 static const long v1_hdrsize = 64;
609 static const long v1_hdrsize = 64;
609
610
610 /*
611 /*
611 * Return a pointer to the beginning of a RevlogNG record.
612 * Return a pointer to the beginning of a RevlogNG record.
612 */
613 */
613 static const char *index_deref(indexObject *self, Py_ssize_t pos)
614 static const char *index_deref(indexObject *self, Py_ssize_t pos)
614 {
615 {
615 if (self->inlined && pos > 0) {
616 if (self->inlined && pos > 0) {
616 if (self->offsets == NULL) {
617 if (self->offsets == NULL) {
617 self->offsets = malloc(self->raw_length *
618 self->offsets = malloc(self->raw_length *
618 sizeof(*self->offsets));
619 sizeof(*self->offsets));
619 if (self->offsets == NULL)
620 if (self->offsets == NULL)
620 return (const char *)PyErr_NoMemory();
621 return (const char *)PyErr_NoMemory();
621 inline_scan(self, self->offsets);
622 inline_scan(self, self->offsets);
622 }
623 }
623 return self->offsets[pos];
624 return self->offsets[pos];
624 }
625 }
625
626
626 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
627 return PyString_AS_STRING(self->data) + pos * v1_hdrsize;
627 }
628 }
628
629
629 /*
630 /*
630 * RevlogNG format (all in big endian, data may be inlined):
631 * RevlogNG format (all in big endian, data may be inlined):
631 * 6 bytes: offset
632 * 6 bytes: offset
632 * 2 bytes: flags
633 * 2 bytes: flags
633 * 4 bytes: compressed length
634 * 4 bytes: compressed length
634 * 4 bytes: uncompressed length
635 * 4 bytes: uncompressed length
635 * 4 bytes: base revision
636 * 4 bytes: base revision
636 * 4 bytes: link revision
637 * 4 bytes: link revision
637 * 4 bytes: parent 1 revision
638 * 4 bytes: parent 1 revision
638 * 4 bytes: parent 2 revision
639 * 4 bytes: parent 2 revision
639 * 32 bytes: nodeid (only 20 bytes used)
640 * 32 bytes: nodeid (only 20 bytes used)
640 */
641 */
641 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
642 static PyObject *index_get(indexObject *self, Py_ssize_t pos)
642 {
643 {
643 uint64_t offset_flags;
644 uint64_t offset_flags;
644 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
645 int comp_len, uncomp_len, base_rev, link_rev, parent_1, parent_2;
645 const char *c_node_id;
646 const char *c_node_id;
646 const char *data;
647 const char *data;
647 Py_ssize_t length = index_length(self);
648 Py_ssize_t length = index_length(self);
648 PyObject *entry;
649 PyObject *entry;
649
650
650 if (pos < 0)
651 if (pos < 0)
651 pos += length;
652 pos += length;
652
653
653 if (pos < 0 || pos >= length) {
654 if (pos < 0 || pos >= length) {
654 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
655 PyErr_SetString(PyExc_IndexError, "revlog index out of range");
655 return NULL;
656 return NULL;
656 }
657 }
657
658
658 if (pos == length - 1) {
659 if (pos == length - 1) {
659 Py_INCREF(nullentry);
660 Py_INCREF(nullentry);
660 return nullentry;
661 return nullentry;
661 }
662 }
662
663
663 if (pos >= self->length - 1) {
664 if (pos >= self->length - 1) {
664 PyObject *obj;
665 PyObject *obj;
665 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
666 obj = PyList_GET_ITEM(self->added, pos - self->length + 1);
666 Py_INCREF(obj);
667 Py_INCREF(obj);
667 return obj;
668 return obj;
668 }
669 }
669
670
670 if (self->cache) {
671 if (self->cache) {
671 if (self->cache[pos]) {
672 if (self->cache[pos]) {
672 Py_INCREF(self->cache[pos]);
673 Py_INCREF(self->cache[pos]);
673 return self->cache[pos];
674 return self->cache[pos];
674 }
675 }
675 } else {
676 } else {
676 self->cache = calloc(self->raw_length, sizeof(PyObject *));
677 self->cache = calloc(self->raw_length, sizeof(PyObject *));
677 if (self->cache == NULL)
678 if (self->cache == NULL)
678 return PyErr_NoMemory();
679 return PyErr_NoMemory();
679 }
680 }
680
681
681 data = index_deref(self, pos);
682 data = index_deref(self, pos);
682 if (data == NULL)
683 if (data == NULL)
683 return NULL;
684 return NULL;
684
685
685 offset_flags = getbe32(data + 4);
686 offset_flags = getbe32(data + 4);
686 if (pos == 0) /* mask out version number for the first entry */
687 if (pos == 0) /* mask out version number for the first entry */
687 offset_flags &= 0xFFFF;
688 offset_flags &= 0xFFFF;
688 else {
689 else {
689 uint32_t offset_high = getbe32(data);
690 uint32_t offset_high = getbe32(data);
690 offset_flags |= ((uint64_t)offset_high) << 32;
691 offset_flags |= ((uint64_t)offset_high) << 32;
691 }
692 }
692
693
693 comp_len = getbe32(data + 8);
694 comp_len = getbe32(data + 8);
694 uncomp_len = getbe32(data + 12);
695 uncomp_len = getbe32(data + 12);
695 base_rev = getbe32(data + 16);
696 base_rev = getbe32(data + 16);
696 link_rev = getbe32(data + 20);
697 link_rev = getbe32(data + 20);
697 parent_1 = getbe32(data + 24);
698 parent_1 = getbe32(data + 24);
698 parent_2 = getbe32(data + 28);
699 parent_2 = getbe32(data + 28);
699 c_node_id = data + 32;
700 c_node_id = data + 32;
700
701
701 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
702 entry = Py_BuildValue(tuple_format, offset_flags, comp_len,
702 uncomp_len, base_rev, link_rev,
703 uncomp_len, base_rev, link_rev,
703 parent_1, parent_2, c_node_id, 20);
704 parent_1, parent_2, c_node_id, 20);
704
705
705 if (entry) {
706 if (entry) {
706 PyObject_GC_UnTrack(entry);
707 PyObject_GC_UnTrack(entry);
707 Py_INCREF(entry);
708 Py_INCREF(entry);
708 }
709 }
709
710
710 self->cache[pos] = entry;
711 self->cache[pos] = entry;
711
712
712 return entry;
713 return entry;
713 }
714 }
714
715
715 /*
716 /*
716 * Return the 20-byte SHA of the node corresponding to the given rev.
717 * Return the 20-byte SHA of the node corresponding to the given rev.
717 */
718 */
718 static const char *index_node(indexObject *self, Py_ssize_t pos)
719 static const char *index_node(indexObject *self, Py_ssize_t pos)
719 {
720 {
720 Py_ssize_t length = index_length(self);
721 Py_ssize_t length = index_length(self);
721 const char *data;
722 const char *data;
722
723
723 if (pos == length - 1 || pos == INT_MAX)
724 if (pos == length - 1 || pos == INT_MAX)
724 return nullid;
725 return nullid;
725
726
726 if (pos >= length)
727 if (pos >= length)
727 return NULL;
728 return NULL;
728
729
729 if (pos >= self->length - 1) {
730 if (pos >= self->length - 1) {
730 PyObject *tuple, *str;
731 PyObject *tuple, *str;
731 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
732 tuple = PyList_GET_ITEM(self->added, pos - self->length + 1);
732 str = PyTuple_GetItem(tuple, 7);
733 str = PyTuple_GetItem(tuple, 7);
733 return str ? PyString_AS_STRING(str) : NULL;
734 return str ? PyString_AS_STRING(str) : NULL;
734 }
735 }
735
736
736 data = index_deref(self, pos);
737 data = index_deref(self, pos);
737 return data ? data + 32 : NULL;
738 return data ? data + 32 : NULL;
738 }
739 }
739
740
740 static int nt_insert(indexObject *self, const char *node, int rev);
741 static int nt_insert(indexObject *self, const char *node, int rev);
741
742
742 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
743 static int node_check(PyObject *obj, char **node, Py_ssize_t *nodelen)
743 {
744 {
744 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
745 if (PyString_AsStringAndSize(obj, node, nodelen) == -1)
745 return -1;
746 return -1;
746 if (*nodelen == 20)
747 if (*nodelen == 20)
747 return 0;
748 return 0;
748 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
749 PyErr_SetString(PyExc_ValueError, "20-byte hash required");
749 return -1;
750 return -1;
750 }
751 }
751
752
752 static PyObject *index_insert(indexObject *self, PyObject *args)
753 static PyObject *index_insert(indexObject *self, PyObject *args)
753 {
754 {
754 PyObject *obj;
755 PyObject *obj;
755 char *node;
756 char *node;
756 int index;
757 int index;
757 Py_ssize_t len, nodelen;
758 Py_ssize_t len, nodelen;
758
759
759 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
760 if (!PyArg_ParseTuple(args, "iO", &index, &obj))
760 return NULL;
761 return NULL;
761
762
762 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
763 if (!PyTuple_Check(obj) || PyTuple_GET_SIZE(obj) != 8) {
763 PyErr_SetString(PyExc_TypeError, "8-tuple required");
764 PyErr_SetString(PyExc_TypeError, "8-tuple required");
764 return NULL;
765 return NULL;
765 }
766 }
766
767
767 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
768 if (node_check(PyTuple_GET_ITEM(obj, 7), &node, &nodelen) == -1)
768 return NULL;
769 return NULL;
769
770
770 len = index_length(self);
771 len = index_length(self);
771
772
772 if (index < 0)
773 if (index < 0)
773 index += len;
774 index += len;
774
775
775 if (index != len - 1) {
776 if (index != len - 1) {
776 PyErr_SetString(PyExc_IndexError,
777 PyErr_SetString(PyExc_IndexError,
777 "insert only supported at index -1");
778 "insert only supported at index -1");
778 return NULL;
779 return NULL;
779 }
780 }
780
781
781 if (self->added == NULL) {
782 if (self->added == NULL) {
782 self->added = PyList_New(0);
783 self->added = PyList_New(0);
783 if (self->added == NULL)
784 if (self->added == NULL)
784 return NULL;
785 return NULL;
785 }
786 }
786
787
787 if (PyList_Append(self->added, obj) == -1)
788 if (PyList_Append(self->added, obj) == -1)
788 return NULL;
789 return NULL;
789
790
790 if (self->nt)
791 if (self->nt)
791 nt_insert(self, node, index);
792 nt_insert(self, node, index);
792
793
793 Py_CLEAR(self->headrevs);
794 Py_CLEAR(self->headrevs);
794 Py_RETURN_NONE;
795 Py_RETURN_NONE;
795 }
796 }
796
797
797 static void _index_clearcaches(indexObject *self)
798 static void _index_clearcaches(indexObject *self)
798 {
799 {
799 if (self->cache) {
800 if (self->cache) {
800 Py_ssize_t i;
801 Py_ssize_t i;
801
802
802 for (i = 0; i < self->raw_length; i++)
803 for (i = 0; i < self->raw_length; i++)
803 Py_CLEAR(self->cache[i]);
804 Py_CLEAR(self->cache[i]);
804 free(self->cache);
805 free(self->cache);
805 self->cache = NULL;
806 self->cache = NULL;
806 }
807 }
807 if (self->offsets) {
808 if (self->offsets) {
808 free(self->offsets);
809 free(self->offsets);
809 self->offsets = NULL;
810 self->offsets = NULL;
810 }
811 }
811 if (self->nt) {
812 if (self->nt) {
812 free(self->nt);
813 free(self->nt);
813 self->nt = NULL;
814 self->nt = NULL;
814 }
815 }
815 Py_CLEAR(self->headrevs);
816 Py_CLEAR(self->headrevs);
816 }
817 }
817
818
818 static PyObject *index_clearcaches(indexObject *self)
819 static PyObject *index_clearcaches(indexObject *self)
819 {
820 {
820 _index_clearcaches(self);
821 _index_clearcaches(self);
821 self->ntlength = self->ntcapacity = 0;
822 self->ntlength = self->ntcapacity = 0;
822 self->ntdepth = self->ntsplits = 0;
823 self->ntdepth = self->ntsplits = 0;
823 self->ntrev = -1;
824 self->ntrev = -1;
824 self->ntlookups = self->ntmisses = 0;
825 self->ntlookups = self->ntmisses = 0;
825 Py_RETURN_NONE;
826 Py_RETURN_NONE;
826 }
827 }
827
828
828 static PyObject *index_stats(indexObject *self)
829 static PyObject *index_stats(indexObject *self)
829 {
830 {
830 PyObject *obj = PyDict_New();
831 PyObject *obj = PyDict_New();
831 PyObject *t = NULL;
832 PyObject *t = NULL;
832
833
833 if (obj == NULL)
834 if (obj == NULL)
834 return NULL;
835 return NULL;
835
836
836 #define istat(__n, __d) \
837 #define istat(__n, __d) \
837 t = PyInt_FromSsize_t(self->__n); \
838 t = PyInt_FromSsize_t(self->__n); \
838 if (!t) \
839 if (!t) \
839 goto bail; \
840 goto bail; \
840 if (PyDict_SetItemString(obj, __d, t) == -1) \
841 if (PyDict_SetItemString(obj, __d, t) == -1) \
841 goto bail; \
842 goto bail; \
842 Py_DECREF(t);
843 Py_DECREF(t);
843
844
844 if (self->added) {
845 if (self->added) {
845 Py_ssize_t len = PyList_GET_SIZE(self->added);
846 Py_ssize_t len = PyList_GET_SIZE(self->added);
846 t = PyInt_FromSsize_t(len);
847 t = PyInt_FromSsize_t(len);
847 if (!t)
848 if (!t)
848 goto bail;
849 goto bail;
849 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
850 if (PyDict_SetItemString(obj, "index entries added", t) == -1)
850 goto bail;
851 goto bail;
851 Py_DECREF(t);
852 Py_DECREF(t);
852 }
853 }
853
854
854 if (self->raw_length != self->length - 1)
855 if (self->raw_length != self->length - 1)
855 istat(raw_length, "revs on disk");
856 istat(raw_length, "revs on disk");
856 istat(length, "revs in memory");
857 istat(length, "revs in memory");
857 istat(ntcapacity, "node trie capacity");
858 istat(ntcapacity, "node trie capacity");
858 istat(ntdepth, "node trie depth");
859 istat(ntdepth, "node trie depth");
859 istat(ntlength, "node trie count");
860 istat(ntlength, "node trie count");
860 istat(ntlookups, "node trie lookups");
861 istat(ntlookups, "node trie lookups");
861 istat(ntmisses, "node trie misses");
862 istat(ntmisses, "node trie misses");
862 istat(ntrev, "node trie last rev scanned");
863 istat(ntrev, "node trie last rev scanned");
863 istat(ntsplits, "node trie splits");
864 istat(ntsplits, "node trie splits");
864
865
865 #undef istat
866 #undef istat
866
867
867 return obj;
868 return obj;
868
869
869 bail:
870 bail:
870 Py_XDECREF(obj);
871 Py_XDECREF(obj);
871 Py_XDECREF(t);
872 Py_XDECREF(t);
872 return NULL;
873 return NULL;
873 }
874 }
874
875
875 /*
876 /*
876 * When we cache a list, we want to be sure the caller can't mutate
877 * When we cache a list, we want to be sure the caller can't mutate
877 * the cached copy.
878 * the cached copy.
878 */
879 */
879 static PyObject *list_copy(PyObject *list)
880 static PyObject *list_copy(PyObject *list)
880 {
881 {
881 Py_ssize_t len = PyList_GET_SIZE(list);
882 Py_ssize_t len = PyList_GET_SIZE(list);
882 PyObject *newlist = PyList_New(len);
883 PyObject *newlist = PyList_New(len);
883 Py_ssize_t i;
884 Py_ssize_t i;
884
885
885 if (newlist == NULL)
886 if (newlist == NULL)
886 return NULL;
887 return NULL;
887
888
888 for (i = 0; i < len; i++) {
889 for (i = 0; i < len; i++) {
889 PyObject *obj = PyList_GET_ITEM(list, i);
890 PyObject *obj = PyList_GET_ITEM(list, i);
890 Py_INCREF(obj);
891 Py_INCREF(obj);
891 PyList_SET_ITEM(newlist, i, obj);
892 PyList_SET_ITEM(newlist, i, obj);
892 }
893 }
893
894
894 return newlist;
895 return newlist;
895 }
896 }
896
897
897 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
898 /* arg should be Py_ssize_t but Python 2.4 do not support the n format */
898 static int check_filter(PyObject *filter, unsigned long arg) {
899 static int check_filter(PyObject *filter, unsigned long arg) {
899 if (filter) {
900 if (filter) {
900 PyObject *arglist, *result;
901 PyObject *arglist, *result;
901 int isfiltered;
902 int isfiltered;
902
903
903 arglist = Py_BuildValue("(k)", arg);
904 arglist = Py_BuildValue("(k)", arg);
904 if (!arglist) {
905 if (!arglist) {
905 return -1;
906 return -1;
906 }
907 }
907
908
908 result = PyEval_CallObject(filter, arglist);
909 result = PyEval_CallObject(filter, arglist);
909 Py_DECREF(arglist);
910 Py_DECREF(arglist);
910 if (!result) {
911 if (!result) {
911 return -1;
912 return -1;
912 }
913 }
913
914
914 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
915 /* PyObject_IsTrue returns 1 if true, 0 if false, -1 if error,
915 * same as this function, so we can just return it directly.*/
916 * same as this function, so we can just return it directly.*/
916 isfiltered = PyObject_IsTrue(result);
917 isfiltered = PyObject_IsTrue(result);
917 Py_DECREF(result);
918 Py_DECREF(result);
918 return isfiltered;
919 return isfiltered;
919 } else {
920 } else {
920 return 0;
921 return 0;
921 }
922 }
922 }
923 }
923
924
924 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
925 static Py_ssize_t add_roots_get_min(indexObject *self, PyObject *list,
925 Py_ssize_t marker, char *phases)
926 Py_ssize_t marker, char *phases)
926 {
927 {
927 PyObject *iter = NULL;
928 PyObject *iter = NULL;
928 PyObject *iter_item = NULL;
929 PyObject *iter_item = NULL;
929 Py_ssize_t min_idx = index_length(self) + 1;
930 Py_ssize_t min_idx = index_length(self) + 1;
930 long iter_item_long;
931 long iter_item_long;
931
932
932 if (PyList_GET_SIZE(list) != 0) {
933 if (PyList_GET_SIZE(list) != 0) {
933 iter = PyObject_GetIter(list);
934 iter = PyObject_GetIter(list);
934 if (iter == NULL)
935 if (iter == NULL)
935 return -2;
936 return -2;
936 while ((iter_item = PyIter_Next(iter)))
937 while ((iter_item = PyIter_Next(iter)))
937 {
938 {
938 iter_item_long = PyInt_AS_LONG(iter_item);
939 iter_item_long = PyInt_AS_LONG(iter_item);
939 Py_DECREF(iter_item);
940 Py_DECREF(iter_item);
940 if (iter_item_long < min_idx)
941 if (iter_item_long < min_idx)
941 min_idx = iter_item_long;
942 min_idx = iter_item_long;
942 phases[iter_item_long] = marker;
943 phases[iter_item_long] = marker;
943 }
944 }
944 Py_DECREF(iter);
945 Py_DECREF(iter);
945 }
946 }
946
947
947 return min_idx;
948 return min_idx;
948 }
949 }
949
950
950 static inline void set_phase_from_parents(char *phases, int parent_1,
951 static inline void set_phase_from_parents(char *phases, int parent_1,
951 int parent_2, Py_ssize_t i)
952 int parent_2, Py_ssize_t i)
952 {
953 {
953 if (parent_1 >= 0 && phases[parent_1] > phases[i])
954 if (parent_1 >= 0 && phases[parent_1] > phases[i])
954 phases[i] = phases[parent_1];
955 phases[i] = phases[parent_1];
955 if (parent_2 >= 0 && phases[parent_2] > phases[i])
956 if (parent_2 >= 0 && phases[parent_2] > phases[i])
956 phases[i] = phases[parent_2];
957 phases[i] = phases[parent_2];
957 }
958 }
958
959
959 static PyObject *compute_phases(indexObject *self, PyObject *args)
960 static PyObject *compute_phases(indexObject *self, PyObject *args)
960 {
961 {
961 PyObject *roots = Py_None;
962 PyObject *roots = Py_None;
962 PyObject *phaseslist = NULL;
963 PyObject *phaseslist = NULL;
963 PyObject *phaseroots = NULL;
964 PyObject *phaseroots = NULL;
964 PyObject *rev = NULL;
965 PyObject *rev = NULL;
965 PyObject *p1 = NULL;
966 PyObject *p1 = NULL;
966 PyObject *p2 = NULL;
967 PyObject *p2 = NULL;
967 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
968 Py_ssize_t addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
968 Py_ssize_t len = index_length(self) - 1;
969 Py_ssize_t len = index_length(self) - 1;
969 Py_ssize_t numphase = 0;
970 Py_ssize_t numphase = 0;
970 Py_ssize_t minrevallphases = 0;
971 Py_ssize_t minrevallphases = 0;
971 Py_ssize_t minrevphase = 0;
972 Py_ssize_t minrevphase = 0;
972 Py_ssize_t i = 0;
973 Py_ssize_t i = 0;
973 int parent_1, parent_2;
974 int parent_1, parent_2;
974 char *phases = NULL;
975 char *phases = NULL;
975 const char *data;
976 const char *data;
976
977
977 if (!PyArg_ParseTuple(args, "O", &roots))
978 if (!PyArg_ParseTuple(args, "O", &roots))
978 goto release_none;
979 goto release_none;
979 if (roots == NULL || !PyList_Check(roots))
980 if (roots == NULL || !PyList_Check(roots))
980 goto release_none;
981 goto release_none;
981
982
982 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
983 phases = calloc(len, 1); /* phase per rev: {0: public, 1: draft, 2: secret} */
983 if (phases == NULL)
984 if (phases == NULL)
984 goto release_none;
985 goto release_none;
985 /* Put the phase information of all the roots in phases */
986 /* Put the phase information of all the roots in phases */
986 numphase = PyList_GET_SIZE(roots)+1;
987 numphase = PyList_GET_SIZE(roots)+1;
987 minrevallphases = len + 1;
988 minrevallphases = len + 1;
988 for (i = 0; i < numphase-1; i++) {
989 for (i = 0; i < numphase-1; i++) {
989 phaseroots = PyList_GET_ITEM(roots, i);
990 phaseroots = PyList_GET_ITEM(roots, i);
990 if (!PyList_Check(phaseroots))
991 if (!PyList_Check(phaseroots))
991 goto release_phases;
992 goto release_phases;
992 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
993 minrevphase = add_roots_get_min(self, phaseroots, i+1, phases);
993 if (minrevphase == -2) /* Error from add_roots_get_min */
994 if (minrevphase == -2) /* Error from add_roots_get_min */
994 goto release_phases;
995 goto release_phases;
995 minrevallphases = MIN(minrevallphases, minrevphase);
996 minrevallphases = MIN(minrevallphases, minrevphase);
996 }
997 }
997 /* Propagate the phase information from the roots to the revs */
998 /* Propagate the phase information from the roots to the revs */
998 if (minrevallphases != -1) {
999 if (minrevallphases != -1) {
999 for (i = minrevallphases; i < self->raw_length; i++) {
1000 for (i = minrevallphases; i < self->raw_length; i++) {
1000 data = index_deref(self, i);
1001 data = index_deref(self, i);
1001 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1002 set_phase_from_parents(phases, getbe32(data+24), getbe32(data+28), i);
1002 }
1003 }
1003 for (i = 0; i < addlen; i++) {
1004 for (i = 0; i < addlen; i++) {
1004 rev = PyList_GET_ITEM(self->added, i);
1005 rev = PyList_GET_ITEM(self->added, i);
1005 p1 = PyTuple_GET_ITEM(rev, 5);
1006 p1 = PyTuple_GET_ITEM(rev, 5);
1006 p2 = PyTuple_GET_ITEM(rev, 6);
1007 p2 = PyTuple_GET_ITEM(rev, 6);
1007 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1008 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1008 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1009 PyErr_SetString(PyExc_TypeError, "revlog parents are invalid");
1009 goto release_phases;
1010 goto release_phases;
1010 }
1011 }
1011 parent_1 = (int)PyInt_AS_LONG(p1);
1012 parent_1 = (int)PyInt_AS_LONG(p1);
1012 parent_2 = (int)PyInt_AS_LONG(p2);
1013 parent_2 = (int)PyInt_AS_LONG(p2);
1013 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1014 set_phase_from_parents(phases, parent_1, parent_2, i+self->raw_length);
1014 }
1015 }
1015 }
1016 }
1016 /* Transform phase list to a python list */
1017 /* Transform phase list to a python list */
1017 phaseslist = PyList_New(len);
1018 phaseslist = PyList_New(len);
1018 if (phaseslist == NULL)
1019 if (phaseslist == NULL)
1019 goto release_phases;
1020 goto release_phases;
1020 for (i = 0; i < len; i++)
1021 for (i = 0; i < len; i++)
1021 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
1022 PyList_SET_ITEM(phaseslist, i, PyInt_FromLong(phases[i]));
1022
1023
1023 release_phases:
1024 release_phases:
1024 free(phases);
1025 free(phases);
1025 release_none:
1026 release_none:
1026 return phaseslist;
1027 return phaseslist;
1027 }
1028 }
1028
1029
1029 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1030 static PyObject *index_headrevs(indexObject *self, PyObject *args)
1030 {
1031 {
1031 Py_ssize_t i, len, addlen;
1032 Py_ssize_t i, len, addlen;
1032 char *nothead = NULL;
1033 char *nothead = NULL;
1033 PyObject *heads = NULL;
1034 PyObject *heads = NULL;
1034 PyObject *filter = NULL;
1035 PyObject *filter = NULL;
1035 PyObject *filteredrevs = Py_None;
1036 PyObject *filteredrevs = Py_None;
1036
1037
1037 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1038 if (!PyArg_ParseTuple(args, "|O", &filteredrevs)) {
1038 return NULL;
1039 return NULL;
1039 }
1040 }
1040
1041
1041 if (self->headrevs && filteredrevs == self->filteredrevs)
1042 if (self->headrevs && filteredrevs == self->filteredrevs)
1042 return list_copy(self->headrevs);
1043 return list_copy(self->headrevs);
1043
1044
1044 Py_DECREF(self->filteredrevs);
1045 Py_DECREF(self->filteredrevs);
1045 self->filteredrevs = filteredrevs;
1046 self->filteredrevs = filteredrevs;
1046 Py_INCREF(filteredrevs);
1047 Py_INCREF(filteredrevs);
1047
1048
1048 if (filteredrevs != Py_None) {
1049 if (filteredrevs != Py_None) {
1049 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1050 filter = PyObject_GetAttrString(filteredrevs, "__contains__");
1050 if (!filter) {
1051 if (!filter) {
1051 PyErr_SetString(PyExc_TypeError,
1052 PyErr_SetString(PyExc_TypeError,
1052 "filteredrevs has no attribute __contains__");
1053 "filteredrevs has no attribute __contains__");
1053 goto bail;
1054 goto bail;
1054 }
1055 }
1055 }
1056 }
1056
1057
1057 len = index_length(self) - 1;
1058 len = index_length(self) - 1;
1058 heads = PyList_New(0);
1059 heads = PyList_New(0);
1059 if (heads == NULL)
1060 if (heads == NULL)
1060 goto bail;
1061 goto bail;
1061 if (len == 0) {
1062 if (len == 0) {
1062 PyObject *nullid = PyInt_FromLong(-1);
1063 PyObject *nullid = PyInt_FromLong(-1);
1063 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1064 if (nullid == NULL || PyList_Append(heads, nullid) == -1) {
1064 Py_XDECREF(nullid);
1065 Py_XDECREF(nullid);
1065 goto bail;
1066 goto bail;
1066 }
1067 }
1067 goto done;
1068 goto done;
1068 }
1069 }
1069
1070
1070 nothead = calloc(len, 1);
1071 nothead = calloc(len, 1);
1071 if (nothead == NULL)
1072 if (nothead == NULL)
1072 goto bail;
1073 goto bail;
1073
1074
1074 for (i = 0; i < self->raw_length; i++) {
1075 for (i = 0; i < self->raw_length; i++) {
1075 const char *data;
1076 const char *data;
1076 int parent_1, parent_2, isfiltered;
1077 int parent_1, parent_2, isfiltered;
1077
1078
1078 isfiltered = check_filter(filter, i);
1079 isfiltered = check_filter(filter, i);
1079 if (isfiltered == -1) {
1080 if (isfiltered == -1) {
1080 PyErr_SetString(PyExc_TypeError,
1081 PyErr_SetString(PyExc_TypeError,
1081 "unable to check filter");
1082 "unable to check filter");
1082 goto bail;
1083 goto bail;
1083 }
1084 }
1084
1085
1085 if (isfiltered) {
1086 if (isfiltered) {
1086 nothead[i] = 1;
1087 nothead[i] = 1;
1087 continue;
1088 continue;
1088 }
1089 }
1089
1090
1090 data = index_deref(self, i);
1091 data = index_deref(self, i);
1091 parent_1 = getbe32(data + 24);
1092 parent_1 = getbe32(data + 24);
1092 parent_2 = getbe32(data + 28);
1093 parent_2 = getbe32(data + 28);
1093
1094
1094 if (parent_1 >= 0)
1095 if (parent_1 >= 0)
1095 nothead[parent_1] = 1;
1096 nothead[parent_1] = 1;
1096 if (parent_2 >= 0)
1097 if (parent_2 >= 0)
1097 nothead[parent_2] = 1;
1098 nothead[parent_2] = 1;
1098 }
1099 }
1099
1100
1100 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1101 addlen = self->added ? PyList_GET_SIZE(self->added) : 0;
1101
1102
1102 for (i = 0; i < addlen; i++) {
1103 for (i = 0; i < addlen; i++) {
1103 PyObject *rev = PyList_GET_ITEM(self->added, i);
1104 PyObject *rev = PyList_GET_ITEM(self->added, i);
1104 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1105 PyObject *p1 = PyTuple_GET_ITEM(rev, 5);
1105 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1106 PyObject *p2 = PyTuple_GET_ITEM(rev, 6);
1106 long parent_1, parent_2;
1107 long parent_1, parent_2;
1107 int isfiltered;
1108 int isfiltered;
1108
1109
1109 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1110 if (!PyInt_Check(p1) || !PyInt_Check(p2)) {
1110 PyErr_SetString(PyExc_TypeError,
1111 PyErr_SetString(PyExc_TypeError,
1111 "revlog parents are invalid");
1112 "revlog parents are invalid");
1112 goto bail;
1113 goto bail;
1113 }
1114 }
1114
1115
1115 isfiltered = check_filter(filter, i);
1116 isfiltered = check_filter(filter, i);
1116 if (isfiltered == -1) {
1117 if (isfiltered == -1) {
1117 PyErr_SetString(PyExc_TypeError,
1118 PyErr_SetString(PyExc_TypeError,
1118 "unable to check filter");
1119 "unable to check filter");
1119 goto bail;
1120 goto bail;
1120 }
1121 }
1121
1122
1122 if (isfiltered) {
1123 if (isfiltered) {
1123 nothead[i] = 1;
1124 nothead[i] = 1;
1124 continue;
1125 continue;
1125 }
1126 }
1126
1127
1127 parent_1 = PyInt_AS_LONG(p1);
1128 parent_1 = PyInt_AS_LONG(p1);
1128 parent_2 = PyInt_AS_LONG(p2);
1129 parent_2 = PyInt_AS_LONG(p2);
1129 if (parent_1 >= 0)
1130 if (parent_1 >= 0)
1130 nothead[parent_1] = 1;
1131 nothead[parent_1] = 1;
1131 if (parent_2 >= 0)
1132 if (parent_2 >= 0)
1132 nothead[parent_2] = 1;
1133 nothead[parent_2] = 1;
1133 }
1134 }
1134
1135
1135 for (i = 0; i < len; i++) {
1136 for (i = 0; i < len; i++) {
1136 PyObject *head;
1137 PyObject *head;
1137
1138
1138 if (nothead[i])
1139 if (nothead[i])
1139 continue;
1140 continue;
1140 head = PyInt_FromSsize_t(i);
1141 head = PyInt_FromSsize_t(i);
1141 if (head == NULL || PyList_Append(heads, head) == -1) {
1142 if (head == NULL || PyList_Append(heads, head) == -1) {
1142 Py_XDECREF(head);
1143 Py_XDECREF(head);
1143 goto bail;
1144 goto bail;
1144 }
1145 }
1145 }
1146 }
1146
1147
1147 done:
1148 done:
1148 self->headrevs = heads;
1149 self->headrevs = heads;
1149 Py_XDECREF(filter);
1150 Py_XDECREF(filter);
1150 free(nothead);
1151 free(nothead);
1151 return list_copy(self->headrevs);
1152 return list_copy(self->headrevs);
1152 bail:
1153 bail:
1153 Py_XDECREF(filter);
1154 Py_XDECREF(filter);
1154 Py_XDECREF(heads);
1155 Py_XDECREF(heads);
1155 free(nothead);
1156 free(nothead);
1156 return NULL;
1157 return NULL;
1157 }
1158 }
1158
1159
1159 static inline int nt_level(const char *node, Py_ssize_t level)
1160 static inline int nt_level(const char *node, Py_ssize_t level)
1160 {
1161 {
1161 int v = node[level>>1];
1162 int v = node[level>>1];
1162 if (!(level & 1))
1163 if (!(level & 1))
1163 v >>= 4;
1164 v >>= 4;
1164 return v & 0xf;
1165 return v & 0xf;
1165 }
1166 }
1166
1167
1167 /*
1168 /*
1168 * Return values:
1169 * Return values:
1169 *
1170 *
1170 * -4: match is ambiguous (multiple candidates)
1171 * -4: match is ambiguous (multiple candidates)
1171 * -2: not found
1172 * -2: not found
1172 * rest: valid rev
1173 * rest: valid rev
1173 */
1174 */
1174 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1175 static int nt_find(indexObject *self, const char *node, Py_ssize_t nodelen,
1175 int hex)
1176 int hex)
1176 {
1177 {
1177 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1178 int (*getnybble)(const char *, Py_ssize_t) = hex ? hexdigit : nt_level;
1178 int level, maxlevel, off;
1179 int level, maxlevel, off;
1179
1180
1180 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1181 if (nodelen == 20 && node[0] == '\0' && memcmp(node, nullid, 20) == 0)
1181 return -1;
1182 return -1;
1182
1183
1183 if (self->nt == NULL)
1184 if (self->nt == NULL)
1184 return -2;
1185 return -2;
1185
1186
1186 if (hex)
1187 if (hex)
1187 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1188 maxlevel = nodelen > 40 ? 40 : (int)nodelen;
1188 else
1189 else
1189 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1190 maxlevel = nodelen > 20 ? 40 : ((int)nodelen * 2);
1190
1191
1191 for (level = off = 0; level < maxlevel; level++) {
1192 for (level = off = 0; level < maxlevel; level++) {
1192 int k = getnybble(node, level);
1193 int k = getnybble(node, level);
1193 nodetree *n = &self->nt[off];
1194 nodetree *n = &self->nt[off];
1194 int v = n->children[k];
1195 int v = n->children[k];
1195
1196
1196 if (v < 0) {
1197 if (v < 0) {
1197 const char *n;
1198 const char *n;
1198 Py_ssize_t i;
1199 Py_ssize_t i;
1199
1200
1200 v = -v - 1;
1201 v = -v - 1;
1201 n = index_node(self, v);
1202 n = index_node(self, v);
1202 if (n == NULL)
1203 if (n == NULL)
1203 return -2;
1204 return -2;
1204 for (i = level; i < maxlevel; i++)
1205 for (i = level; i < maxlevel; i++)
1205 if (getnybble(node, i) != nt_level(n, i))
1206 if (getnybble(node, i) != nt_level(n, i))
1206 return -2;
1207 return -2;
1207 return v;
1208 return v;
1208 }
1209 }
1209 if (v == 0)
1210 if (v == 0)
1210 return -2;
1211 return -2;
1211 off = v;
1212 off = v;
1212 }
1213 }
1213 /* multiple matches against an ambiguous prefix */
1214 /* multiple matches against an ambiguous prefix */
1214 return -4;
1215 return -4;
1215 }
1216 }
1216
1217
1217 static int nt_new(indexObject *self)
1218 static int nt_new(indexObject *self)
1218 {
1219 {
1219 if (self->ntlength == self->ntcapacity) {
1220 if (self->ntlength == self->ntcapacity) {
1220 self->ntcapacity *= 2;
1221 self->ntcapacity *= 2;
1221 self->nt = realloc(self->nt,
1222 self->nt = realloc(self->nt,
1222 self->ntcapacity * sizeof(nodetree));
1223 self->ntcapacity * sizeof(nodetree));
1223 if (self->nt == NULL) {
1224 if (self->nt == NULL) {
1224 PyErr_SetString(PyExc_MemoryError, "out of memory");
1225 PyErr_SetString(PyExc_MemoryError, "out of memory");
1225 return -1;
1226 return -1;
1226 }
1227 }
1227 memset(&self->nt[self->ntlength], 0,
1228 memset(&self->nt[self->ntlength], 0,
1228 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1229 sizeof(nodetree) * (self->ntcapacity - self->ntlength));
1229 }
1230 }
1230 return self->ntlength++;
1231 return self->ntlength++;
1231 }
1232 }
1232
1233
1233 static int nt_insert(indexObject *self, const char *node, int rev)
1234 static int nt_insert(indexObject *self, const char *node, int rev)
1234 {
1235 {
1235 int level = 0;
1236 int level = 0;
1236 int off = 0;
1237 int off = 0;
1237
1238
1238 while (level < 40) {
1239 while (level < 40) {
1239 int k = nt_level(node, level);
1240 int k = nt_level(node, level);
1240 nodetree *n;
1241 nodetree *n;
1241 int v;
1242 int v;
1242
1243
1243 n = &self->nt[off];
1244 n = &self->nt[off];
1244 v = n->children[k];
1245 v = n->children[k];
1245
1246
1246 if (v == 0) {
1247 if (v == 0) {
1247 n->children[k] = -rev - 1;
1248 n->children[k] = -rev - 1;
1248 return 0;
1249 return 0;
1249 }
1250 }
1250 if (v < 0) {
1251 if (v < 0) {
1251 const char *oldnode = index_node(self, -v - 1);
1252 const char *oldnode = index_node(self, -v - 1);
1252 int noff;
1253 int noff;
1253
1254
1254 if (!oldnode || !memcmp(oldnode, node, 20)) {
1255 if (!oldnode || !memcmp(oldnode, node, 20)) {
1255 n->children[k] = -rev - 1;
1256 n->children[k] = -rev - 1;
1256 return 0;
1257 return 0;
1257 }
1258 }
1258 noff = nt_new(self);
1259 noff = nt_new(self);
1259 if (noff == -1)
1260 if (noff == -1)
1260 return -1;
1261 return -1;
1261 /* self->nt may have been changed by realloc */
1262 /* self->nt may have been changed by realloc */
1262 self->nt[off].children[k] = noff;
1263 self->nt[off].children[k] = noff;
1263 off = noff;
1264 off = noff;
1264 n = &self->nt[off];
1265 n = &self->nt[off];
1265 n->children[nt_level(oldnode, ++level)] = v;
1266 n->children[nt_level(oldnode, ++level)] = v;
1266 if (level > self->ntdepth)
1267 if (level > self->ntdepth)
1267 self->ntdepth = level;
1268 self->ntdepth = level;
1268 self->ntsplits += 1;
1269 self->ntsplits += 1;
1269 } else {
1270 } else {
1270 level += 1;
1271 level += 1;
1271 off = v;
1272 off = v;
1272 }
1273 }
1273 }
1274 }
1274
1275
1275 return -1;
1276 return -1;
1276 }
1277 }
1277
1278
1278 static int nt_init(indexObject *self)
1279 static int nt_init(indexObject *self)
1279 {
1280 {
1280 if (self->nt == NULL) {
1281 if (self->nt == NULL) {
1281 if (self->raw_length > INT_MAX) {
1282 if (self->raw_length > INT_MAX) {
1282 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1283 PyErr_SetString(PyExc_ValueError, "overflow in nt_init");
1283 return -1;
1284 return -1;
1284 }
1285 }
1285 self->ntcapacity = self->raw_length < 4
1286 self->ntcapacity = self->raw_length < 4
1286 ? 4 : (int)self->raw_length / 2;
1287 ? 4 : (int)self->raw_length / 2;
1287
1288
1288 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1289 self->nt = calloc(self->ntcapacity, sizeof(nodetree));
1289 if (self->nt == NULL) {
1290 if (self->nt == NULL) {
1290 PyErr_NoMemory();
1291 PyErr_NoMemory();
1291 return -1;
1292 return -1;
1292 }
1293 }
1293 self->ntlength = 1;
1294 self->ntlength = 1;
1294 self->ntrev = (int)index_length(self) - 1;
1295 self->ntrev = (int)index_length(self) - 1;
1295 self->ntlookups = 1;
1296 self->ntlookups = 1;
1296 self->ntmisses = 0;
1297 self->ntmisses = 0;
1297 if (nt_insert(self, nullid, INT_MAX) == -1)
1298 if (nt_insert(self, nullid, INT_MAX) == -1)
1298 return -1;
1299 return -1;
1299 }
1300 }
1300 return 0;
1301 return 0;
1301 }
1302 }
1302
1303
1303 /*
1304 /*
1304 * Return values:
1305 * Return values:
1305 *
1306 *
1306 * -3: error (exception set)
1307 * -3: error (exception set)
1307 * -2: not found (no exception set)
1308 * -2: not found (no exception set)
1308 * rest: valid rev
1309 * rest: valid rev
1309 */
1310 */
1310 static int index_find_node(indexObject *self,
1311 static int index_find_node(indexObject *self,
1311 const char *node, Py_ssize_t nodelen)
1312 const char *node, Py_ssize_t nodelen)
1312 {
1313 {
1313 int rev;
1314 int rev;
1314
1315
1315 self->ntlookups++;
1316 self->ntlookups++;
1316 rev = nt_find(self, node, nodelen, 0);
1317 rev = nt_find(self, node, nodelen, 0);
1317 if (rev >= -1)
1318 if (rev >= -1)
1318 return rev;
1319 return rev;
1319
1320
1320 if (nt_init(self) == -1)
1321 if (nt_init(self) == -1)
1321 return -3;
1322 return -3;
1322
1323
1323 /*
1324 /*
1324 * For the first handful of lookups, we scan the entire index,
1325 * For the first handful of lookups, we scan the entire index,
1325 * and cache only the matching nodes. This optimizes for cases
1326 * and cache only the matching nodes. This optimizes for cases
1326 * like "hg tip", where only a few nodes are accessed.
1327 * like "hg tip", where only a few nodes are accessed.
1327 *
1328 *
1328 * After that, we cache every node we visit, using a single
1329 * After that, we cache every node we visit, using a single
1329 * scan amortized over multiple lookups. This gives the best
1330 * scan amortized over multiple lookups. This gives the best
1330 * bulk performance, e.g. for "hg log".
1331 * bulk performance, e.g. for "hg log".
1331 */
1332 */
1332 if (self->ntmisses++ < 4) {
1333 if (self->ntmisses++ < 4) {
1333 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1334 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1334 const char *n = index_node(self, rev);
1335 const char *n = index_node(self, rev);
1335 if (n == NULL)
1336 if (n == NULL)
1336 return -2;
1337 return -2;
1337 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1338 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1338 if (nt_insert(self, n, rev) == -1)
1339 if (nt_insert(self, n, rev) == -1)
1339 return -3;
1340 return -3;
1340 break;
1341 break;
1341 }
1342 }
1342 }
1343 }
1343 } else {
1344 } else {
1344 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1345 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1345 const char *n = index_node(self, rev);
1346 const char *n = index_node(self, rev);
1346 if (n == NULL) {
1347 if (n == NULL) {
1347 self->ntrev = rev + 1;
1348 self->ntrev = rev + 1;
1348 return -2;
1349 return -2;
1349 }
1350 }
1350 if (nt_insert(self, n, rev) == -1) {
1351 if (nt_insert(self, n, rev) == -1) {
1351 self->ntrev = rev + 1;
1352 self->ntrev = rev + 1;
1352 return -3;
1353 return -3;
1353 }
1354 }
1354 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1355 if (memcmp(node, n, nodelen > 20 ? 20 : nodelen) == 0) {
1355 break;
1356 break;
1356 }
1357 }
1357 }
1358 }
1358 self->ntrev = rev;
1359 self->ntrev = rev;
1359 }
1360 }
1360
1361
1361 if (rev >= 0)
1362 if (rev >= 0)
1362 return rev;
1363 return rev;
1363 return -2;
1364 return -2;
1364 }
1365 }
1365
1366
1366 static PyObject *raise_revlog_error(void)
1367 static PyObject *raise_revlog_error(void)
1367 {
1368 {
1368 static PyObject *errclass;
1369 static PyObject *errclass;
1369 PyObject *mod = NULL, *errobj;
1370 PyObject *mod = NULL, *errobj;
1370
1371
1371 if (errclass == NULL) {
1372 if (errclass == NULL) {
1372 PyObject *dict;
1373 PyObject *dict;
1373
1374
1374 mod = PyImport_ImportModule("mercurial.error");
1375 mod = PyImport_ImportModule("mercurial.error");
1375 if (mod == NULL)
1376 if (mod == NULL)
1376 goto classfail;
1377 goto classfail;
1377
1378
1378 dict = PyModule_GetDict(mod);
1379 dict = PyModule_GetDict(mod);
1379 if (dict == NULL)
1380 if (dict == NULL)
1380 goto classfail;
1381 goto classfail;
1381
1382
1382 errclass = PyDict_GetItemString(dict, "RevlogError");
1383 errclass = PyDict_GetItemString(dict, "RevlogError");
1383 if (errclass == NULL) {
1384 if (errclass == NULL) {
1384 PyErr_SetString(PyExc_SystemError,
1385 PyErr_SetString(PyExc_SystemError,
1385 "could not find RevlogError");
1386 "could not find RevlogError");
1386 goto classfail;
1387 goto classfail;
1387 }
1388 }
1388 Py_INCREF(errclass);
1389 Py_INCREF(errclass);
1389 Py_DECREF(mod);
1390 Py_DECREF(mod);
1390 }
1391 }
1391
1392
1392 errobj = PyObject_CallFunction(errclass, NULL);
1393 errobj = PyObject_CallFunction(errclass, NULL);
1393 if (errobj == NULL)
1394 if (errobj == NULL)
1394 return NULL;
1395 return NULL;
1395 PyErr_SetObject(errclass, errobj);
1396 PyErr_SetObject(errclass, errobj);
1396 return errobj;
1397 return errobj;
1397
1398
1398 classfail:
1399 classfail:
1399 Py_XDECREF(mod);
1400 Py_XDECREF(mod);
1400 return NULL;
1401 return NULL;
1401 }
1402 }
1402
1403
1403 static PyObject *index_getitem(indexObject *self, PyObject *value)
1404 static PyObject *index_getitem(indexObject *self, PyObject *value)
1404 {
1405 {
1405 char *node;
1406 char *node;
1406 Py_ssize_t nodelen;
1407 Py_ssize_t nodelen;
1407 int rev;
1408 int rev;
1408
1409
1409 if (PyInt_Check(value))
1410 if (PyInt_Check(value))
1410 return index_get(self, PyInt_AS_LONG(value));
1411 return index_get(self, PyInt_AS_LONG(value));
1411
1412
1412 if (node_check(value, &node, &nodelen) == -1)
1413 if (node_check(value, &node, &nodelen) == -1)
1413 return NULL;
1414 return NULL;
1414 rev = index_find_node(self, node, nodelen);
1415 rev = index_find_node(self, node, nodelen);
1415 if (rev >= -1)
1416 if (rev >= -1)
1416 return PyInt_FromLong(rev);
1417 return PyInt_FromLong(rev);
1417 if (rev == -2)
1418 if (rev == -2)
1418 raise_revlog_error();
1419 raise_revlog_error();
1419 return NULL;
1420 return NULL;
1420 }
1421 }
1421
1422
1422 static int nt_partialmatch(indexObject *self, const char *node,
1423 static int nt_partialmatch(indexObject *self, const char *node,
1423 Py_ssize_t nodelen)
1424 Py_ssize_t nodelen)
1424 {
1425 {
1425 int rev;
1426 int rev;
1426
1427
1427 if (nt_init(self) == -1)
1428 if (nt_init(self) == -1)
1428 return -3;
1429 return -3;
1429
1430
1430 if (self->ntrev > 0) {
1431 if (self->ntrev > 0) {
1431 /* ensure that the radix tree is fully populated */
1432 /* ensure that the radix tree is fully populated */
1432 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1433 for (rev = self->ntrev - 1; rev >= 0; rev--) {
1433 const char *n = index_node(self, rev);
1434 const char *n = index_node(self, rev);
1434 if (n == NULL)
1435 if (n == NULL)
1435 return -2;
1436 return -2;
1436 if (nt_insert(self, n, rev) == -1)
1437 if (nt_insert(self, n, rev) == -1)
1437 return -3;
1438 return -3;
1438 }
1439 }
1439 self->ntrev = rev;
1440 self->ntrev = rev;
1440 }
1441 }
1441
1442
1442 return nt_find(self, node, nodelen, 1);
1443 return nt_find(self, node, nodelen, 1);
1443 }
1444 }
1444
1445
1445 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1446 static PyObject *index_partialmatch(indexObject *self, PyObject *args)
1446 {
1447 {
1447 const char *fullnode;
1448 const char *fullnode;
1448 int nodelen;
1449 int nodelen;
1449 char *node;
1450 char *node;
1450 int rev, i;
1451 int rev, i;
1451
1452
1452 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1453 if (!PyArg_ParseTuple(args, "s#", &node, &nodelen))
1453 return NULL;
1454 return NULL;
1454
1455
1455 if (nodelen < 4) {
1456 if (nodelen < 4) {
1456 PyErr_SetString(PyExc_ValueError, "key too short");
1457 PyErr_SetString(PyExc_ValueError, "key too short");
1457 return NULL;
1458 return NULL;
1458 }
1459 }
1459
1460
1460 if (nodelen > 40) {
1461 if (nodelen > 40) {
1461 PyErr_SetString(PyExc_ValueError, "key too long");
1462 PyErr_SetString(PyExc_ValueError, "key too long");
1462 return NULL;
1463 return NULL;
1463 }
1464 }
1464
1465
1465 for (i = 0; i < nodelen; i++)
1466 for (i = 0; i < nodelen; i++)
1466 hexdigit(node, i);
1467 hexdigit(node, i);
1467 if (PyErr_Occurred()) {
1468 if (PyErr_Occurred()) {
1468 /* input contains non-hex characters */
1469 /* input contains non-hex characters */
1469 PyErr_Clear();
1470 PyErr_Clear();
1470 Py_RETURN_NONE;
1471 Py_RETURN_NONE;
1471 }
1472 }
1472
1473
1473 rev = nt_partialmatch(self, node, nodelen);
1474 rev = nt_partialmatch(self, node, nodelen);
1474
1475
1475 switch (rev) {
1476 switch (rev) {
1476 case -4:
1477 case -4:
1477 raise_revlog_error();
1478 raise_revlog_error();
1478 case -3:
1479 case -3:
1479 return NULL;
1480 return NULL;
1480 case -2:
1481 case -2:
1481 Py_RETURN_NONE;
1482 Py_RETURN_NONE;
1482 case -1:
1483 case -1:
1483 return PyString_FromStringAndSize(nullid, 20);
1484 return PyString_FromStringAndSize(nullid, 20);
1484 }
1485 }
1485
1486
1486 fullnode = index_node(self, rev);
1487 fullnode = index_node(self, rev);
1487 if (fullnode == NULL) {
1488 if (fullnode == NULL) {
1488 PyErr_Format(PyExc_IndexError,
1489 PyErr_Format(PyExc_IndexError,
1489 "could not access rev %d", rev);
1490 "could not access rev %d", rev);
1490 return NULL;
1491 return NULL;
1491 }
1492 }
1492 return PyString_FromStringAndSize(fullnode, 20);
1493 return PyString_FromStringAndSize(fullnode, 20);
1493 }
1494 }
1494
1495
1495 static PyObject *index_m_get(indexObject *self, PyObject *args)
1496 static PyObject *index_m_get(indexObject *self, PyObject *args)
1496 {
1497 {
1497 Py_ssize_t nodelen;
1498 Py_ssize_t nodelen;
1498 PyObject *val;
1499 PyObject *val;
1499 char *node;
1500 char *node;
1500 int rev;
1501 int rev;
1501
1502
1502 if (!PyArg_ParseTuple(args, "O", &val))
1503 if (!PyArg_ParseTuple(args, "O", &val))
1503 return NULL;
1504 return NULL;
1504 if (node_check(val, &node, &nodelen) == -1)
1505 if (node_check(val, &node, &nodelen) == -1)
1505 return NULL;
1506 return NULL;
1506 rev = index_find_node(self, node, nodelen);
1507 rev = index_find_node(self, node, nodelen);
1507 if (rev == -3)
1508 if (rev == -3)
1508 return NULL;
1509 return NULL;
1509 if (rev == -2)
1510 if (rev == -2)
1510 Py_RETURN_NONE;
1511 Py_RETURN_NONE;
1511 return PyInt_FromLong(rev);
1512 return PyInt_FromLong(rev);
1512 }
1513 }
1513
1514
1514 static int index_contains(indexObject *self, PyObject *value)
1515 static int index_contains(indexObject *self, PyObject *value)
1515 {
1516 {
1516 char *node;
1517 char *node;
1517 Py_ssize_t nodelen;
1518 Py_ssize_t nodelen;
1518
1519
1519 if (PyInt_Check(value)) {
1520 if (PyInt_Check(value)) {
1520 long rev = PyInt_AS_LONG(value);
1521 long rev = PyInt_AS_LONG(value);
1521 return rev >= -1 && rev < index_length(self);
1522 return rev >= -1 && rev < index_length(self);
1522 }
1523 }
1523
1524
1524 if (node_check(value, &node, &nodelen) == -1)
1525 if (node_check(value, &node, &nodelen) == -1)
1525 return -1;
1526 return -1;
1526
1527
1527 switch (index_find_node(self, node, nodelen)) {
1528 switch (index_find_node(self, node, nodelen)) {
1528 case -3:
1529 case -3:
1529 return -1;
1530 return -1;
1530 case -2:
1531 case -2:
1531 return 0;
1532 return 0;
1532 default:
1533 default:
1533 return 1;
1534 return 1;
1534 }
1535 }
1535 }
1536 }
1536
1537
1537 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1538 static inline void index_get_parents(indexObject *self, int rev, int *ps)
1538 {
1539 {
1539 if (rev >= self->length - 1) {
1540 if (rev >= self->length - 1) {
1540 PyObject *tuple = PyList_GET_ITEM(self->added,
1541 PyObject *tuple = PyList_GET_ITEM(self->added,
1541 rev - self->length + 1);
1542 rev - self->length + 1);
1542 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1543 ps[0] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 5));
1543 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1544 ps[1] = (int)PyInt_AS_LONG(PyTuple_GET_ITEM(tuple, 6));
1544 } else {
1545 } else {
1545 const char *data = index_deref(self, rev);
1546 const char *data = index_deref(self, rev);
1546 ps[0] = getbe32(data + 24);
1547 ps[0] = getbe32(data + 24);
1547 ps[1] = getbe32(data + 28);
1548 ps[1] = getbe32(data + 28);
1548 }
1549 }
1549 }
1550 }
1550
1551
1551 typedef uint64_t bitmask;
1552 typedef uint64_t bitmask;
1552
1553
1553 /*
1554 /*
1554 * Given a disjoint set of revs, return all candidates for the
1555 * Given a disjoint set of revs, return all candidates for the
1555 * greatest common ancestor. In revset notation, this is the set
1556 * greatest common ancestor. In revset notation, this is the set
1556 * "heads(::a and ::b and ...)"
1557 * "heads(::a and ::b and ...)"
1557 */
1558 */
1558 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1559 static PyObject *find_gca_candidates(indexObject *self, const int *revs,
1559 int revcount)
1560 int revcount)
1560 {
1561 {
1561 const bitmask allseen = (1ull << revcount) - 1;
1562 const bitmask allseen = (1ull << revcount) - 1;
1562 const bitmask poison = 1ull << revcount;
1563 const bitmask poison = 1ull << revcount;
1563 PyObject *gca = PyList_New(0);
1564 PyObject *gca = PyList_New(0);
1564 int i, v, interesting;
1565 int i, v, interesting;
1565 int maxrev = -1;
1566 int maxrev = -1;
1566 bitmask sp;
1567 bitmask sp;
1567 bitmask *seen;
1568 bitmask *seen;
1568
1569
1569 if (gca == NULL)
1570 if (gca == NULL)
1570 return PyErr_NoMemory();
1571 return PyErr_NoMemory();
1571
1572
1572 for (i = 0; i < revcount; i++) {
1573 for (i = 0; i < revcount; i++) {
1573 if (revs[i] > maxrev)
1574 if (revs[i] > maxrev)
1574 maxrev = revs[i];
1575 maxrev = revs[i];
1575 }
1576 }
1576
1577
1577 seen = calloc(sizeof(*seen), maxrev + 1);
1578 seen = calloc(sizeof(*seen), maxrev + 1);
1578 if (seen == NULL) {
1579 if (seen == NULL) {
1579 Py_DECREF(gca);
1580 Py_DECREF(gca);
1580 return PyErr_NoMemory();
1581 return PyErr_NoMemory();
1581 }
1582 }
1582
1583
1583 for (i = 0; i < revcount; i++)
1584 for (i = 0; i < revcount; i++)
1584 seen[revs[i]] = 1ull << i;
1585 seen[revs[i]] = 1ull << i;
1585
1586
1586 interesting = revcount;
1587 interesting = revcount;
1587
1588
1588 for (v = maxrev; v >= 0 && interesting; v--) {
1589 for (v = maxrev; v >= 0 && interesting; v--) {
1589 bitmask sv = seen[v];
1590 bitmask sv = seen[v];
1590 int parents[2];
1591 int parents[2];
1591
1592
1592 if (!sv)
1593 if (!sv)
1593 continue;
1594 continue;
1594
1595
1595 if (sv < poison) {
1596 if (sv < poison) {
1596 interesting -= 1;
1597 interesting -= 1;
1597 if (sv == allseen) {
1598 if (sv == allseen) {
1598 PyObject *obj = PyInt_FromLong(v);
1599 PyObject *obj = PyInt_FromLong(v);
1599 if (obj == NULL)
1600 if (obj == NULL)
1600 goto bail;
1601 goto bail;
1601 if (PyList_Append(gca, obj) == -1) {
1602 if (PyList_Append(gca, obj) == -1) {
1602 Py_DECREF(obj);
1603 Py_DECREF(obj);
1603 goto bail;
1604 goto bail;
1604 }
1605 }
1605 sv |= poison;
1606 sv |= poison;
1606 for (i = 0; i < revcount; i++) {
1607 for (i = 0; i < revcount; i++) {
1607 if (revs[i] == v)
1608 if (revs[i] == v)
1608 goto done;
1609 goto done;
1609 }
1610 }
1610 }
1611 }
1611 }
1612 }
1612 index_get_parents(self, v, parents);
1613 index_get_parents(self, v, parents);
1613
1614
1614 for (i = 0; i < 2; i++) {
1615 for (i = 0; i < 2; i++) {
1615 int p = parents[i];
1616 int p = parents[i];
1616 if (p == -1)
1617 if (p == -1)
1617 continue;
1618 continue;
1618 sp = seen[p];
1619 sp = seen[p];
1619 if (sv < poison) {
1620 if (sv < poison) {
1620 if (sp == 0) {
1621 if (sp == 0) {
1621 seen[p] = sv;
1622 seen[p] = sv;
1622 interesting++;
1623 interesting++;
1623 }
1624 }
1624 else if (sp != sv)
1625 else if (sp != sv)
1625 seen[p] |= sv;
1626 seen[p] |= sv;
1626 } else {
1627 } else {
1627 if (sp && sp < poison)
1628 if (sp && sp < poison)
1628 interesting--;
1629 interesting--;
1629 seen[p] = sv;
1630 seen[p] = sv;
1630 }
1631 }
1631 }
1632 }
1632 }
1633 }
1633
1634
1634 done:
1635 done:
1635 free(seen);
1636 free(seen);
1636 return gca;
1637 return gca;
1637 bail:
1638 bail:
1638 free(seen);
1639 free(seen);
1639 Py_XDECREF(gca);
1640 Py_XDECREF(gca);
1640 return NULL;
1641 return NULL;
1641 }
1642 }
1642
1643
1643 /*
1644 /*
1644 * Given a disjoint set of revs, return the subset with the longest
1645 * Given a disjoint set of revs, return the subset with the longest
1645 * path to the root.
1646 * path to the root.
1646 */
1647 */
1647 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1648 static PyObject *find_deepest(indexObject *self, PyObject *revs)
1648 {
1649 {
1649 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1650 const Py_ssize_t revcount = PyList_GET_SIZE(revs);
1650 static const Py_ssize_t capacity = 24;
1651 static const Py_ssize_t capacity = 24;
1651 int *depth, *interesting = NULL;
1652 int *depth, *interesting = NULL;
1652 int i, j, v, ninteresting;
1653 int i, j, v, ninteresting;
1653 PyObject *dict = NULL, *keys = NULL;
1654 PyObject *dict = NULL, *keys = NULL;
1654 long *seen = NULL;
1655 long *seen = NULL;
1655 int maxrev = -1;
1656 int maxrev = -1;
1656 long final;
1657 long final;
1657
1658
1658 if (revcount > capacity) {
1659 if (revcount > capacity) {
1659 PyErr_Format(PyExc_OverflowError,
1660 PyErr_Format(PyExc_OverflowError,
1660 "bitset size (%ld) > capacity (%ld)",
1661 "bitset size (%ld) > capacity (%ld)",
1661 (long)revcount, (long)capacity);
1662 (long)revcount, (long)capacity);
1662 return NULL;
1663 return NULL;
1663 }
1664 }
1664
1665
1665 for (i = 0; i < revcount; i++) {
1666 for (i = 0; i < revcount; i++) {
1666 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1667 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1667 if (n > maxrev)
1668 if (n > maxrev)
1668 maxrev = n;
1669 maxrev = n;
1669 }
1670 }
1670
1671
1671 depth = calloc(sizeof(*depth), maxrev + 1);
1672 depth = calloc(sizeof(*depth), maxrev + 1);
1672 if (depth == NULL)
1673 if (depth == NULL)
1673 return PyErr_NoMemory();
1674 return PyErr_NoMemory();
1674
1675
1675 seen = calloc(sizeof(*seen), maxrev + 1);
1676 seen = calloc(sizeof(*seen), maxrev + 1);
1676 if (seen == NULL) {
1677 if (seen == NULL) {
1677 PyErr_NoMemory();
1678 PyErr_NoMemory();
1678 goto bail;
1679 goto bail;
1679 }
1680 }
1680
1681
1681 interesting = calloc(sizeof(*interesting), 2 << revcount);
1682 interesting = calloc(sizeof(*interesting), 2 << revcount);
1682 if (interesting == NULL) {
1683 if (interesting == NULL) {
1683 PyErr_NoMemory();
1684 PyErr_NoMemory();
1684 goto bail;
1685 goto bail;
1685 }
1686 }
1686
1687
1687 if (PyList_Sort(revs) == -1)
1688 if (PyList_Sort(revs) == -1)
1688 goto bail;
1689 goto bail;
1689
1690
1690 for (i = 0; i < revcount; i++) {
1691 for (i = 0; i < revcount; i++) {
1691 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1692 int n = (int)PyInt_AsLong(PyList_GET_ITEM(revs, i));
1692 long b = 1l << i;
1693 long b = 1l << i;
1693 depth[n] = 1;
1694 depth[n] = 1;
1694 seen[n] = b;
1695 seen[n] = b;
1695 interesting[b] = 1;
1696 interesting[b] = 1;
1696 }
1697 }
1697
1698
1698 ninteresting = (int)revcount;
1699 ninteresting = (int)revcount;
1699
1700
1700 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1701 for (v = maxrev; v >= 0 && ninteresting > 1; v--) {
1701 int dv = depth[v];
1702 int dv = depth[v];
1702 int parents[2];
1703 int parents[2];
1703 long sv;
1704 long sv;
1704
1705
1705 if (dv == 0)
1706 if (dv == 0)
1706 continue;
1707 continue;
1707
1708
1708 sv = seen[v];
1709 sv = seen[v];
1709 index_get_parents(self, v, parents);
1710 index_get_parents(self, v, parents);
1710
1711
1711 for (i = 0; i < 2; i++) {
1712 for (i = 0; i < 2; i++) {
1712 int p = parents[i];
1713 int p = parents[i];
1713 long nsp, sp;
1714 long nsp, sp;
1714 int dp;
1715 int dp;
1715
1716
1716 if (p == -1)
1717 if (p == -1)
1717 continue;
1718 continue;
1718
1719
1719 dp = depth[p];
1720 dp = depth[p];
1720 nsp = sp = seen[p];
1721 nsp = sp = seen[p];
1721 if (dp <= dv) {
1722 if (dp <= dv) {
1722 depth[p] = dv + 1;
1723 depth[p] = dv + 1;
1723 if (sp != sv) {
1724 if (sp != sv) {
1724 interesting[sv] += 1;
1725 interesting[sv] += 1;
1725 nsp = seen[p] = sv;
1726 nsp = seen[p] = sv;
1726 if (sp) {
1727 if (sp) {
1727 interesting[sp] -= 1;
1728 interesting[sp] -= 1;
1728 if (interesting[sp] == 0)
1729 if (interesting[sp] == 0)
1729 ninteresting -= 1;
1730 ninteresting -= 1;
1730 }
1731 }
1731 }
1732 }
1732 }
1733 }
1733 else if (dv == dp - 1) {
1734 else if (dv == dp - 1) {
1734 nsp = sp | sv;
1735 nsp = sp | sv;
1735 if (nsp == sp)
1736 if (nsp == sp)
1736 continue;
1737 continue;
1737 seen[p] = nsp;
1738 seen[p] = nsp;
1738 interesting[sp] -= 1;
1739 interesting[sp] -= 1;
1739 if (interesting[sp] == 0 && interesting[nsp] > 0)
1740 if (interesting[sp] == 0 && interesting[nsp] > 0)
1740 ninteresting -= 1;
1741 ninteresting -= 1;
1741 interesting[nsp] += 1;
1742 interesting[nsp] += 1;
1742 }
1743 }
1743 }
1744 }
1744 interesting[sv] -= 1;
1745 interesting[sv] -= 1;
1745 if (interesting[sv] == 0)
1746 if (interesting[sv] == 0)
1746 ninteresting -= 1;
1747 ninteresting -= 1;
1747 }
1748 }
1748
1749
1749 final = 0;
1750 final = 0;
1750 j = ninteresting;
1751 j = ninteresting;
1751 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1752 for (i = 0; i < (int)(2 << revcount) && j > 0; i++) {
1752 if (interesting[i] == 0)
1753 if (interesting[i] == 0)
1753 continue;
1754 continue;
1754 final |= i;
1755 final |= i;
1755 j -= 1;
1756 j -= 1;
1756 }
1757 }
1757 if (final == 0) {
1758 if (final == 0) {
1758 keys = PyList_New(0);
1759 keys = PyList_New(0);
1759 goto bail;
1760 goto bail;
1760 }
1761 }
1761
1762
1762 dict = PyDict_New();
1763 dict = PyDict_New();
1763 if (dict == NULL)
1764 if (dict == NULL)
1764 goto bail;
1765 goto bail;
1765
1766
1766 for (i = 0; i < revcount; i++) {
1767 for (i = 0; i < revcount; i++) {
1767 PyObject *key;
1768 PyObject *key;
1768
1769
1769 if ((final & (1 << i)) == 0)
1770 if ((final & (1 << i)) == 0)
1770 continue;
1771 continue;
1771
1772
1772 key = PyList_GET_ITEM(revs, i);
1773 key = PyList_GET_ITEM(revs, i);
1773 Py_INCREF(key);
1774 Py_INCREF(key);
1774 Py_INCREF(Py_None);
1775 Py_INCREF(Py_None);
1775 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1776 if (PyDict_SetItem(dict, key, Py_None) == -1) {
1776 Py_DECREF(key);
1777 Py_DECREF(key);
1777 Py_DECREF(Py_None);
1778 Py_DECREF(Py_None);
1778 goto bail;
1779 goto bail;
1779 }
1780 }
1780 }
1781 }
1781
1782
1782 keys = PyDict_Keys(dict);
1783 keys = PyDict_Keys(dict);
1783
1784
1784 bail:
1785 bail:
1785 free(depth);
1786 free(depth);
1786 free(seen);
1787 free(seen);
1787 free(interesting);
1788 free(interesting);
1788 Py_XDECREF(dict);
1789 Py_XDECREF(dict);
1789
1790
1790 return keys;
1791 return keys;
1791 }
1792 }
1792
1793
1793 /*
1794 /*
1794 * Given a (possibly overlapping) set of revs, return all the
1795 * Given a (possibly overlapping) set of revs, return all the
1795 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1796 * common ancestors heads: heads(::args[0] and ::a[1] and ...)
1796 */
1797 */
1797 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1798 static PyObject *index_commonancestorsheads(indexObject *self, PyObject *args)
1798 {
1799 {
1799 PyObject *ret = NULL;
1800 PyObject *ret = NULL;
1800 Py_ssize_t argcount, i, len;
1801 Py_ssize_t argcount, i, len;
1801 bitmask repeat = 0;
1802 bitmask repeat = 0;
1802 int revcount = 0;
1803 int revcount = 0;
1803 int *revs;
1804 int *revs;
1804
1805
1805 argcount = PySequence_Length(args);
1806 argcount = PySequence_Length(args);
1806 revs = malloc(argcount * sizeof(*revs));
1807 revs = malloc(argcount * sizeof(*revs));
1807 if (argcount > 0 && revs == NULL)
1808 if (argcount > 0 && revs == NULL)
1808 return PyErr_NoMemory();
1809 return PyErr_NoMemory();
1809 len = index_length(self) - 1;
1810 len = index_length(self) - 1;
1810
1811
1811 for (i = 0; i < argcount; i++) {
1812 for (i = 0; i < argcount; i++) {
1812 static const int capacity = 24;
1813 static const int capacity = 24;
1813 PyObject *obj = PySequence_GetItem(args, i);
1814 PyObject *obj = PySequence_GetItem(args, i);
1814 bitmask x;
1815 bitmask x;
1815 long val;
1816 long val;
1816
1817
1817 if (!PyInt_Check(obj)) {
1818 if (!PyInt_Check(obj)) {
1818 PyErr_SetString(PyExc_TypeError,
1819 PyErr_SetString(PyExc_TypeError,
1819 "arguments must all be ints");
1820 "arguments must all be ints");
1820 Py_DECREF(obj);
1821 Py_DECREF(obj);
1821 goto bail;
1822 goto bail;
1822 }
1823 }
1823 val = PyInt_AsLong(obj);
1824 val = PyInt_AsLong(obj);
1824 Py_DECREF(obj);
1825 Py_DECREF(obj);
1825 if (val == -1) {
1826 if (val == -1) {
1826 ret = PyList_New(0);
1827 ret = PyList_New(0);
1827 goto done;
1828 goto done;
1828 }
1829 }
1829 if (val < 0 || val >= len) {
1830 if (val < 0 || val >= len) {
1830 PyErr_SetString(PyExc_IndexError,
1831 PyErr_SetString(PyExc_IndexError,
1831 "index out of range");
1832 "index out of range");
1832 goto bail;
1833 goto bail;
1833 }
1834 }
1834 /* this cheesy bloom filter lets us avoid some more
1835 /* this cheesy bloom filter lets us avoid some more
1835 * expensive duplicate checks in the common set-is-disjoint
1836 * expensive duplicate checks in the common set-is-disjoint
1836 * case */
1837 * case */
1837 x = 1ull << (val & 0x3f);
1838 x = 1ull << (val & 0x3f);
1838 if (repeat & x) {
1839 if (repeat & x) {
1839 int k;
1840 int k;
1840 for (k = 0; k < revcount; k++) {
1841 for (k = 0; k < revcount; k++) {
1841 if (val == revs[k])
1842 if (val == revs[k])
1842 goto duplicate;
1843 goto duplicate;
1843 }
1844 }
1844 }
1845 }
1845 else repeat |= x;
1846 else repeat |= x;
1846 if (revcount >= capacity) {
1847 if (revcount >= capacity) {
1847 PyErr_Format(PyExc_OverflowError,
1848 PyErr_Format(PyExc_OverflowError,
1848 "bitset size (%d) > capacity (%d)",
1849 "bitset size (%d) > capacity (%d)",
1849 revcount, capacity);
1850 revcount, capacity);
1850 goto bail;
1851 goto bail;
1851 }
1852 }
1852 revs[revcount++] = (int)val;
1853 revs[revcount++] = (int)val;
1853 duplicate:;
1854 duplicate:;
1854 }
1855 }
1855
1856
1856 if (revcount == 0) {
1857 if (revcount == 0) {
1857 ret = PyList_New(0);
1858 ret = PyList_New(0);
1858 goto done;
1859 goto done;
1859 }
1860 }
1860 if (revcount == 1) {
1861 if (revcount == 1) {
1861 PyObject *obj;
1862 PyObject *obj;
1862 ret = PyList_New(1);
1863 ret = PyList_New(1);
1863 if (ret == NULL)
1864 if (ret == NULL)
1864 goto bail;
1865 goto bail;
1865 obj = PyInt_FromLong(revs[0]);
1866 obj = PyInt_FromLong(revs[0]);
1866 if (obj == NULL)
1867 if (obj == NULL)
1867 goto bail;
1868 goto bail;
1868 PyList_SET_ITEM(ret, 0, obj);
1869 PyList_SET_ITEM(ret, 0, obj);
1869 goto done;
1870 goto done;
1870 }
1871 }
1871
1872
1872 ret = find_gca_candidates(self, revs, revcount);
1873 ret = find_gca_candidates(self, revs, revcount);
1873 if (ret == NULL)
1874 if (ret == NULL)
1874 goto bail;
1875 goto bail;
1875
1876
1876 done:
1877 done:
1877 free(revs);
1878 free(revs);
1878 return ret;
1879 return ret;
1879
1880
1880 bail:
1881 bail:
1881 free(revs);
1882 free(revs);
1882 Py_XDECREF(ret);
1883 Py_XDECREF(ret);
1883 return NULL;
1884 return NULL;
1884 }
1885 }
1885
1886
1886 /*
1887 /*
1887 * Given a (possibly overlapping) set of revs, return the greatest
1888 * Given a (possibly overlapping) set of revs, return the greatest
1888 * common ancestors: those with the longest path to the root.
1889 * common ancestors: those with the longest path to the root.
1889 */
1890 */
1890 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1891 static PyObject *index_ancestors(indexObject *self, PyObject *args)
1891 {
1892 {
1892 PyObject *gca = index_commonancestorsheads(self, args);
1893 PyObject *gca = index_commonancestorsheads(self, args);
1893 if (gca == NULL)
1894 if (gca == NULL)
1894 return NULL;
1895 return NULL;
1895
1896
1896 if (PyList_GET_SIZE(gca) <= 1) {
1897 if (PyList_GET_SIZE(gca) <= 1) {
1897 Py_INCREF(gca);
1898 Py_INCREF(gca);
1898 return gca;
1899 return gca;
1899 }
1900 }
1900
1901
1901 return find_deepest(self, gca);
1902 return find_deepest(self, gca);
1902 }
1903 }
1903
1904
1904 /*
1905 /*
1905 * Invalidate any trie entries introduced by added revs.
1906 * Invalidate any trie entries introduced by added revs.
1906 */
1907 */
1907 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1908 static void nt_invalidate_added(indexObject *self, Py_ssize_t start)
1908 {
1909 {
1909 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1910 Py_ssize_t i, len = PyList_GET_SIZE(self->added);
1910
1911
1911 for (i = start; i < len; i++) {
1912 for (i = start; i < len; i++) {
1912 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1913 PyObject *tuple = PyList_GET_ITEM(self->added, i);
1913 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1914 PyObject *node = PyTuple_GET_ITEM(tuple, 7);
1914
1915
1915 nt_insert(self, PyString_AS_STRING(node), -1);
1916 nt_insert(self, PyString_AS_STRING(node), -1);
1916 }
1917 }
1917
1918
1918 if (start == 0)
1919 if (start == 0)
1919 Py_CLEAR(self->added);
1920 Py_CLEAR(self->added);
1920 }
1921 }
1921
1922
1922 /*
1923 /*
1923 * Delete a numeric range of revs, which must be at the end of the
1924 * Delete a numeric range of revs, which must be at the end of the
1924 * range, but exclude the sentinel nullid entry.
1925 * range, but exclude the sentinel nullid entry.
1925 */
1926 */
1926 static int index_slice_del(indexObject *self, PyObject *item)
1927 static int index_slice_del(indexObject *self, PyObject *item)
1927 {
1928 {
1928 Py_ssize_t start, stop, step, slicelength;
1929 Py_ssize_t start, stop, step, slicelength;
1929 Py_ssize_t length = index_length(self);
1930 Py_ssize_t length = index_length(self);
1930 int ret = 0;
1931 int ret = 0;
1931
1932
1932 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1933 if (PySlice_GetIndicesEx((PySliceObject*)item, length,
1933 &start, &stop, &step, &slicelength) < 0)
1934 &start, &stop, &step, &slicelength) < 0)
1934 return -1;
1935 return -1;
1935
1936
1936 if (slicelength <= 0)
1937 if (slicelength <= 0)
1937 return 0;
1938 return 0;
1938
1939
1939 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1940 if ((step < 0 && start < stop) || (step > 0 && start > stop))
1940 stop = start;
1941 stop = start;
1941
1942
1942 if (step < 0) {
1943 if (step < 0) {
1943 stop = start + 1;
1944 stop = start + 1;
1944 start = stop + step*(slicelength - 1) - 1;
1945 start = stop + step*(slicelength - 1) - 1;
1945 step = -step;
1946 step = -step;
1946 }
1947 }
1947
1948
1948 if (step != 1) {
1949 if (step != 1) {
1949 PyErr_SetString(PyExc_ValueError,
1950 PyErr_SetString(PyExc_ValueError,
1950 "revlog index delete requires step size of 1");
1951 "revlog index delete requires step size of 1");
1951 return -1;
1952 return -1;
1952 }
1953 }
1953
1954
1954 if (stop != length - 1) {
1955 if (stop != length - 1) {
1955 PyErr_SetString(PyExc_IndexError,
1956 PyErr_SetString(PyExc_IndexError,
1956 "revlog index deletion indices are invalid");
1957 "revlog index deletion indices are invalid");
1957 return -1;
1958 return -1;
1958 }
1959 }
1959
1960
1960 if (start < self->length - 1) {
1961 if (start < self->length - 1) {
1961 if (self->nt) {
1962 if (self->nt) {
1962 Py_ssize_t i;
1963 Py_ssize_t i;
1963
1964
1964 for (i = start + 1; i < self->length - 1; i++) {
1965 for (i = start + 1; i < self->length - 1; i++) {
1965 const char *node = index_node(self, i);
1966 const char *node = index_node(self, i);
1966
1967
1967 if (node)
1968 if (node)
1968 nt_insert(self, node, -1);
1969 nt_insert(self, node, -1);
1969 }
1970 }
1970 if (self->added)
1971 if (self->added)
1971 nt_invalidate_added(self, 0);
1972 nt_invalidate_added(self, 0);
1972 if (self->ntrev > start)
1973 if (self->ntrev > start)
1973 self->ntrev = (int)start;
1974 self->ntrev = (int)start;
1974 }
1975 }
1975 self->length = start + 1;
1976 self->length = start + 1;
1976 if (start < self->raw_length) {
1977 if (start < self->raw_length) {
1977 if (self->cache) {
1978 if (self->cache) {
1978 Py_ssize_t i;
1979 Py_ssize_t i;
1979 for (i = start; i < self->raw_length; i++)
1980 for (i = start; i < self->raw_length; i++)
1980 Py_CLEAR(self->cache[i]);
1981 Py_CLEAR(self->cache[i]);
1981 }
1982 }
1982 self->raw_length = start;
1983 self->raw_length = start;
1983 }
1984 }
1984 goto done;
1985 goto done;
1985 }
1986 }
1986
1987
1987 if (self->nt) {
1988 if (self->nt) {
1988 nt_invalidate_added(self, start - self->length + 1);
1989 nt_invalidate_added(self, start - self->length + 1);
1989 if (self->ntrev > start)
1990 if (self->ntrev > start)
1990 self->ntrev = (int)start;
1991 self->ntrev = (int)start;
1991 }
1992 }
1992 if (self->added)
1993 if (self->added)
1993 ret = PyList_SetSlice(self->added, start - self->length + 1,
1994 ret = PyList_SetSlice(self->added, start - self->length + 1,
1994 PyList_GET_SIZE(self->added), NULL);
1995 PyList_GET_SIZE(self->added), NULL);
1995 done:
1996 done:
1996 Py_CLEAR(self->headrevs);
1997 Py_CLEAR(self->headrevs);
1997 return ret;
1998 return ret;
1998 }
1999 }
1999
2000
2000 /*
2001 /*
2001 * Supported ops:
2002 * Supported ops:
2002 *
2003 *
2003 * slice deletion
2004 * slice deletion
2004 * string assignment (extend node->rev mapping)
2005 * string assignment (extend node->rev mapping)
2005 * string deletion (shrink node->rev mapping)
2006 * string deletion (shrink node->rev mapping)
2006 */
2007 */
2007 static int index_assign_subscript(indexObject *self, PyObject *item,
2008 static int index_assign_subscript(indexObject *self, PyObject *item,
2008 PyObject *value)
2009 PyObject *value)
2009 {
2010 {
2010 char *node;
2011 char *node;
2011 Py_ssize_t nodelen;
2012 Py_ssize_t nodelen;
2012 long rev;
2013 long rev;
2013
2014
2014 if (PySlice_Check(item) && value == NULL)
2015 if (PySlice_Check(item) && value == NULL)
2015 return index_slice_del(self, item);
2016 return index_slice_del(self, item);
2016
2017
2017 if (node_check(item, &node, &nodelen) == -1)
2018 if (node_check(item, &node, &nodelen) == -1)
2018 return -1;
2019 return -1;
2019
2020
2020 if (value == NULL)
2021 if (value == NULL)
2021 return self->nt ? nt_insert(self, node, -1) : 0;
2022 return self->nt ? nt_insert(self, node, -1) : 0;
2022 rev = PyInt_AsLong(value);
2023 rev = PyInt_AsLong(value);
2023 if (rev > INT_MAX || rev < 0) {
2024 if (rev > INT_MAX || rev < 0) {
2024 if (!PyErr_Occurred())
2025 if (!PyErr_Occurred())
2025 PyErr_SetString(PyExc_ValueError, "rev out of range");
2026 PyErr_SetString(PyExc_ValueError, "rev out of range");
2026 return -1;
2027 return -1;
2027 }
2028 }
2028
2029
2029 if (nt_init(self) == -1)
2030 if (nt_init(self) == -1)
2030 return -1;
2031 return -1;
2031 return nt_insert(self, node, (int)rev);
2032 return nt_insert(self, node, (int)rev);
2032 }
2033 }
2033
2034
2034 /*
2035 /*
2035 * Find all RevlogNG entries in an index that has inline data. Update
2036 * Find all RevlogNG entries in an index that has inline data. Update
2036 * the optional "offsets" table with those entries.
2037 * the optional "offsets" table with those entries.
2037 */
2038 */
2038 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2039 static Py_ssize_t inline_scan(indexObject *self, const char **offsets)
2039 {
2040 {
2040 const char *data = PyString_AS_STRING(self->data);
2041 const char *data = PyString_AS_STRING(self->data);
2041 Py_ssize_t pos = 0;
2042 Py_ssize_t pos = 0;
2042 Py_ssize_t end = PyString_GET_SIZE(self->data);
2043 Py_ssize_t end = PyString_GET_SIZE(self->data);
2043 long incr = v1_hdrsize;
2044 long incr = v1_hdrsize;
2044 Py_ssize_t len = 0;
2045 Py_ssize_t len = 0;
2045
2046
2046 while (pos + v1_hdrsize <= end && pos >= 0) {
2047 while (pos + v1_hdrsize <= end && pos >= 0) {
2047 uint32_t comp_len;
2048 uint32_t comp_len;
2048 /* 3rd element of header is length of compressed inline data */
2049 /* 3rd element of header is length of compressed inline data */
2049 comp_len = getbe32(data + pos + 8);
2050 comp_len = getbe32(data + pos + 8);
2050 incr = v1_hdrsize + comp_len;
2051 incr = v1_hdrsize + comp_len;
2051 if (offsets)
2052 if (offsets)
2052 offsets[len] = data + pos;
2053 offsets[len] = data + pos;
2053 len++;
2054 len++;
2054 pos += incr;
2055 pos += incr;
2055 }
2056 }
2056
2057
2057 if (pos != end) {
2058 if (pos != end) {
2058 if (!PyErr_Occurred())
2059 if (!PyErr_Occurred())
2059 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2060 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2060 return -1;
2061 return -1;
2061 }
2062 }
2062
2063
2063 return len;
2064 return len;
2064 }
2065 }
2065
2066
2066 static int index_init(indexObject *self, PyObject *args)
2067 static int index_init(indexObject *self, PyObject *args)
2067 {
2068 {
2068 PyObject *data_obj, *inlined_obj;
2069 PyObject *data_obj, *inlined_obj;
2069 Py_ssize_t size;
2070 Py_ssize_t size;
2070
2071
2071 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2072 /* Initialize before argument-checking to avoid index_dealloc() crash. */
2072 self->raw_length = 0;
2073 self->raw_length = 0;
2073 self->added = NULL;
2074 self->added = NULL;
2074 self->cache = NULL;
2075 self->cache = NULL;
2075 self->data = NULL;
2076 self->data = NULL;
2076 self->headrevs = NULL;
2077 self->headrevs = NULL;
2077 self->filteredrevs = Py_None;
2078 self->filteredrevs = Py_None;
2078 Py_INCREF(Py_None);
2079 Py_INCREF(Py_None);
2079 self->nt = NULL;
2080 self->nt = NULL;
2080 self->offsets = NULL;
2081 self->offsets = NULL;
2081
2082
2082 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2083 if (!PyArg_ParseTuple(args, "OO", &data_obj, &inlined_obj))
2083 return -1;
2084 return -1;
2084 if (!PyString_Check(data_obj)) {
2085 if (!PyString_Check(data_obj)) {
2085 PyErr_SetString(PyExc_TypeError, "data is not a string");
2086 PyErr_SetString(PyExc_TypeError, "data is not a string");
2086 return -1;
2087 return -1;
2087 }
2088 }
2088 size = PyString_GET_SIZE(data_obj);
2089 size = PyString_GET_SIZE(data_obj);
2089
2090
2090 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2091 self->inlined = inlined_obj && PyObject_IsTrue(inlined_obj);
2091 self->data = data_obj;
2092 self->data = data_obj;
2092
2093
2093 self->ntlength = self->ntcapacity = 0;
2094 self->ntlength = self->ntcapacity = 0;
2094 self->ntdepth = self->ntsplits = 0;
2095 self->ntdepth = self->ntsplits = 0;
2095 self->ntlookups = self->ntmisses = 0;
2096 self->ntlookups = self->ntmisses = 0;
2096 self->ntrev = -1;
2097 self->ntrev = -1;
2097 Py_INCREF(self->data);
2098 Py_INCREF(self->data);
2098
2099
2099 if (self->inlined) {
2100 if (self->inlined) {
2100 Py_ssize_t len = inline_scan(self, NULL);
2101 Py_ssize_t len = inline_scan(self, NULL);
2101 if (len == -1)
2102 if (len == -1)
2102 goto bail;
2103 goto bail;
2103 self->raw_length = len;
2104 self->raw_length = len;
2104 self->length = len + 1;
2105 self->length = len + 1;
2105 } else {
2106 } else {
2106 if (size % v1_hdrsize) {
2107 if (size % v1_hdrsize) {
2107 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2108 PyErr_SetString(PyExc_ValueError, "corrupt index file");
2108 goto bail;
2109 goto bail;
2109 }
2110 }
2110 self->raw_length = size / v1_hdrsize;
2111 self->raw_length = size / v1_hdrsize;
2111 self->length = self->raw_length + 1;
2112 self->length = self->raw_length + 1;
2112 }
2113 }
2113
2114
2114 return 0;
2115 return 0;
2115 bail:
2116 bail:
2116 return -1;
2117 return -1;
2117 }
2118 }
2118
2119
2119 static PyObject *index_nodemap(indexObject *self)
2120 static PyObject *index_nodemap(indexObject *self)
2120 {
2121 {
2121 Py_INCREF(self);
2122 Py_INCREF(self);
2122 return (PyObject *)self;
2123 return (PyObject *)self;
2123 }
2124 }
2124
2125
2125 static void index_dealloc(indexObject *self)
2126 static void index_dealloc(indexObject *self)
2126 {
2127 {
2127 _index_clearcaches(self);
2128 _index_clearcaches(self);
2128 Py_XDECREF(self->filteredrevs);
2129 Py_XDECREF(self->filteredrevs);
2129 Py_XDECREF(self->data);
2130 Py_XDECREF(self->data);
2130 Py_XDECREF(self->added);
2131 Py_XDECREF(self->added);
2131 PyObject_Del(self);
2132 PyObject_Del(self);
2132 }
2133 }
2133
2134
2134 static PySequenceMethods index_sequence_methods = {
2135 static PySequenceMethods index_sequence_methods = {
2135 (lenfunc)index_length, /* sq_length */
2136 (lenfunc)index_length, /* sq_length */
2136 0, /* sq_concat */
2137 0, /* sq_concat */
2137 0, /* sq_repeat */
2138 0, /* sq_repeat */
2138 (ssizeargfunc)index_get, /* sq_item */
2139 (ssizeargfunc)index_get, /* sq_item */
2139 0, /* sq_slice */
2140 0, /* sq_slice */
2140 0, /* sq_ass_item */
2141 0, /* sq_ass_item */
2141 0, /* sq_ass_slice */
2142 0, /* sq_ass_slice */
2142 (objobjproc)index_contains, /* sq_contains */
2143 (objobjproc)index_contains, /* sq_contains */
2143 };
2144 };
2144
2145
2145 static PyMappingMethods index_mapping_methods = {
2146 static PyMappingMethods index_mapping_methods = {
2146 (lenfunc)index_length, /* mp_length */
2147 (lenfunc)index_length, /* mp_length */
2147 (binaryfunc)index_getitem, /* mp_subscript */
2148 (binaryfunc)index_getitem, /* mp_subscript */
2148 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2149 (objobjargproc)index_assign_subscript, /* mp_ass_subscript */
2149 };
2150 };
2150
2151
2151 static PyMethodDef index_methods[] = {
2152 static PyMethodDef index_methods[] = {
2152 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2153 {"ancestors", (PyCFunction)index_ancestors, METH_VARARGS,
2153 "return the gca set of the given revs"},
2154 "return the gca set of the given revs"},
2154 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2155 {"commonancestorsheads", (PyCFunction)index_commonancestorsheads,
2155 METH_VARARGS,
2156 METH_VARARGS,
2156 "return the heads of the common ancestors of the given revs"},
2157 "return the heads of the common ancestors of the given revs"},
2157 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2158 {"clearcaches", (PyCFunction)index_clearcaches, METH_NOARGS,
2158 "clear the index caches"},
2159 "clear the index caches"},
2159 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2160 {"get", (PyCFunction)index_m_get, METH_VARARGS,
2160 "get an index entry"},
2161 "get an index entry"},
2161 {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
2162 {"computephases", (PyCFunction)compute_phases, METH_VARARGS,
2162 "compute phases"},
2163 "compute phases"},
2163 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2164 {"headrevs", (PyCFunction)index_headrevs, METH_VARARGS,
2164 "get head revisions"}, /* Can do filtering since 3.2 */
2165 "get head revisions"}, /* Can do filtering since 3.2 */
2165 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2166 {"headrevsfiltered", (PyCFunction)index_headrevs, METH_VARARGS,
2166 "get filtered head revisions"}, /* Can always do filtering */
2167 "get filtered head revisions"}, /* Can always do filtering */
2167 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2168 {"insert", (PyCFunction)index_insert, METH_VARARGS,
2168 "insert an index entry"},
2169 "insert an index entry"},
2169 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2170 {"partialmatch", (PyCFunction)index_partialmatch, METH_VARARGS,
2170 "match a potentially ambiguous node ID"},
2171 "match a potentially ambiguous node ID"},
2171 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2172 {"stats", (PyCFunction)index_stats, METH_NOARGS,
2172 "stats for the index"},
2173 "stats for the index"},
2173 {NULL} /* Sentinel */
2174 {NULL} /* Sentinel */
2174 };
2175 };
2175
2176
2176 static PyGetSetDef index_getset[] = {
2177 static PyGetSetDef index_getset[] = {
2177 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2178 {"nodemap", (getter)index_nodemap, NULL, "nodemap", NULL},
2178 {NULL} /* Sentinel */
2179 {NULL} /* Sentinel */
2179 };
2180 };
2180
2181
2181 static PyTypeObject indexType = {
2182 static PyTypeObject indexType = {
2182 PyObject_HEAD_INIT(NULL)
2183 PyObject_HEAD_INIT(NULL)
2183 0, /* ob_size */
2184 0, /* ob_size */
2184 "parsers.index", /* tp_name */
2185 "parsers.index", /* tp_name */
2185 sizeof(indexObject), /* tp_basicsize */
2186 sizeof(indexObject), /* tp_basicsize */
2186 0, /* tp_itemsize */
2187 0, /* tp_itemsize */
2187 (destructor)index_dealloc, /* tp_dealloc */
2188 (destructor)index_dealloc, /* tp_dealloc */
2188 0, /* tp_print */
2189 0, /* tp_print */
2189 0, /* tp_getattr */
2190 0, /* tp_getattr */
2190 0, /* tp_setattr */
2191 0, /* tp_setattr */
2191 0, /* tp_compare */
2192 0, /* tp_compare */
2192 0, /* tp_repr */
2193 0, /* tp_repr */
2193 0, /* tp_as_number */
2194 0, /* tp_as_number */
2194 &index_sequence_methods, /* tp_as_sequence */
2195 &index_sequence_methods, /* tp_as_sequence */
2195 &index_mapping_methods, /* tp_as_mapping */
2196 &index_mapping_methods, /* tp_as_mapping */
2196 0, /* tp_hash */
2197 0, /* tp_hash */
2197 0, /* tp_call */
2198 0, /* tp_call */
2198 0, /* tp_str */
2199 0, /* tp_str */
2199 0, /* tp_getattro */
2200 0, /* tp_getattro */
2200 0, /* tp_setattro */
2201 0, /* tp_setattro */
2201 0, /* tp_as_buffer */
2202 0, /* tp_as_buffer */
2202 Py_TPFLAGS_DEFAULT, /* tp_flags */
2203 Py_TPFLAGS_DEFAULT, /* tp_flags */
2203 "revlog index", /* tp_doc */
2204 "revlog index", /* tp_doc */
2204 0, /* tp_traverse */
2205 0, /* tp_traverse */
2205 0, /* tp_clear */
2206 0, /* tp_clear */
2206 0, /* tp_richcompare */
2207 0, /* tp_richcompare */
2207 0, /* tp_weaklistoffset */
2208 0, /* tp_weaklistoffset */
2208 0, /* tp_iter */
2209 0, /* tp_iter */
2209 0, /* tp_iternext */
2210 0, /* tp_iternext */
2210 index_methods, /* tp_methods */
2211 index_methods, /* tp_methods */
2211 0, /* tp_members */
2212 0, /* tp_members */
2212 index_getset, /* tp_getset */
2213 index_getset, /* tp_getset */
2213 0, /* tp_base */
2214 0, /* tp_base */
2214 0, /* tp_dict */
2215 0, /* tp_dict */
2215 0, /* tp_descr_get */
2216 0, /* tp_descr_get */
2216 0, /* tp_descr_set */
2217 0, /* tp_descr_set */
2217 0, /* tp_dictoffset */
2218 0, /* tp_dictoffset */
2218 (initproc)index_init, /* tp_init */
2219 (initproc)index_init, /* tp_init */
2219 0, /* tp_alloc */
2220 0, /* tp_alloc */
2220 };
2221 };
2221
2222
2222 /*
2223 /*
2223 * returns a tuple of the form (index, index, cache) with elements as
2224 * returns a tuple of the form (index, index, cache) with elements as
2224 * follows:
2225 * follows:
2225 *
2226 *
2226 * index: an index object that lazily parses RevlogNG records
2227 * index: an index object that lazily parses RevlogNG records
2227 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2228 * cache: if data is inlined, a tuple (index_file_content, 0), else None
2228 *
2229 *
2229 * added complications are for backwards compatibility
2230 * added complications are for backwards compatibility
2230 */
2231 */
2231 static PyObject *parse_index2(PyObject *self, PyObject *args)
2232 static PyObject *parse_index2(PyObject *self, PyObject *args)
2232 {
2233 {
2233 PyObject *tuple = NULL, *cache = NULL;
2234 PyObject *tuple = NULL, *cache = NULL;
2234 indexObject *idx;
2235 indexObject *idx;
2235 int ret;
2236 int ret;
2236
2237
2237 idx = PyObject_New(indexObject, &indexType);
2238 idx = PyObject_New(indexObject, &indexType);
2238 if (idx == NULL)
2239 if (idx == NULL)
2239 goto bail;
2240 goto bail;
2240
2241
2241 ret = index_init(idx, args);
2242 ret = index_init(idx, args);
2242 if (ret == -1)
2243 if (ret == -1)
2243 goto bail;
2244 goto bail;
2244
2245
2245 if (idx->inlined) {
2246 if (idx->inlined) {
2246 cache = Py_BuildValue("iO", 0, idx->data);
2247 cache = Py_BuildValue("iO", 0, idx->data);
2247 if (cache == NULL)
2248 if (cache == NULL)
2248 goto bail;
2249 goto bail;
2249 } else {
2250 } else {
2250 cache = Py_None;
2251 cache = Py_None;
2251 Py_INCREF(cache);
2252 Py_INCREF(cache);
2252 }
2253 }
2253
2254
2254 tuple = Py_BuildValue("NN", idx, cache);
2255 tuple = Py_BuildValue("NN", idx, cache);
2255 if (!tuple)
2256 if (!tuple)
2256 goto bail;
2257 goto bail;
2257 return tuple;
2258 return tuple;
2258
2259
2259 bail:
2260 bail:
2260 Py_XDECREF(idx);
2261 Py_XDECREF(idx);
2261 Py_XDECREF(cache);
2262 Py_XDECREF(cache);
2262 Py_XDECREF(tuple);
2263 Py_XDECREF(tuple);
2263 return NULL;
2264 return NULL;
2264 }
2265 }
2265
2266
2266 #define BUMPED_FIX 1
2267 #define BUMPED_FIX 1
2267 #define USING_SHA_256 2
2268 #define USING_SHA_256 2
2268
2269
2269 static PyObject *readshas(
2270 static PyObject *readshas(
2270 const char *source, unsigned char num, Py_ssize_t hashwidth)
2271 const char *source, unsigned char num, Py_ssize_t hashwidth)
2271 {
2272 {
2272 int i;
2273 int i;
2273 PyObject *list = PyTuple_New(num);
2274 PyObject *list = PyTuple_New(num);
2274 if (list == NULL) {
2275 if (list == NULL) {
2275 return NULL;
2276 return NULL;
2276 }
2277 }
2277 for (i = 0; i < num; i++) {
2278 for (i = 0; i < num; i++) {
2278 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2279 PyObject *hash = PyString_FromStringAndSize(source, hashwidth);
2279 if (hash == NULL) {
2280 if (hash == NULL) {
2280 Py_DECREF(list);
2281 Py_DECREF(list);
2281 return NULL;
2282 return NULL;
2282 }
2283 }
2283 PyTuple_SetItem(list, i, hash);
2284 PyTuple_SetItem(list, i, hash);
2284 source += hashwidth;
2285 source += hashwidth;
2285 }
2286 }
2286 return list;
2287 return list;
2287 }
2288 }
2288
2289
2289 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2290 static PyObject *fm1readmarker(const char *data, uint32_t *msize)
2290 {
2291 {
2291 const char *meta;
2292 const char *meta;
2292
2293
2293 double mtime;
2294 double mtime;
2294 int16_t tz;
2295 int16_t tz;
2295 uint16_t flags;
2296 uint16_t flags;
2296 unsigned char nsuccs, nparents, nmetadata;
2297 unsigned char nsuccs, nparents, nmetadata;
2297 Py_ssize_t hashwidth = 20;
2298 Py_ssize_t hashwidth = 20;
2298
2299
2299 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2300 PyObject *prec = NULL, *parents = NULL, *succs = NULL;
2300 PyObject *metadata = NULL, *ret = NULL;
2301 PyObject *metadata = NULL, *ret = NULL;
2301 int i;
2302 int i;
2302
2303
2303 *msize = getbe32(data);
2304 *msize = getbe32(data);
2304 data += 4;
2305 data += 4;
2305 mtime = getbefloat64(data);
2306 mtime = getbefloat64(data);
2306 data += 8;
2307 data += 8;
2307 tz = getbeint16(data);
2308 tz = getbeint16(data);
2308 data += 2;
2309 data += 2;
2309 flags = getbeuint16(data);
2310 flags = getbeuint16(data);
2310 data += 2;
2311 data += 2;
2311
2312
2312 if (flags & USING_SHA_256) {
2313 if (flags & USING_SHA_256) {
2313 hashwidth = 32;
2314 hashwidth = 32;
2314 }
2315 }
2315
2316
2316 nsuccs = (unsigned char)(*data++);
2317 nsuccs = (unsigned char)(*data++);
2317 nparents = (unsigned char)(*data++);
2318 nparents = (unsigned char)(*data++);
2318 nmetadata = (unsigned char)(*data++);
2319 nmetadata = (unsigned char)(*data++);
2319
2320
2320 prec = PyString_FromStringAndSize(data, hashwidth);
2321 prec = PyString_FromStringAndSize(data, hashwidth);
2321 data += hashwidth;
2322 data += hashwidth;
2322 if (prec == NULL) {
2323 if (prec == NULL) {
2323 goto bail;
2324 goto bail;
2324 }
2325 }
2325
2326
2326 succs = readshas(data, nsuccs, hashwidth);
2327 succs = readshas(data, nsuccs, hashwidth);
2327 if (succs == NULL) {
2328 if (succs == NULL) {
2328 goto bail;
2329 goto bail;
2329 }
2330 }
2330 data += nsuccs * hashwidth;
2331 data += nsuccs * hashwidth;
2331
2332
2332 if (nparents == 1 || nparents == 2) {
2333 if (nparents == 1 || nparents == 2) {
2333 parents = readshas(data, nparents, hashwidth);
2334 parents = readshas(data, nparents, hashwidth);
2334 if (parents == NULL) {
2335 if (parents == NULL) {
2335 goto bail;
2336 goto bail;
2336 }
2337 }
2337 data += nparents * hashwidth;
2338 data += nparents * hashwidth;
2338 } else {
2339 } else {
2339 parents = Py_None;
2340 parents = Py_None;
2340 }
2341 }
2341
2342
2342 meta = data + (2 * nmetadata);
2343 meta = data + (2 * nmetadata);
2343 metadata = PyTuple_New(nmetadata);
2344 metadata = PyTuple_New(nmetadata);
2344 if (metadata == NULL) {
2345 if (metadata == NULL) {
2345 goto bail;
2346 goto bail;
2346 }
2347 }
2347 for (i = 0; i < nmetadata; i++) {
2348 for (i = 0; i < nmetadata; i++) {
2348 PyObject *tmp, *left = NULL, *right = NULL;
2349 PyObject *tmp, *left = NULL, *right = NULL;
2349 Py_ssize_t metasize = (unsigned char)(*data++);
2350 Py_ssize_t metasize = (unsigned char)(*data++);
2350 left = PyString_FromStringAndSize(meta, metasize);
2351 left = PyString_FromStringAndSize(meta, metasize);
2351 meta += metasize;
2352 meta += metasize;
2352 metasize = (unsigned char)(*data++);
2353 metasize = (unsigned char)(*data++);
2353 right = PyString_FromStringAndSize(meta, metasize);
2354 right = PyString_FromStringAndSize(meta, metasize);
2354 meta += metasize;
2355 meta += metasize;
2355 if (!left || !right) {
2356 if (!left || !right) {
2356 Py_XDECREF(left);
2357 Py_XDECREF(left);
2357 Py_XDECREF(right);
2358 Py_XDECREF(right);
2358 goto bail;
2359 goto bail;
2359 }
2360 }
2360 tmp = PyTuple_Pack(2, left, right);
2361 tmp = PyTuple_Pack(2, left, right);
2361 Py_DECREF(left);
2362 Py_DECREF(left);
2362 Py_DECREF(right);
2363 Py_DECREF(right);
2363 if (!tmp) {
2364 if (!tmp) {
2364 goto bail;
2365 goto bail;
2365 }
2366 }
2366 PyTuple_SetItem(metadata, i, tmp);
2367 PyTuple_SetItem(metadata, i, tmp);
2367 }
2368 }
2368 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2369 ret = Py_BuildValue("(OOHO(di)O)", prec, succs, flags,
2369 metadata, mtime, (int)tz * 60, parents);
2370 metadata, mtime, (int)tz * 60, parents);
2370 bail:
2371 bail:
2371 Py_XDECREF(prec);
2372 Py_XDECREF(prec);
2372 Py_XDECREF(succs);
2373 Py_XDECREF(succs);
2373 Py_XDECREF(metadata);
2374 Py_XDECREF(metadata);
2374 if (parents != Py_None)
2375 if (parents != Py_None)
2375 Py_XDECREF(parents);
2376 Py_XDECREF(parents);
2376 return ret;
2377 return ret;
2377 }
2378 }
2378
2379
2379
2380
2380 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2381 static PyObject *fm1readmarkers(PyObject *self, PyObject *args) {
2381 const char *data;
2382 const char *data;
2382 Py_ssize_t datalen;
2383 Py_ssize_t datalen;
2383 /* only unsigned long because python 2.4, should be Py_ssize_t */
2384 /* only unsigned long because python 2.4, should be Py_ssize_t */
2384 unsigned long offset, stop;
2385 unsigned long offset, stop;
2385 PyObject *markers = NULL;
2386 PyObject *markers = NULL;
2386
2387
2387 /* replace kk with nn when we drop Python 2.4 */
2388 /* replace kk with nn when we drop Python 2.4 */
2388 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2389 if (!PyArg_ParseTuple(args, "s#kk", &data, &datalen, &offset, &stop)) {
2389 return NULL;
2390 return NULL;
2390 }
2391 }
2391 data += offset;
2392 data += offset;
2392 markers = PyList_New(0);
2393 markers = PyList_New(0);
2393 if (!markers) {
2394 if (!markers) {
2394 return NULL;
2395 return NULL;
2395 }
2396 }
2396 while (offset < stop) {
2397 while (offset < stop) {
2397 uint32_t msize;
2398 uint32_t msize;
2398 int error;
2399 int error;
2399 PyObject *record = fm1readmarker(data, &msize);
2400 PyObject *record = fm1readmarker(data, &msize);
2400 if (!record) {
2401 if (!record) {
2401 goto bail;
2402 goto bail;
2402 }
2403 }
2403 error = PyList_Append(markers, record);
2404 error = PyList_Append(markers, record);
2404 Py_DECREF(record);
2405 Py_DECREF(record);
2405 if (error) {
2406 if (error) {
2406 goto bail;
2407 goto bail;
2407 }
2408 }
2408 data += msize;
2409 data += msize;
2409 offset += msize;
2410 offset += msize;
2410 }
2411 }
2411 return markers;
2412 return markers;
2412 bail:
2413 bail:
2413 Py_DECREF(markers);
2414 Py_DECREF(markers);
2414 return NULL;
2415 return NULL;
2415 }
2416 }
2416
2417
2417 static char parsers_doc[] = "Efficient content parsing.";
2418 static char parsers_doc[] = "Efficient content parsing.";
2418
2419
2419 PyObject *encodedir(PyObject *self, PyObject *args);
2420 PyObject *encodedir(PyObject *self, PyObject *args);
2420 PyObject *pathencode(PyObject *self, PyObject *args);
2421 PyObject *pathencode(PyObject *self, PyObject *args);
2421 PyObject *lowerencode(PyObject *self, PyObject *args);
2422 PyObject *lowerencode(PyObject *self, PyObject *args);
2422
2423
2423 static PyMethodDef methods[] = {
2424 static PyMethodDef methods[] = {
2424 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2425 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
2425 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2426 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
2426 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2427 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
2427 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2428 {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"},
2428 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2429 {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"},
2429 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2430 {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"},
2430 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2431 {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"},
2431 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2432 {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},
2432 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2433 {"fm1readmarkers", fm1readmarkers, METH_VARARGS,
2433 "parse v1 obsolete markers\n"},
2434 "parse v1 obsolete markers\n"},
2434 {NULL, NULL}
2435 {NULL, NULL}
2435 };
2436 };
2436
2437
2437 void dirs_module_init(PyObject *mod);
2438 void dirs_module_init(PyObject *mod);
2438 void manifest_module_init(PyObject *mod);
2439 void manifest_module_init(PyObject *mod);
2439
2440
2440 static void module_init(PyObject *mod)
2441 static void module_init(PyObject *mod)
2441 {
2442 {
2442 /* This module constant has two purposes. First, it lets us unit test
2443 /* This module constant has two purposes. First, it lets us unit test
2443 * the ImportError raised without hard-coding any error text. This
2444 * the ImportError raised without hard-coding any error text. This
2444 * means we can change the text in the future without breaking tests,
2445 * means we can change the text in the future without breaking tests,
2445 * even across changesets without a recompile. Second, its presence
2446 * even across changesets without a recompile. Second, its presence
2446 * can be used to determine whether the version-checking logic is
2447 * can be used to determine whether the version-checking logic is
2447 * present, which also helps in testing across changesets without a
2448 * present, which also helps in testing across changesets without a
2448 * recompile. Note that this means the pure-Python version of parsers
2449 * recompile. Note that this means the pure-Python version of parsers
2449 * should not have this module constant. */
2450 * should not have this module constant. */
2450 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2451 PyModule_AddStringConstant(mod, "versionerrortext", versionerrortext);
2451
2452
2452 dirs_module_init(mod);
2453 dirs_module_init(mod);
2453 manifest_module_init(mod);
2454 manifest_module_init(mod);
2454
2455
2455 indexType.tp_new = PyType_GenericNew;
2456 indexType.tp_new = PyType_GenericNew;
2456 if (PyType_Ready(&indexType) < 0 ||
2457 if (PyType_Ready(&indexType) < 0 ||
2457 PyType_Ready(&dirstateTupleType) < 0)
2458 PyType_Ready(&dirstateTupleType) < 0)
2458 return;
2459 return;
2459 Py_INCREF(&indexType);
2460 Py_INCREF(&indexType);
2460 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2461 PyModule_AddObject(mod, "index", (PyObject *)&indexType);
2461 Py_INCREF(&dirstateTupleType);
2462 Py_INCREF(&dirstateTupleType);
2462 PyModule_AddObject(mod, "dirstatetuple",
2463 PyModule_AddObject(mod, "dirstatetuple",
2463 (PyObject *)&dirstateTupleType);
2464 (PyObject *)&dirstateTupleType);
2464
2465
2465 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2466 nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0,
2466 -1, -1, -1, -1, nullid, 20);
2467 -1, -1, -1, -1, nullid, 20);
2467 if (nullentry)
2468 if (nullentry)
2468 PyObject_GC_UnTrack(nullentry);
2469 PyObject_GC_UnTrack(nullentry);
2469 }
2470 }
2470
2471
2471 static int check_python_version(void)
2472 static int check_python_version(void)
2472 {
2473 {
2473 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2474 PyObject *sys = PyImport_ImportModule("sys"), *ver;
2474 long hexversion;
2475 long hexversion;
2475 if (!sys)
2476 if (!sys)
2476 return -1;
2477 return -1;
2477 ver = PyObject_GetAttrString(sys, "hexversion");
2478 ver = PyObject_GetAttrString(sys, "hexversion");
2478 Py_DECREF(sys);
2479 Py_DECREF(sys);
2479 if (!ver)
2480 if (!ver)
2480 return -1;
2481 return -1;
2481 hexversion = PyInt_AsLong(ver);
2482 hexversion = PyInt_AsLong(ver);
2482 Py_DECREF(ver);
2483 Py_DECREF(ver);
2483 /* sys.hexversion is a 32-bit number by default, so the -1 case
2484 /* sys.hexversion is a 32-bit number by default, so the -1 case
2484 * should only occur in unusual circumstances (e.g. if sys.hexversion
2485 * should only occur in unusual circumstances (e.g. if sys.hexversion
2485 * is manually set to an invalid value). */
2486 * is manually set to an invalid value). */
2486 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2487 if ((hexversion == -1) || (hexversion >> 16 != PY_VERSION_HEX >> 16)) {
2487 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2488 PyErr_Format(PyExc_ImportError, "%s: The Mercurial extension "
2488 "modules were compiled with Python " PY_VERSION ", but "
2489 "modules were compiled with Python " PY_VERSION ", but "
2489 "Mercurial is currently using Python with sys.hexversion=%ld: "
2490 "Mercurial is currently using Python with sys.hexversion=%ld: "
2490 "Python %s\n at: %s", versionerrortext, hexversion,
2491 "Python %s\n at: %s", versionerrortext, hexversion,
2491 Py_GetVersion(), Py_GetProgramFullPath());
2492 Py_GetVersion(), Py_GetProgramFullPath());
2492 return -1;
2493 return -1;
2493 }
2494 }
2494 return 0;
2495 return 0;
2495 }
2496 }
2496
2497
2497 #ifdef IS_PY3K
2498 #ifdef IS_PY3K
2498 static struct PyModuleDef parsers_module = {
2499 static struct PyModuleDef parsers_module = {
2499 PyModuleDef_HEAD_INIT,
2500 PyModuleDef_HEAD_INIT,
2500 "parsers",
2501 "parsers",
2501 parsers_doc,
2502 parsers_doc,
2502 -1,
2503 -1,
2503 methods
2504 methods
2504 };
2505 };
2505
2506
2506 PyMODINIT_FUNC PyInit_parsers(void)
2507 PyMODINIT_FUNC PyInit_parsers(void)
2507 {
2508 {
2508 PyObject *mod;
2509 PyObject *mod;
2509
2510
2510 if (check_python_version() == -1)
2511 if (check_python_version() == -1)
2511 return;
2512 return;
2512 mod = PyModule_Create(&parsers_module);
2513 mod = PyModule_Create(&parsers_module);
2513 module_init(mod);
2514 module_init(mod);
2514 return mod;
2515 return mod;
2515 }
2516 }
2516 #else
2517 #else
2517 PyMODINIT_FUNC initparsers(void)
2518 PyMODINIT_FUNC initparsers(void)
2518 {
2519 {
2519 PyObject *mod;
2520 PyObject *mod;
2520
2521
2521 if (check_python_version() == -1)
2522 if (check_python_version() == -1)
2522 return;
2523 return;
2523 mod = Py_InitModule3("parsers", methods, parsers_doc);
2524 mod = Py_InitModule3("parsers", methods, parsers_doc);
2524 module_init(mod);
2525 module_init(mod);
2525 }
2526 }
2526 #endif
2527 #endif
General Comments 0
You need to be logged in to leave comments. Login now