From be0f2de179235980b5409d5e77577207b93a4f12 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Tue, 8 Dec 2020 18:08:54 -0500 Subject: [PATCH] * src/fns.c (hash_string): Speed up on large strings --- src/fns.c | 41 ++++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/fns.c b/src/fns.c index e4c9acc3163..23d24ef4db4 100644 --- a/src/fns.c +++ b/src/fns.c @@ -18,6 +18,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see . */ +#include #include #include @@ -4525,18 +4526,40 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) EMACS_UINT hash_string (char const *ptr, ptrdiff_t len) { - char const *p = ptr; - char const *end = p + len; - unsigned char c; - EMACS_UINT hash = 0; - - while (p != end) + if (len < 16) { - c = *p++; - hash = sxhash_combine (hash, c); + char const *p = ptr; + char const *end = p + len; + EMACS_UINT hash = len; + + while (p < end) + { + unsigned char c = *p++; + hash = sxhash_combine (hash, c); + } + + return hash; } + else + { + EMACS_UINT const *p = (EMACS_UINT const *) ptr; + EMACS_UINT const *end = (EMACS_UINT const *) (ptr + len); + EMACS_UINT hash = len; + /* At most 8 steps. We could reuse SXHASH_MAX_LEN, of course, + * but dividing by 8 is cheaper. */ + ptrdiff_t step = max (1, (end - p) >> 3); + + /* Beware: `end` might be unaligned, so `p < end` is not always the same + * as `p <= end - 1`. */ + while (p <= end - 1) + { + EMACS_UINT c = *p; + p += step; + hash = sxhash_combine (hash, c); + } - return hash; + return hash; + } } /* Return a hash for string PTR which has length LEN. The hash -- 2.39.2