diff -r 087cdbf49e80 Objects/unicodeobject.c --- a/Objects/unicodeobject.c Fri Apr 04 21:05:46 2014 +0200 +++ b/Objects/unicodeobject.c Sat Apr 05 14:43:23 2014 +0300 @@ -8445,70 +8445,94 @@ return resunicode; } +static PyObject no_mapping_sentinel; + +static void +charmaptranslatecache_init(PyObject *cache[128]) +{ + memset(cache, 0, 128 * sizeof(PyObject *)); +} + +static void +charmaptranslatecache_free(PyObject *cache[128]) +{ + int i; + for (i = 0; i < 128; i++) + if (cache[i] != NULL && cache[i] != &no_mapping_sentinel) + Py_DECREF(cache[i]); +} + /* Lookup the character ch in the mapping and put the result in result, which must be decrefed by the caller. - Return 0 on success, -1 on error */ -static int -charmaptranslate_lookup(Py_UCS4 c, PyObject *mapping, PyObject **result) -{ - PyObject *w = PyLong_FromLong((long)c); - PyObject *x; - - if (w == NULL) - return -1; - x = PyObject_GetItem(mapping, w); - Py_DECREF(w); - if (x == NULL) { - if (PyErr_ExceptionMatches(PyExc_LookupError)) { - /* No mapping found means: use 1:1 mapping. */ - PyErr_Clear(); - *result = NULL; - return 0; - } else - return -1; - } - else if (x == Py_None) { - *result = x; - return 0; - } - else if (PyLong_Check(x)) { - long value = PyLong_AS_LONG(x); - long max = PyUnicode_GetMax(); - if (value < 0 || value > max) { - PyErr_Format(PyExc_TypeError, - "character mapping must be in range(0x%x)", max+1); + Return NULL on error */ +static PyObject * +charmaptranslate_lookup(Py_UCS4 c, PyObject *mapping, PyObject *cache[128]) +{ + PyObject *x = NULL; + + if (c < 128) { + x = cache[c]; + if (x == &no_mapping_sentinel) + return x; + } + if (x != NULL) + Py_INCREF(x); + else { + PyObject *w = PyLong_FromLong((long)c); + if (w == NULL) + return NULL; + x = PyObject_GetItem(mapping, w); + Py_DECREF(w); + if (x == NULL) { + if (PyErr_ExceptionMatches(PyExc_LookupError)) { + /* No mapping found means: use 1:1 mapping. */ + PyErr_Clear(); + x = &no_mapping_sentinel; + if (c < 128) + cache[c] = x; + return x; + } else + return NULL; + } + if (x == Py_None || PyUnicode_Check(x)) { + } + else if (PyLong_Check(x)) { + long value = PyLong_AS_LONG(x); + long max = PyUnicode_GetMax(); + if (value < 0 || value > max) { + PyErr_Format(PyExc_TypeError, + "character mapping must be in range(0x%x)", max+1); + Py_DECREF(x); + return NULL; + } + } + else { + /* wrong return value */ + PyErr_SetString(PyExc_TypeError, + "character mapping must return integer, None or str"); Py_DECREF(x); - return -1; - } - *result = x; - return 0; - } - else if (PyUnicode_Check(x)) { - *result = x; - return 0; - } - else { - /* wrong return value */ - PyErr_SetString(PyExc_TypeError, - "character mapping must return integer, None or str"); - Py_DECREF(x); - return -1; - } + return NULL; + } + if (c < 128) { + Py_INCREF(x); + cache[c] = x; + } + } + return x; } /* lookup the character, write the result into the writer. Return 1 if the result was written into the writer, return 0 if the mapping was undefined, raise an exception return -1 on error. */ static int -charmaptranslate_output(Py_UCS4 ch, PyObject *mapping, +charmaptranslate_output(Py_UCS4 ch, PyObject *mapping, PyObject *cache[128], _PyUnicodeWriter *writer) { - PyObject *item; - - if (charmaptranslate_lookup(ch, mapping, &item)) - return -1; - - if (item == NULL) { + PyObject *item = charmaptranslate_lookup(ch, mapping, cache); + if (item == NULL) + return -1; + + if (item == &no_mapping_sentinel) { /* not found => default to 1:1 mapping */ if (_PyUnicodeWriter_WriteCharInline(writer, ch) < 0) { return -1; @@ -8536,7 +8560,18 @@ return -1; } - if (_PyUnicodeWriter_WriteStr(writer, item) < 0) { + if (PyUnicode_GET_SIZE(item) == 1) { + ch = PyUnicode_READ_CHAR(item, 0); + if (_PyUnicodeWriter_WriteCharInline(writer, ch) < 0) { + Py_DECREF(item); + return -1; + } + Py_DECREF(item); + return 1; + } + + if (PyUnicode_GET_SIZE(item) && + _PyUnicodeWriter_WriteStr(writer, item) < 0) { Py_DECREF(item); return -1; } @@ -8561,6 +8596,7 @@ PyObject *errorHandler = NULL; PyObject *exc = NULL; int ignore; + PyObject *cache[128]; if (mapping == NULL) { PyErr_BadArgument(); @@ -8585,6 +8621,7 @@ goto onError; ignore = (errors != NULL && strcmp(errors, "ignore") == 0); + charmaptranslatecache_init(cache); i = 0; while (i