bpo-32147: Improved perfomance of binascii.unhexlify(). (GH-4586)

This commit is contained in:
Sergey Fedoseev 2018-02-27 01:35:41 +05:00 committed by Serhiy Storchaka
parent 19e7d48ce8
commit 6b5df906af
4 changed files with 13 additions and 33 deletions

View File

@ -198,6 +198,11 @@ class BinASCIITest(unittest.TestCase):
self.assertEqual(s, u) self.assertEqual(s, u)
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1]) self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1])
self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q') self.assertRaises(binascii.Error, binascii.a2b_hex, t[:-1] + b'q')
self.assertRaises(binascii.Error, binascii.a2b_hex, bytes([255, 255]))
self.assertRaises(binascii.Error, binascii.a2b_hex, b'0G')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'0g')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'G0')
self.assertRaises(binascii.Error, binascii.a2b_hex, b'g0')
# Confirm that b2a_hex == hexlify and a2b_hex == unhexlify # Confirm that b2a_hex == hexlify and a2b_hex == unhexlify
self.assertEqual(binascii.hexlify(self.type2test(s)), t) self.assertEqual(binascii.hexlify(self.type2test(s)), t)

View File

@ -460,6 +460,7 @@ Michael Farrell
Troy J. Farrell Troy J. Farrell
Jim Fasarakis-Hilliard Jim Fasarakis-Hilliard
Mark Favas Mark Favas
Sergey Fedoseev
Boris Feld Boris Feld
Thomas Fenzl Thomas Fenzl
Niels Ferguson Niels Ferguson

View File

@ -0,0 +1,2 @@
:func:`binascii.unhexlify` is now up to 2 times faster.
Patch by Sergey Fedoseev.

View File

@ -1130,21 +1130,6 @@ binascii_hexlify_impl(PyObject *module, Py_buffer *data)
return _Py_strhex_bytes((const char *)data->buf, data->len); return _Py_strhex_bytes((const char *)data->buf, data->len);
} }
static int
to_int(int c)
{
if (Py_ISDIGIT(c))
return c - '0';
else {
if (Py_ISUPPER(c))
c = Py_TOLOWER(c);
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
return -1;
}
/*[clinic input] /*[clinic input]
binascii.a2b_hex binascii.a2b_hex
@ -1187,9 +1172,9 @@ binascii_a2b_hex_impl(PyObject *module, Py_buffer *hexstr)
retbuf = PyBytes_AS_STRING(retval); retbuf = PyBytes_AS_STRING(retval);
for (i=j=0; i < arglen; i += 2) { for (i=j=0; i < arglen; i += 2) {
int top = to_int(Py_CHARMASK(argbuf[i])); unsigned int top = _PyLong_DigitValue[Py_CHARMASK(argbuf[i])];
int bot = to_int(Py_CHARMASK(argbuf[i+1])); unsigned int bot = _PyLong_DigitValue[Py_CHARMASK(argbuf[i+1])];
if (top == -1 || bot == -1) { if (top >= 16 || bot >= 16) {
PyErr_SetString(Error, PyErr_SetString(Error,
"Non-hexadecimal digit found"); "Non-hexadecimal digit found");
goto finally; goto finally;
@ -1218,19 +1203,6 @@ binascii_unhexlify_impl(PyObject *module, Py_buffer *hexstr)
return binascii_a2b_hex_impl(module, hexstr); return binascii_a2b_hex_impl(module, hexstr);
} }
static const int table_hex[128] = {
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
};
#define hexval(c) table_hex[(unsigned int)(c)]
#define MAXLINESIZE 76 #define MAXLINESIZE 76
@ -1293,9 +1265,9 @@ binascii_a2b_qp_impl(PyObject *module, Py_buffer *data, int header)
(ascii_data[in+1] >= 'a' && ascii_data[in+1] <= 'f') || (ascii_data[in+1] >= 'a' && ascii_data[in+1] <= 'f') ||
(ascii_data[in+1] >= '0' && ascii_data[in+1] <= '9'))) { (ascii_data[in+1] >= '0' && ascii_data[in+1] <= '9'))) {
/* hexval */ /* hexval */
ch = hexval(ascii_data[in]) << 4; ch = _PyLong_DigitValue[ascii_data[in]] << 4;
in++; in++;
ch |= hexval(ascii_data[in]); ch |= _PyLong_DigitValue[ascii_data[in]];
in++; in++;
odata[out++] = ch; odata[out++] = ch;
} }