##// END OF EJS Templates
dirs: port PyInt code to work on Python 3...
Gregory Szorc -
r30106:cb304874 default
parent child Browse files
Show More
@@ -1,294 +1,304 b''
1 /*
1 /*
2 dirs.c - dynamic directory diddling for dirstates
2 dirs.c - dynamic directory diddling for dirstates
3
3
4 Copyright 2013 Facebook
4 Copyright 2013 Facebook
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 #define PY_SSIZE_T_CLEAN
10 #define PY_SSIZE_T_CLEAN
11 #include <Python.h>
11 #include <Python.h>
12 #include "util.h"
12 #include "util.h"
13
13
14 #ifdef IS_PY3K
15 #define PYLONG_VALUE(o) ((PyLongObject *)o)->ob_digit[1]
16 #else
17 #define PYLONG_VALUE(o) PyInt_AS_LONG(o)
18 #endif
19
14 /*
20 /*
15 * This is a multiset of directory names, built from the files that
21 * This is a multiset of directory names, built from the files that
16 * appear in a dirstate or manifest.
22 * appear in a dirstate or manifest.
17 *
23 *
18 * A few implementation notes:
24 * A few implementation notes:
19 *
25 *
20 * We modify Python integers for refcounting, but those integers are
26 * We modify Python integers for refcounting, but those integers are
21 * never visible to Python code.
27 * never visible to Python code.
22 *
28 *
23 * We mutate strings in-place, but leave them immutable once they can
29 * We mutate strings in-place, but leave them immutable once they can
24 * be seen by Python code.
30 * be seen by Python code.
25 */
31 */
26 typedef struct {
32 typedef struct {
27 PyObject_HEAD
33 PyObject_HEAD
28 PyObject *dict;
34 PyObject *dict;
29 } dirsObject;
35 } dirsObject;
30
36
31 static inline Py_ssize_t _finddir(const char *path, Py_ssize_t pos)
37 static inline Py_ssize_t _finddir(const char *path, Py_ssize_t pos)
32 {
38 {
33 while (pos != -1) {
39 while (pos != -1) {
34 if (path[pos] == '/')
40 if (path[pos] == '/')
35 break;
41 break;
36 pos -= 1;
42 pos -= 1;
37 }
43 }
38
44
39 return pos;
45 return pos;
40 }
46 }
41
47
42 static int _addpath(PyObject *dirs, PyObject *path)
48 static int _addpath(PyObject *dirs, PyObject *path)
43 {
49 {
44 const char *cpath = PyBytes_AS_STRING(path);
50 const char *cpath = PyBytes_AS_STRING(path);
45 Py_ssize_t pos = PyBytes_GET_SIZE(path);
51 Py_ssize_t pos = PyBytes_GET_SIZE(path);
46 PyObject *key = NULL;
52 PyObject *key = NULL;
47 int ret = -1;
53 int ret = -1;
48
54
49 while ((pos = _finddir(cpath, pos - 1)) != -1) {
55 while ((pos = _finddir(cpath, pos - 1)) != -1) {
50 PyObject *val;
56 PyObject *val;
51
57
52 /* It's likely that every prefix already has an entry
58 /* It's likely that every prefix already has an entry
53 in our dict. Try to avoid allocating and
59 in our dict. Try to avoid allocating and
54 deallocating a string for each prefix we check. */
60 deallocating a string for each prefix we check. */
55 if (key != NULL)
61 if (key != NULL)
56 ((PyBytesObject *)key)->ob_shash = -1;
62 ((PyBytesObject *)key)->ob_shash = -1;
57 else {
63 else {
58 /* Force Python to not reuse a small shared string. */
64 /* Force Python to not reuse a small shared string. */
59 key = PyBytes_FromStringAndSize(cpath,
65 key = PyBytes_FromStringAndSize(cpath,
60 pos < 2 ? 2 : pos);
66 pos < 2 ? 2 : pos);
61 if (key == NULL)
67 if (key == NULL)
62 goto bail;
68 goto bail;
63 }
69 }
64 Py_SIZE(key) = pos;
70 Py_SIZE(key) = pos;
65 ((PyBytesObject *)key)->ob_sval[pos] = '\0';
71 ((PyBytesObject *)key)->ob_sval[pos] = '\0';
66
72
67 val = PyDict_GetItem(dirs, key);
73 val = PyDict_GetItem(dirs, key);
68 if (val != NULL) {
74 if (val != NULL) {
69 PyInt_AS_LONG(val) += 1;
75 PYLONG_VALUE(val) += 1;
70 break;
76 break;
71 }
77 }
72
78
73 /* Force Python to not reuse a small shared int. */
79 /* Force Python to not reuse a small shared int. */
80 #ifdef IS_PY3K
81 val = PyLong_FromLong(0x1eadbeef);
82 #else
74 val = PyInt_FromLong(0x1eadbeef);
83 val = PyInt_FromLong(0x1eadbeef);
84 #endif
75
85
76 if (val == NULL)
86 if (val == NULL)
77 goto bail;
87 goto bail;
78
88
79 PyInt_AS_LONG(val) = 1;
89 PYLONG_VALUE(val) = 1;
80 ret = PyDict_SetItem(dirs, key, val);
90 ret = PyDict_SetItem(dirs, key, val);
81 Py_DECREF(val);
91 Py_DECREF(val);
82 if (ret == -1)
92 if (ret == -1)
83 goto bail;
93 goto bail;
84 Py_CLEAR(key);
94 Py_CLEAR(key);
85 }
95 }
86 ret = 0;
96 ret = 0;
87
97
88 bail:
98 bail:
89 Py_XDECREF(key);
99 Py_XDECREF(key);
90
100
91 return ret;
101 return ret;
92 }
102 }
93
103
94 static int _delpath(PyObject *dirs, PyObject *path)
104 static int _delpath(PyObject *dirs, PyObject *path)
95 {
105 {
96 char *cpath = PyBytes_AS_STRING(path);
106 char *cpath = PyBytes_AS_STRING(path);
97 Py_ssize_t pos = PyBytes_GET_SIZE(path);
107 Py_ssize_t pos = PyBytes_GET_SIZE(path);
98 PyObject *key = NULL;
108 PyObject *key = NULL;
99 int ret = -1;
109 int ret = -1;
100
110
101 while ((pos = _finddir(cpath, pos - 1)) != -1) {
111 while ((pos = _finddir(cpath, pos - 1)) != -1) {
102 PyObject *val;
112 PyObject *val;
103
113
104 key = PyBytes_FromStringAndSize(cpath, pos);
114 key = PyBytes_FromStringAndSize(cpath, pos);
105
115
106 if (key == NULL)
116 if (key == NULL)
107 goto bail;
117 goto bail;
108
118
109 val = PyDict_GetItem(dirs, key);
119 val = PyDict_GetItem(dirs, key);
110 if (val == NULL) {
120 if (val == NULL) {
111 PyErr_SetString(PyExc_ValueError,
121 PyErr_SetString(PyExc_ValueError,
112 "expected a value, found none");
122 "expected a value, found none");
113 goto bail;
123 goto bail;
114 }
124 }
115
125
116 if (--PyInt_AS_LONG(val) <= 0) {
126 if (--PYLONG_VALUE(val) <= 0) {
117 if (PyDict_DelItem(dirs, key) == -1)
127 if (PyDict_DelItem(dirs, key) == -1)
118 goto bail;
128 goto bail;
119 } else
129 } else
120 break;
130 break;
121 Py_CLEAR(key);
131 Py_CLEAR(key);
122 }
132 }
123 ret = 0;
133 ret = 0;
124
134
125 bail:
135 bail:
126 Py_XDECREF(key);
136 Py_XDECREF(key);
127
137
128 return ret;
138 return ret;
129 }
139 }
130
140
131 static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar)
141 static int dirs_fromdict(PyObject *dirs, PyObject *source, char skipchar)
132 {
142 {
133 PyObject *key, *value;
143 PyObject *key, *value;
134 Py_ssize_t pos = 0;
144 Py_ssize_t pos = 0;
135
145
136 while (PyDict_Next(source, &pos, &key, &value)) {
146 while (PyDict_Next(source, &pos, &key, &value)) {
137 if (!PyBytes_Check(key)) {
147 if (!PyBytes_Check(key)) {
138 PyErr_SetString(PyExc_TypeError, "expected string key");
148 PyErr_SetString(PyExc_TypeError, "expected string key");
139 return -1;
149 return -1;
140 }
150 }
141 if (skipchar) {
151 if (skipchar) {
142 if (!dirstate_tuple_check(value)) {
152 if (!dirstate_tuple_check(value)) {
143 PyErr_SetString(PyExc_TypeError,
153 PyErr_SetString(PyExc_TypeError,
144 "expected a dirstate tuple");
154 "expected a dirstate tuple");
145 return -1;
155 return -1;
146 }
156 }
147 if (((dirstateTupleObject *)value)->state == skipchar)
157 if (((dirstateTupleObject *)value)->state == skipchar)
148 continue;
158 continue;
149 }
159 }
150
160
151 if (_addpath(dirs, key) == -1)
161 if (_addpath(dirs, key) == -1)
152 return -1;
162 return -1;
153 }
163 }
154
164
155 return 0;
165 return 0;
156 }
166 }
157
167
158 static int dirs_fromiter(PyObject *dirs, PyObject *source)
168 static int dirs_fromiter(PyObject *dirs, PyObject *source)
159 {
169 {
160 PyObject *iter, *item = NULL;
170 PyObject *iter, *item = NULL;
161 int ret;
171 int ret;
162
172
163 iter = PyObject_GetIter(source);
173 iter = PyObject_GetIter(source);
164 if (iter == NULL)
174 if (iter == NULL)
165 return -1;
175 return -1;
166
176
167 while ((item = PyIter_Next(iter)) != NULL) {
177 while ((item = PyIter_Next(iter)) != NULL) {
168 if (!PyBytes_Check(item)) {
178 if (!PyBytes_Check(item)) {
169 PyErr_SetString(PyExc_TypeError, "expected string");
179 PyErr_SetString(PyExc_TypeError, "expected string");
170 break;
180 break;
171 }
181 }
172
182
173 if (_addpath(dirs, item) == -1)
183 if (_addpath(dirs, item) == -1)
174 break;
184 break;
175 Py_CLEAR(item);
185 Py_CLEAR(item);
176 }
186 }
177
187
178 ret = PyErr_Occurred() ? -1 : 0;
188 ret = PyErr_Occurred() ? -1 : 0;
179 Py_DECREF(iter);
189 Py_DECREF(iter);
180 Py_XDECREF(item);
190 Py_XDECREF(item);
181 return ret;
191 return ret;
182 }
192 }
183
193
184 /*
194 /*
185 * Calculate a refcounted set of directory names for the files in a
195 * Calculate a refcounted set of directory names for the files in a
186 * dirstate.
196 * dirstate.
187 */
197 */
188 static int dirs_init(dirsObject *self, PyObject *args)
198 static int dirs_init(dirsObject *self, PyObject *args)
189 {
199 {
190 PyObject *dirs = NULL, *source = NULL;
200 PyObject *dirs = NULL, *source = NULL;
191 char skipchar = 0;
201 char skipchar = 0;
192 int ret = -1;
202 int ret = -1;
193
203
194 self->dict = NULL;
204 self->dict = NULL;
195
205
196 if (!PyArg_ParseTuple(args, "|Oc:__init__", &source, &skipchar))
206 if (!PyArg_ParseTuple(args, "|Oc:__init__", &source, &skipchar))
197 return -1;
207 return -1;
198
208
199 dirs = PyDict_New();
209 dirs = PyDict_New();
200
210
201 if (dirs == NULL)
211 if (dirs == NULL)
202 return -1;
212 return -1;
203
213
204 if (source == NULL)
214 if (source == NULL)
205 ret = 0;
215 ret = 0;
206 else if (PyDict_Check(source))
216 else if (PyDict_Check(source))
207 ret = dirs_fromdict(dirs, source, skipchar);
217 ret = dirs_fromdict(dirs, source, skipchar);
208 else if (skipchar)
218 else if (skipchar)
209 PyErr_SetString(PyExc_ValueError,
219 PyErr_SetString(PyExc_ValueError,
210 "skip character is only supported "
220 "skip character is only supported "
211 "with a dict source");
221 "with a dict source");
212 else
222 else
213 ret = dirs_fromiter(dirs, source);
223 ret = dirs_fromiter(dirs, source);
214
224
215 if (ret == -1)
225 if (ret == -1)
216 Py_XDECREF(dirs);
226 Py_XDECREF(dirs);
217 else
227 else
218 self->dict = dirs;
228 self->dict = dirs;
219
229
220 return ret;
230 return ret;
221 }
231 }
222
232
223 PyObject *dirs_addpath(dirsObject *self, PyObject *args)
233 PyObject *dirs_addpath(dirsObject *self, PyObject *args)
224 {
234 {
225 PyObject *path;
235 PyObject *path;
226
236
227 if (!PyArg_ParseTuple(args, "O!:addpath", &PyBytes_Type, &path))
237 if (!PyArg_ParseTuple(args, "O!:addpath", &PyBytes_Type, &path))
228 return NULL;
238 return NULL;
229
239
230 if (_addpath(self->dict, path) == -1)
240 if (_addpath(self->dict, path) == -1)
231 return NULL;
241 return NULL;
232
242
233 Py_RETURN_NONE;
243 Py_RETURN_NONE;
234 }
244 }
235
245
236 static PyObject *dirs_delpath(dirsObject *self, PyObject *args)
246 static PyObject *dirs_delpath(dirsObject *self, PyObject *args)
237 {
247 {
238 PyObject *path;
248 PyObject *path;
239
249
240 if (!PyArg_ParseTuple(args, "O!:delpath", &PyBytes_Type, &path))
250 if (!PyArg_ParseTuple(args, "O!:delpath", &PyBytes_Type, &path))
241 return NULL;
251 return NULL;
242
252
243 if (_delpath(self->dict, path) == -1)
253 if (_delpath(self->dict, path) == -1)
244 return NULL;
254 return NULL;
245
255
246 Py_RETURN_NONE;
256 Py_RETURN_NONE;
247 }
257 }
248
258
249 static int dirs_contains(dirsObject *self, PyObject *value)
259 static int dirs_contains(dirsObject *self, PyObject *value)
250 {
260 {
251 return PyBytes_Check(value) ? PyDict_Contains(self->dict, value) : 0;
261 return PyBytes_Check(value) ? PyDict_Contains(self->dict, value) : 0;
252 }
262 }
253
263
254 static void dirs_dealloc(dirsObject *self)
264 static void dirs_dealloc(dirsObject *self)
255 {
265 {
256 Py_XDECREF(self->dict);
266 Py_XDECREF(self->dict);
257 PyObject_Del(self);
267 PyObject_Del(self);
258 }
268 }
259
269
260 static PyObject *dirs_iter(dirsObject *self)
270 static PyObject *dirs_iter(dirsObject *self)
261 {
271 {
262 return PyObject_GetIter(self->dict);
272 return PyObject_GetIter(self->dict);
263 }
273 }
264
274
265 static PySequenceMethods dirs_sequence_methods;
275 static PySequenceMethods dirs_sequence_methods;
266
276
267 static PyMethodDef dirs_methods[] = {
277 static PyMethodDef dirs_methods[] = {
268 {"addpath", (PyCFunction)dirs_addpath, METH_VARARGS, "add a path"},
278 {"addpath", (PyCFunction)dirs_addpath, METH_VARARGS, "add a path"},
269 {"delpath", (PyCFunction)dirs_delpath, METH_VARARGS, "remove a path"},
279 {"delpath", (PyCFunction)dirs_delpath, METH_VARARGS, "remove a path"},
270 {NULL} /* Sentinel */
280 {NULL} /* Sentinel */
271 };
281 };
272
282
273 static PyTypeObject dirsType = { PyObject_HEAD_INIT(NULL) };
283 static PyTypeObject dirsType = { PyObject_HEAD_INIT(NULL) };
274
284
275 void dirs_module_init(PyObject *mod)
285 void dirs_module_init(PyObject *mod)
276 {
286 {
277 dirs_sequence_methods.sq_contains = (objobjproc)dirs_contains;
287 dirs_sequence_methods.sq_contains = (objobjproc)dirs_contains;
278 dirsType.tp_name = "parsers.dirs";
288 dirsType.tp_name = "parsers.dirs";
279 dirsType.tp_new = PyType_GenericNew;
289 dirsType.tp_new = PyType_GenericNew;
280 dirsType.tp_basicsize = sizeof(dirsObject);
290 dirsType.tp_basicsize = sizeof(dirsObject);
281 dirsType.tp_dealloc = (destructor)dirs_dealloc;
291 dirsType.tp_dealloc = (destructor)dirs_dealloc;
282 dirsType.tp_as_sequence = &dirs_sequence_methods;
292 dirsType.tp_as_sequence = &dirs_sequence_methods;
283 dirsType.tp_flags = Py_TPFLAGS_DEFAULT;
293 dirsType.tp_flags = Py_TPFLAGS_DEFAULT;
284 dirsType.tp_doc = "dirs";
294 dirsType.tp_doc = "dirs";
285 dirsType.tp_iter = (getiterfunc)dirs_iter;
295 dirsType.tp_iter = (getiterfunc)dirs_iter;
286 dirsType.tp_methods = dirs_methods;
296 dirsType.tp_methods = dirs_methods;
287 dirsType.tp_init = (initproc)dirs_init;
297 dirsType.tp_init = (initproc)dirs_init;
288
298
289 if (PyType_Ready(&dirsType) < 0)
299 if (PyType_Ready(&dirsType) < 0)
290 return;
300 return;
291 Py_INCREF(&dirsType);
301 Py_INCREF(&dirsType);
292
302
293 PyModule_AddObject(mod, "dirs", (PyObject *)&dirsType);
303 PyModule_AddObject(mod, "dirs", (PyObject *)&dirsType);
294 }
304 }
General Comments 0
You need to be logged in to leave comments. Login now