]> git.eshelyaron.com Git - emacs.git/commitdiff
Port knuth_hash to odd platforms
authorPaul Eggert <eggert@cs.ucla.edu>
Sun, 19 May 2024 15:42:57 +0000 (08:42 -0700)
committerEshel Yaron <me@eshelyaron.com>
Thu, 23 May 2024 07:43:27 +0000 (09:43 +0200)
* src/lisp.h (hash_hash_t, knuth_hash): Use unsigned int and
unsigned long long int rather than uint32_t and uint64_t, as POSIX
does not guarantee the presence of uint64_t, and uint32_t and
uint64_t both in theory have problems with undefined behavior on
integer overflow.  This doesn’t affect behavior (or even machine
code) on typical platforms.

(cherry picked from commit 9bcd644408367b1d57e62a7f73b4ef4a3cd366b4)

src/lisp.h

index d61a4d5c9829a65ca34bc2a21c5bc08d9468b781..4b4ff2a2c60f1edfba01fb253940c4b65450ddcb 100644 (file)
@@ -2534,7 +2534,7 @@ struct Lisp_Hash_Table;
 
 /* The type of a hash value stored in the table.
    It's unsigned and a subtype of EMACS_UINT.  */
-typedef uint32_t hash_hash_t;
+typedef unsigned int hash_hash_t;
 
 typedef enum {
   Test_eql,
@@ -2818,10 +2818,14 @@ INLINE ptrdiff_t
 knuth_hash (hash_hash_t hash, unsigned bits)
 {
   /* Knuth multiplicative hashing, tailored for 32-bit indices
-     (avoiding a 64-bit multiply).  */
-  uint32_t alpha = 2654435769; /* 2**32/phi */
-  /* Note the cast to uint64_t, to make it work for bits=0.  */
-  return (uint64_t)((uint32_t)hash * alpha) >> (32 - bits);
+     (avoiding a 64-bit multiply on typical platforms).  */
+  unsigned int h = hash;
+  unsigned int alpha = 2654435769;     /* 2**32/phi */
+  /* Multiply with unsigned int, ANDing in case UINT_WIDTH exceeds 32.  */
+  unsigned int product = (h * alpha) & 0xffffffffu;
+  /* Convert to a wider type, so that the shift works when BITS == 0.  */
+  unsigned long long int wide_product = product;
+  return wide_product >> (32 - bits);
 }