diff -r 7537e57f5dbd -r e250b8300e6e mercurial/parsers.c --- a/mercurial/parsers.c Tue May 27 17:10:28 2014 -0700 +++ b/mercurial/parsers.c Tue May 27 14:27:41 2014 -0700 @@ -153,6 +153,122 @@ return NULL; } +static inline dirstateTupleObject *make_dirstate_tuple(char state, int mode, + int size, int mtime) +{ + dirstateTupleObject *t = PyObject_New(dirstateTupleObject, + &dirstateTupleType); + if (!t) + return NULL; + t->state = state; + t->mode = mode; + t->size = size; + t->mtime = mtime; + return t; +} + +static PyObject *dirstate_tuple_new(PyTypeObject *subtype, PyObject *args, + PyObject *kwds) +{ + /* We do all the initialization here and not a tp_init function because + * dirstate_tuple is immutable. */ + dirstateTupleObject *t; + char state; + int size, mode, mtime; + if (!PyArg_ParseTuple(args, "ciii", &state, &mode, &size, &mtime)) + return NULL; + + t = (dirstateTupleObject *)subtype->tp_alloc(subtype, 1); + if (!t) + return NULL; + t->state = state; + t->mode = mode; + t->size = size; + t->mtime = mtime; + + return (PyObject *)t; +} + +static void dirstate_tuple_dealloc(PyObject *o) +{ + PyObject_Del(o); +} + +static Py_ssize_t dirstate_tuple_length(PyObject *o) +{ + return 4; +} + +static PyObject *dirstate_tuple_item(PyObject *o, Py_ssize_t i) +{ + dirstateTupleObject *t = (dirstateTupleObject *)o; + switch (i) { + case 0: + return PyBytes_FromStringAndSize(&t->state, 1); + case 1: + return PyInt_FromLong(t->mode); + case 2: + return PyInt_FromLong(t->size); + case 3: + return PyInt_FromLong(t->mtime); + default: + PyErr_SetString(PyExc_IndexError, "index out of range"); + return NULL; + } +} + +static PySequenceMethods dirstate_tuple_sq = { + dirstate_tuple_length, /* sq_length */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + dirstate_tuple_item, /* sq_item */ + 0, /* sq_ass_item */ + 0, /* sq_contains */ + 0, /* sq_inplace_concat */ + 0 /* sq_inplace_repeat */ +}; + +PyTypeObject dirstateTupleType = { + PyVarObject_HEAD_INIT(NULL, 0) + "dirstate_tuple", /* tp_name */ + sizeof(dirstateTupleObject),/* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)dirstate_tuple_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + &dirstate_tuple_sq, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "dirstate tuple", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + dirstate_tuple_new, /* tp_new */ +}; + static PyObject *parse_dirstate(PyObject *self, PyObject *args) { PyObject *dmap, *cmap, *parents = NULL, *ret = NULL; @@ -192,11 +308,8 @@ goto quit; } - entry = Py_BuildValue("ciii", state, mode, size, mtime); - if (!entry) - goto quit; - PyObject_GC_UnTrack(entry); /* don't waste time with this */ - + entry = (PyObject *)make_dirstate_tuple(state, mode, size, + mtime); cpos = memchr(cur, 0, flen); if (cpos) { fname = PyBytes_FromStringAndSize(cur, cpos - cur); @@ -316,33 +429,30 @@ p += 20; for (pos = 0; PyDict_Next(map, &pos, &k, &v); ) { + dirstateTupleObject *tuple; + char state; uint32_t mode, size, mtime; Py_ssize_t len, l; PyObject *o; - char *s, *t; + char *t; - if (!PyTuple_Check(v) || PyTuple_GET_SIZE(v) != 4) { - PyErr_SetString(PyExc_TypeError, "expected a 4-tuple"); + if (!dirstate_tuple_check(v)) { + PyErr_SetString(PyExc_TypeError, + "expected a dirstate tuple"); goto bail; } - o = PyTuple_GET_ITEM(v, 0); - if (PyString_AsStringAndSize(o, &s, &l) == -1 || l != 1) { - PyErr_SetString(PyExc_TypeError, "expected one byte"); - goto bail; - } - *p++ = *s; - if (getintat(v, 1, &mode) == -1) - goto bail; - if (getintat(v, 2, &size) == -1) - goto bail; - if (getintat(v, 3, &mtime) == -1) - goto bail; - if (*s == 'n' && mtime == (uint32_t)now) { + tuple = (dirstateTupleObject *)v; + + state = tuple->state; + mode = tuple->mode; + size = tuple->size; + mtime = tuple->mtime; + if (state == 'n' && mtime == (uint32_t)now) { /* See pure/parsers.py:pack_dirstate for why we do * this. */ mtime = -1; - mtime_unset = Py_BuildValue( - "ciii", *s, mode, size, mtime); + mtime_unset = (PyObject *)make_dirstate_tuple( + state, mode, size, mtime); if (!mtime_unset) goto bail; if (PyDict_SetItem(map, k, mtime_unset) == -1) @@ -350,6 +460,7 @@ Py_DECREF(mtime_unset); mtime_unset = NULL; } + *p++ = state; putbe32(mode, p); putbe32(size, p + 4); putbe32(mtime, p + 8); @@ -2021,11 +2132,14 @@ dirs_module_init(mod); indexType.tp_new = PyType_GenericNew; - if (PyType_Ready(&indexType) < 0) + if (PyType_Ready(&indexType) < 0 || + PyType_Ready(&dirstateTupleType) < 0) return; Py_INCREF(&indexType); - PyModule_AddObject(mod, "index", (PyObject *)&indexType); + Py_INCREF(&dirstateTupleType); + PyModule_AddObject(mod, "dirstatetuple", + (PyObject *)&dirstateTupleType); nullentry = Py_BuildValue("iiiiiiis#", 0, 0, 0, -1, -1, -1, -1, nullid, 20);