mirror of
https://github.com/python/cpython.git
synced 2025-08-03 16:39:00 +00:00
Issue #21118: Optimize str.translate() for ASCII => ASCII translation
This commit is contained in:
parent
5a29f25843
commit
89a76abf20
1 changed files with 120 additions and 1 deletions
|
@ -8545,6 +8545,116 @@ charmaptranslate_output(Py_UCS4 ch, PyObject *mapping,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
unicode_fast_translate_lookup(PyObject *mapping, Py_UCS1 ch,
|
||||||
|
Py_UCS1 *translate)
|
||||||
|
{
|
||||||
|
PyObject *item;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
item = NULL;
|
||||||
|
if (charmaptranslate_lookup(ch, mapping, &item)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item == Py_None) {
|
||||||
|
/* deletion: skip fast translate */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item == NULL) {
|
||||||
|
/* not found => default to 1:1 mapping */
|
||||||
|
translate[ch] = ch;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PyLong_Check(item)) {
|
||||||
|
long replace = (Py_UCS4)PyLong_AS_LONG(item);
|
||||||
|
if (replace == -1) {
|
||||||
|
Py_DECREF(item);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (replace < 0 || 127 < replace) {
|
||||||
|
/* invalid character or character outside ASCII:
|
||||||
|
skip the fast translate */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
translate[ch] = (Py_UCS1)replace;
|
||||||
|
}
|
||||||
|
else if (PyUnicode_Check(item)) {
|
||||||
|
Py_UCS4 replace;
|
||||||
|
|
||||||
|
if (PyUnicode_READY(item) == -1) {
|
||||||
|
Py_DECREF(item);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (PyUnicode_GET_LENGTH(item) != 1)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
replace = PyUnicode_READ_CHAR(item, 0);
|
||||||
|
if (replace > 127)
|
||||||
|
goto exit;
|
||||||
|
translate[ch] = (Py_UCS1)replace;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* not a long or unicode */
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
Py_DECREF(item);
|
||||||
|
item = NULL;
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
Py_XDECREF(item);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fast path for ascii => ascii translation. Return 1 if the whole string
|
||||||
|
was translated into writer, return 0 if the input string was partially
|
||||||
|
translated into writer, raise an exception and return -1 on error. */
|
||||||
|
static int
|
||||||
|
unicode_fast_translate(PyObject *input, PyObject *mapping,
|
||||||
|
_PyUnicodeWriter *writer)
|
||||||
|
{
|
||||||
|
Py_UCS1 translate[128], ch, ch2;
|
||||||
|
Py_ssize_t len;
|
||||||
|
Py_UCS1 *in, *end, *out;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (PyUnicode_READY(input) == -1)
|
||||||
|
return -1;
|
||||||
|
if (!PyUnicode_IS_ASCII(input))
|
||||||
|
return 0;
|
||||||
|
len = PyUnicode_GET_LENGTH(input);
|
||||||
|
|
||||||
|
memset(translate, 0xff, 128);
|
||||||
|
|
||||||
|
in = PyUnicode_1BYTE_DATA(input);
|
||||||
|
end = in + len;
|
||||||
|
|
||||||
|
assert(PyUnicode_IS_ASCII(writer->buffer));
|
||||||
|
assert(PyUnicode_GET_LENGTH(writer->buffer) == len);
|
||||||
|
out = PyUnicode_1BYTE_DATA(writer->buffer);
|
||||||
|
|
||||||
|
for (; in < end; in++, out++) {
|
||||||
|
ch = *in;
|
||||||
|
ch2 = translate[ch];
|
||||||
|
if (ch2 == 0xff) {
|
||||||
|
res = unicode_fast_translate_lookup(mapping, ch, translate);
|
||||||
|
if (res < 0)
|
||||||
|
return -1;
|
||||||
|
if (res == 0) {
|
||||||
|
writer->pos = in - PyUnicode_1BYTE_DATA(input);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ch2 = translate[ch];
|
||||||
|
}
|
||||||
|
*out = ch2;
|
||||||
|
}
|
||||||
|
writer->pos = len;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
_PyUnicode_TranslateCharmap(PyObject *input,
|
_PyUnicode_TranslateCharmap(PyObject *input,
|
||||||
PyObject *mapping,
|
PyObject *mapping,
|
||||||
|
@ -8561,6 +8671,7 @@ _PyUnicode_TranslateCharmap(PyObject *input,
|
||||||
PyObject *errorHandler = NULL;
|
PyObject *errorHandler = NULL;
|
||||||
PyObject *exc = NULL;
|
PyObject *exc = NULL;
|
||||||
int ignore;
|
int ignore;
|
||||||
|
int res;
|
||||||
|
|
||||||
if (mapping == NULL) {
|
if (mapping == NULL) {
|
||||||
PyErr_BadArgument();
|
PyErr_BadArgument();
|
||||||
|
@ -8584,9 +8695,17 @@ _PyUnicode_TranslateCharmap(PyObject *input,
|
||||||
if (_PyUnicodeWriter_Prepare(&writer, size, 127) == -1)
|
if (_PyUnicodeWriter_Prepare(&writer, size, 127) == -1)
|
||||||
goto onError;
|
goto onError;
|
||||||
|
|
||||||
|
res = unicode_fast_translate(input, mapping, &writer);
|
||||||
|
if (res < 0) {
|
||||||
|
_PyUnicodeWriter_Dealloc(&writer);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (res == 1)
|
||||||
|
return _PyUnicodeWriter_Finish(&writer);
|
||||||
|
|
||||||
ignore = (errors != NULL && strcmp(errors, "ignore") == 0);
|
ignore = (errors != NULL && strcmp(errors, "ignore") == 0);
|
||||||
|
|
||||||
i = 0;
|
i = writer.pos;
|
||||||
while (i<size) {
|
while (i<size) {
|
||||||
/* try to encode it */
|
/* try to encode it */
|
||||||
int translate;
|
int translate;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue