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