# HG changeset patch # User Siddharth Agarwal # Date 1427869947 25200 # Node ID 670aaee7931cdff354af49371428ac371d241acb # Parent 1c533e23ce9533d9c5556c34cbd4122f3a0161b0 parsers: add a C function to create a file foldmap This is a hot path on case-insensitive filesystems -- it's guaranteed to be called every time 'hg status' is run. This is significantly faster than the equivalent Python code: see the following patch for numbers. diff -r 1c533e23ce95 -r 670aaee7931c mercurial/parsers.c --- a/mercurial/parsers.c Thu Apr 02 19:17:32 2015 -0700 +++ b/mercurial/parsers.c Tue Mar 31 23:32:27 2015 -0700 @@ -173,6 +173,72 @@ return _asciitransform(str_obj, uppertable, NULL); } +static PyObject *make_file_foldmap(PyObject *self, PyObject *args) +{ + PyObject *dmap, *spec_obj, *normcase_fallback; + PyObject *file_foldmap = NULL; + enum normcase_spec spec; + PyObject *k, *v; + dirstateTupleObject *tuple; + Py_ssize_t pos = 0; + const char *table; + + if (!PyArg_ParseTuple(args, "O!O!O!:make_file_foldmap", + &PyDict_Type, &dmap, + &PyInt_Type, &spec_obj, + &PyFunction_Type, &normcase_fallback)) + goto quit; + + spec = PyInt_AS_LONG(spec_obj); + switch (spec) { + case NORMCASE_LOWER: + table = lowertable; + break; + case NORMCASE_UPPER: + table = uppertable; + break; + case NORMCASE_OTHER: + table = NULL; + break; + default: + PyErr_SetString(PyExc_TypeError, "invalid normcasespec"); + goto quit; + } + + file_foldmap = PyDict_New(); + if (file_foldmap == NULL) + goto quit; + + while (PyDict_Next(dmap, &pos, &k, &v)) { + if (!dirstate_tuple_check(v)) { + PyErr_SetString(PyExc_TypeError, + "expected a dirstate tuple"); + goto quit; + } + + tuple = (dirstateTupleObject *)v; + if (tuple->state != 'r') { + PyObject *normed; + if (table != NULL) { + normed = _asciitransform(k, table, + normcase_fallback); + } else { + normed = PyObject_CallFunctionObjArgs( + normcase_fallback, k, NULL); + } + + if (normed == NULL) + goto quit; + if (PyDict_SetItem(file_foldmap, normed, k) == -1) + goto quit; + } + } + return file_foldmap; +quit: + Py_XDECREF(file_foldmap); + return NULL; +} + /* * This code assumes that a manifest is stitched together with newline * ('\n') characters. @@ -2463,6 +2529,8 @@ {"parse_index2", parse_index2, METH_VARARGS, "parse a revlog index\n"}, {"asciilower", asciilower, METH_VARARGS, "lowercase an ASCII string\n"}, {"asciiupper", asciiupper, METH_VARARGS, "uppercase an ASCII string\n"}, + {"make_file_foldmap", make_file_foldmap, METH_VARARGS, + "make file foldmap\n"}, {"encodedir", encodedir, METH_VARARGS, "encodedir a path\n"}, {"pathencode", pathencode, METH_VARARGS, "fncache-encode a path\n"}, {"lowerencode", lowerencode, METH_VARARGS, "lower-encode a path\n"},