From 6a9e80a93148b13e4d3bceaab5ea1804ab0e64d5 Mon Sep 17 00:00:00 2001 From: sweeneyde <36520290+sweeneyde@users.noreply.github.com> Date: Mon, 20 Apr 2020 20:17:52 -0400 Subject: [PATCH] bpo-40313: speed up bytes.hex() (GH-19594) Automerge-Triggered-By: @gpshead --- .../2020-04-20-23-58-35.bpo-40313.USVRW8.rst | 1 + Python/pystrhex.c | 61 +++++++++++++++---- 2 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-04-20-23-58-35.bpo-40313.USVRW8.rst diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-04-20-23-58-35.bpo-40313.USVRW8.rst b/Misc/NEWS.d/next/Core and Builtins/2020-04-20-23-58-35.bpo-40313.USVRW8.rst new file mode 100644 index 00000000000..52880abe9c2 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2020-04-20-23-58-35.bpo-40313.USVRW8.rst @@ -0,0 +1 @@ +Improve the performance of bytes.hex(). \ No newline at end of file diff --git a/Python/pystrhex.c b/Python/pystrhex.c index 7e4fad30320..b74e57ad913 100644 --- a/Python/pystrhex.c +++ b/Python/pystrhex.c @@ -82,22 +82,59 @@ static PyObject *_Py_strhex_impl(const char* argbuf, const Py_ssize_t arglen, /* Hexlify */ Py_ssize_t i, j; - for (i=j=0; i < arglen; ++i) { - assert((j + 1) < resultlen); - unsigned char c; - c = (argbuf[i] >> 4) & 0x0f; - retbuf[j++] = Py_hexdigits[c]; - c = argbuf[i] & 0x0f; - retbuf[j++] = Py_hexdigits[c]; - if (bytes_per_sep_group && i < arglen - 1) { - Py_ssize_t anchor; - anchor = (bytes_per_sep_group > 0) ? (arglen - 1 - i) : (i + 1); - if (anchor % abs_bytes_per_sep == 0) { + unsigned char c; + + if (bytes_per_sep_group == 0) { + for (i = j = 0; i < arglen; ++i) { + assert((j + 1) < resultlen); + c = argbuf[i]; + retbuf[j++] = Py_hexdigits[c >> 4]; + retbuf[j++] = Py_hexdigits[c & 0x0f]; + } + assert(j == resultlen); + } + else { + /* The number of complete chunk+sep periods */ + Py_ssize_t chunks = (arglen - 1) / abs_bytes_per_sep; + Py_ssize_t chunk; + unsigned int k; + + if (bytes_per_sep_group < 0) { + i = j = 0; + for (chunk = 0; chunk < chunks; chunk++) { + for (k = 0; k < abs_bytes_per_sep; k++) { + c = argbuf[i++]; + retbuf[j++] = Py_hexdigits[c >> 4]; + retbuf[j++] = Py_hexdigits[c & 0x0f]; + } retbuf[j++] = sep_char; } + while (i < arglen) { + c = argbuf[i++]; + retbuf[j++] = Py_hexdigits[c >> 4]; + retbuf[j++] = Py_hexdigits[c & 0x0f]; + } + assert(j == resultlen); + } + else { + i = arglen - 1; + j = resultlen - 1; + for (chunk = 0; chunk < chunks; chunk++) { + for (k = 0; k < abs_bytes_per_sep; k++) { + c = argbuf[i--]; + retbuf[j--] = Py_hexdigits[c & 0x0f]; + retbuf[j--] = Py_hexdigits[c >> 4]; + } + retbuf[j--] = sep_char; + } + while (i >= 0) { + c = argbuf[i--]; + retbuf[j--] = Py_hexdigits[c & 0x0f]; + retbuf[j--] = Py_hexdigits[c >> 4]; + } + assert(j == -1); } } - assert(j == resultlen); #ifdef Py_DEBUG if (!return_bytes) {