[PATCH 1/6] bitrotate: prefer C2y to bitrotate or by-hand

Paul Eggert <[email protected]>
Newsgroups gmane.comp.lib.gnulib.bugs
Message-ID <[email protected]>
Deprecate the bitrotate module; it is superseded by C2y’s
stdc_rotate_left and stdc_rotate_right.  In several places, prefer
the C2y functions to doing things by hand.
* lib/arctwo.c (arctwo_encrypt, arctwo_decyrpt):
* lib/hash.c (raw_hasher):
* lib/hashcode-mem.c (hash_pjw_bare):
* lib/hashcode-string1.c (hash_string):
* lib/hashcode-string2.c (hash_pjw):
* lib/hashkey-string.c (hashkey_string_hash):
* lib/mem-hash-map.c (compute_hashval):
* lib/struniq.h (hash):
* tests/test-array_map.c (string_hash):
* tests/test-avltreehash_list.c (string_hash):
* tests/test-hash_map.c (string_hash):
* tests/test-linkedhash_list.c (string_hash):
* tests/test-linkedhash_map.c (string_hash):
* tests/test-rbtreehash_list.c (string_hash):
Use stdbit.h functions, instead of bitrotate.h functions or doing
things by hand.  Include stdbit.h to get them.  Don’t include
bitrotate.h, if it was being included.
* lib/getlocalename_l-unsafe.c, lib/getlocalename_l.c:
* lib/localename.c:
Include stdbit.h, since struniq.h now needs this.
* lib/hashcode-mem.c, lib/hashcode-string2.c, lib/hashkey-string.c:
* lib/struniq.h, tests/test-array_map.c, tests/test-avltreehash_list.c:
* tests/test-hash_map.c, tests/test-linkedhash_list.c:
* tests/test-linkedhash_map.c, tests/test-rbtreehash_list.c:
(SIZE_BITS): Remove; no longer needed.
* modules/array-map-tests, modules/avltreehash-list-tests:
* modules/crypto/arctwo, modules/getlocalename_l-simple:
* modules/getlocalename_l-unsafe, modules/hash:
* modules/hash-map-tests, modules/hashcode-mem:
* modules/hashcode-string1, modules/hashcode-string2:
* modules/hashkey-string, modules/linkedhash-list-tests:
* modules/linkedhash-map-tests, modules/localename:
* modules/mem-hash-map, modules/rbtree-list-tests:
Depend on stdc_rotate_left.
Don’t depend on bitrotate, if we were depending on it.
* modules/bitrotate: Deprecate.
* modules/crypto/arctwo: Depend on stdc_rotate_right.
---
 ChangeLog                      | 44 ++++++++++++++++++++++++++++++++++
 NEWS                           |  3 +++
 lib/arctwo.c                   | 18 +++++++-------
 lib/getlocalename_l-unsafe.c   |  1 +
 lib/getlocalename_l.c          |  1 +
 lib/hash.c                     |  4 ++--
 lib/hashcode-mem.c             |  5 ++--
 lib/hashcode-string1.c         |  4 ++--
 lib/hashcode-string2.c         |  5 ++--
 lib/hashkey-string.c           |  5 ++--
 lib/localename.c               |  1 +
 lib/mem-hash-map.c             |  3 ++-
 lib/struniq.h                  |  6 ++---
 modules/array-map-tests        |  1 +
 modules/avltreehash-list-tests |  2 +-
 modules/bitrotate              |  6 +++++
 modules/crypto/arctwo          |  3 ++-
 modules/getlocalename_l-simple |  1 +
 modules/getlocalename_l-unsafe |  1 +
 modules/hash                   |  2 +-
 modules/hash-map-tests         |  1 +
 modules/hashcode-mem           |  1 +
 modules/hashcode-string1       |  2 +-
 modules/hashcode-string2       |  1 +
 modules/hashkey-string         |  1 +
 modules/linkedhash-list-tests  |  1 +
 modules/linkedhash-map-tests   |  1 +
 modules/localename             |  1 +
 modules/mem-hash-map           |  1 +
 modules/rbtree-list-tests      |  1 +
 tests/test-array_map.c         |  5 ++--
 tests/test-avltreehash_list.c  |  5 ++--
 tests/test-hash_map.c          |  5 ++--
 tests/test-linkedhash_list.c   |  5 ++--
 tests/test-linkedhash_map.c    |  5 ++--
 tests/test-rbtreehash_list.c   |  5 ++--
 36 files changed, 109 insertions(+), 48 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d8969b59d1..a5282f0450 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,47 @@
+2026-06-26  Paul Eggert  <[email protected]>
+
+	bitrotate: prefer C2y to bitrotate or by-hand
+	Deprecate the bitrotate module; it is superseded by C2y’s
+	stdc_rotate_left and stdc_rotate_right.  In several places, prefer
+	the C2y functions to doing things by hand.
+	* lib/arctwo.c (arctwo_encrypt, arctwo_decyrpt):
+	* lib/hash.c (raw_hasher):
+	* lib/hashcode-mem.c (hash_pjw_bare):
+	* lib/hashcode-string1.c (hash_string):
+	* lib/hashcode-string2.c (hash_pjw):
+	* lib/hashkey-string.c (hashkey_string_hash):
+	* lib/mem-hash-map.c (compute_hashval):
+	* lib/struniq.h (hash):
+	* tests/test-array_map.c (string_hash):
+	* tests/test-avltreehash_list.c (string_hash):
+	* tests/test-hash_map.c (string_hash):
+	* tests/test-linkedhash_list.c (string_hash):
+	* tests/test-linkedhash_map.c (string_hash):
+	* tests/test-rbtreehash_list.c (string_hash):
+	Use stdbit.h functions, instead of bitrotate.h functions or doing
+	things by hand.  Include stdbit.h to get them.  Don’t include
+	bitrotate.h, if it was being included.
+	* lib/getlocalename_l-unsafe.c, lib/getlocalename_l.c:
+	* lib/localename.c:
+	Include stdbit.h, since struniq.h now needs this.
+	* lib/hashcode-mem.c, lib/hashcode-string2.c, lib/hashkey-string.c:
+	* lib/struniq.h, tests/test-array_map.c, tests/test-avltreehash_list.c:
+	* tests/test-hash_map.c, tests/test-linkedhash_list.c:
+	* tests/test-linkedhash_map.c, tests/test-rbtreehash_list.c:
+	(SIZE_BITS): Remove; no longer needed.
+	* modules/array-map-tests, modules/avltreehash-list-tests:
+	* modules/crypto/arctwo, modules/getlocalename_l-simple:
+	* modules/getlocalename_l-unsafe, modules/hash:
+	* modules/hash-map-tests, modules/hashcode-mem:
+	* modules/hashcode-string1, modules/hashcode-string2:
+	* modules/hashkey-string, modules/linkedhash-list-tests:
+	* modules/linkedhash-map-tests, modules/localename:
+	* modules/mem-hash-map, modules/rbtree-list-tests:
+	Depend on stdc_rotate_left.
+	Don’t depend on bitrotate, if we were depending on it.
+	* modules/bitrotate: Deprecate.
+	* modules/crypto/arctwo: Depend on stdc_rotate_right.
+
 2026-06-26  Bruno Haible  <[email protected]>
 
 	mkdtemp: Provide declaration in <stdlib.h>.
diff --git a/NEWS b/NEWS
index 6eef535dfa..db7776ee78 100644
--- a/NEWS
+++ b/NEWS
@@ -78,6 +78,9 @@ User visible incompatible changes
 
 Date        Modules         Changes
 
+2026-06-26  bitrotate       This module is deprecated.  Use stdc_rotate_left
+                            or stdc_rotate_right instead.
+
 2026-06-22  crypto/af_alg   This module has been deprecated following the
                             deprecation of the AF_ALG API in Linux 7.2.  If your
                             package requires optimized hash algorithms, place
diff --git a/lib/arctwo.c b/lib/arctwo.c
index 3b3d075eb7..7c73b68afc 100644
--- a/lib/arctwo.c
+++ b/lib/arctwo.c
@@ -29,7 +29,7 @@
 
 #include "arctwo.h"
 
-#include "bitrotate.h"
+#include <stdbit.h>
 
 static const uint8_t arctwo_sbox[] = {
   217, 120, 249, 196, 25, 221, 181, 237,
@@ -96,16 +96,16 @@ arctwo_encrypt (arctwo_context *restrict context, char const *restrict inbuf,
           size_t j = i * 4;
           /* For some reason I cannot combine those steps. */
           word0 += (word1 & ~word3) + (word2 & word3) + context->S[j];
-          word0 = rotl16 (word0, 1);
+          word0 = stdc_rotate_left (word0, 1);
 
           word1 += (word2 & ~word0) + (word3 & word0) + context->S[j + 1];
-          word1 = rotl16 (word1, 2);
+          word1 = stdc_rotate_left (word1, 2);
 
           word2 += (word3 & ~word1) + (word0 & word1) + context->S[j + 2];
-          word2 = rotl16 (word2, 3);
+          word2 = stdc_rotate_left (word2, 3);
 
           word3 += (word0 & ~word2) + (word1 & word2) + context->S[j + 3];
-          word3 = rotl16 (word3, 5);
+          word3 = stdc_rotate_left (word3, 5);
 
           if (i == 4 || i == 10)
             {
@@ -149,16 +149,16 @@ arctwo_decrypt (arctwo_context *restrict context, char const *restrict inbuf,
         {
           size_t j = (i - 1) * 4;
 
-          word3 = rotr16 (word3, 5);
+          word3 = stdc_rotate_right (word3, 5);
           word3 -= (word0 & ~word2) + (word1 & word2) + context->S[j + 3];
 
-          word2 = rotr16 (word2, 3);
+          word2 = stdc_rotate_right (word2, 3);
           word2 -= (word3 & ~word1) + (word0 & word1) + context->S[j + 2];
 
-          word1 = rotr16 (word1, 2);
+          word1 = stdc_rotate_right (word1, 2);
           word1 -= (word2 & ~word0) + (word3 & word0) + context->S[j + 1];
 
-          word0 = rotr16 (word0, 1);
+          word0 = stdc_rotate_right (word0, 1);
           word0 -= (word1 & ~word3) + (word2 & word3) + context->S[j];
 
           if (i == 6 || i == 12)
diff --git a/lib/getlocalename_l-unsafe.c b/lib/getlocalename_l-unsafe.c
index cac2f35b62..bd24a8de7a 100644
--- a/lib/getlocalename_l-unsafe.c
+++ b/lib/getlocalename_l-unsafe.c
@@ -26,6 +26,7 @@
 #include <locale.h>
 #include <limits.h>
 #include <stddef.h>
+#include <stdbit.h>
 #include <stdlib.h>
 #include <string.h>
 
diff --git a/lib/getlocalename_l.c b/lib/getlocalename_l.c
index 768e93e32d..fea5ae2269 100644
--- a/lib/getlocalename_l.c
+++ b/lib/getlocalename_l.c
@@ -20,6 +20,7 @@
 #include <locale.h>
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdlib.h>
 #include <string.h>
 
diff --git a/lib/hash.c b/lib/hash.c
index d1012f0afc..95696e0916 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -26,11 +26,11 @@
 
 #include "hash.h"
 
-#include "bitrotate.h"
 #include "next-prime.h"
 #include "xalloc-oversized.h"
 
 #include <errno.h>
+#include <stdbit.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -360,7 +360,7 @@ raw_hasher (const void *data, size_t n)
      bits are 0.  As this tends to give poorer performance with small
      tables, we rotate the pointer value before performing division,
      in an attempt to improve hash quality.  */
-  size_t val = rotr_sz ((size_t) data, 3);
+  size_t val = stdc_rotate_right ((size_t) data, 3);
   return val % n;
 }
 
diff --git a/lib/hashcode-mem.c b/lib/hashcode-mem.c
index 148558be18..a4963afb68 100644
--- a/lib/hashcode-mem.c
+++ b/lib/hashcode-mem.c
@@ -21,8 +21,7 @@
 #include "hashcode-mem.h"
 
 #include <limits.h>
-
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
+#include <stdbit.h>
 
 /* Return a hash of the N bytes of X using the method described by
    Bruno Haible in https://www.haible.de/bruno/hashfunc.html.
@@ -36,7 +35,7 @@ hash_pjw_bare (const void *x, size_t n)
   size_t h = 0;
 
   for (unsigned int i = 0; i < n; i++)
-    h = s[i] + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = s[i] + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/lib/hashcode-string1.c b/lib/hashcode-string1.c
index 1dc15a8724..0eef513aef 100644
--- a/lib/hashcode-string1.c
+++ b/lib/hashcode-string1.c
@@ -22,7 +22,7 @@
 
 #if USE_DIFF_HASH
 
-# include "bitrotate.h"
+# include <stdbit.h>
 
 /* About hashings, Paul Eggert writes to me (FP), on 1994-01-01: "Please see
    B. J. McKenzie, R. Harries & T. Bell, Selecting a hashing algorithm,
@@ -37,7 +37,7 @@ hash_string (const char *string, size_t tablesize)
   unsigned char ch;
 
   for (; (ch = *string); string++)
-    value = ch + rotl_sz (value, 7);
+    value = ch + stdc_rotate_left (value, 7);
   return value % tablesize;
 }
 
diff --git a/lib/hashcode-string2.c b/lib/hashcode-string2.c
index 1b365dde60..3009d1489c 100644
--- a/lib/hashcode-string2.c
+++ b/lib/hashcode-string2.c
@@ -21,8 +21,7 @@
 #include "hashcode-string2.h"
 
 #include <limits.h>
-
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
+#include <stdbit.h>
 
 /* A hash function for NUL-terminated char* strings using
    the method described by Bruno Haible.
@@ -34,7 +33,7 @@ hash_pjw (const void *x, size_t tablesize)
   size_t h = 0;
 
   for (const char *s = x; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h % tablesize;
 }
diff --git a/lib/hashkey-string.c b/lib/hashkey-string.c
index 08200686c5..abd1956eba 100644
--- a/lib/hashkey-string.c
+++ b/lib/hashkey-string.c
@@ -20,6 +20,7 @@
 #include "hashkey-string.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <string.h>
 
 bool
@@ -30,8 +31,6 @@ hashkey_string_equals (const void *x1, const void *x2)
   return streq (s1, s2);
 }
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 /* A hash function for NUL-terminated 'const char *' strings using
    the method described by Bruno Haible.
    See https://www.haible.de/bruno/hashfunc.html.  */
@@ -42,7 +41,7 @@ hashkey_string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/lib/localename.c b/lib/localename.c
index 8fd3fe725b..3cf4be26d1 100644
--- a/lib/localename.c
+++ b/lib/localename.c
@@ -26,6 +26,7 @@
 #include "localename.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdlib.h>
 #include <locale.h>
 #include <string.h>
diff --git a/lib/mem-hash-map.c b/lib/mem-hash-map.c
index 96fba6ee1a..c8620ee22d 100644
--- a/lib/mem-hash-map.c
+++ b/lib/mem-hash-map.c
@@ -20,6 +20,7 @@
 /* Specification.  */
 #include "mem-hash-map.h"
 
+#include <stdbit.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -95,7 +96,7 @@ compute_hashval (const void *key, size_t keylen)
   size_t hval = keylen;
   while (cnt < keylen)
     {
-      hval = (hval << 9) | (hval >> (sizeof (size_t) * CHAR_BIT - 9));
+      hval = stdc_rotate_left (hval, 9);
       hval += (size_t) *(((const char *) key) + cnt++);
     }
   return hval != 0 ? hval : ~((size_t) 0);
diff --git a/lib/struniq.h b/lib/struniq.h
index a9686f1ab3..afa616c864 100644
--- a/lib/struniq.h
+++ b/lib/struniq.h
@@ -20,6 +20,7 @@
 /* This file needs the following includes:
 
      #include <limits.h>
+     #include <stdbit.h>
      #include <stdlib.h>
      #include <string.h>
      #include "flexmember.h"
@@ -31,6 +32,7 @@
      flexmember
      lock
      bool
+     stdc_rotate_left
      thread-optim
  */
 
@@ -38,8 +40,6 @@
 /* Simple hash set of strings.  We don't want to drag in lots of hash table
    code here.  */
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 /* A hash function for NUL-terminated char* strings using
    the method described by Bruno Haible.
    See https://www.haible.de/bruno/hashfunc.html.  */
@@ -50,7 +50,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/modules/array-map-tests b/modules/array-map-tests
index 37dc407b7f..c1646ea8c4 100644
--- a/modules/array-map-tests
+++ b/modules/array-map-tests
@@ -7,6 +7,7 @@ xlist
 array-list
 xalloc
 stdcountof-h
+stdc_rotate_left
 streq
 
 configure.ac:
diff --git a/modules/avltreehash-list-tests b/modules/avltreehash-list-tests
index cc0bc64d46..86ec20e5d7 100644
--- a/modules/avltreehash-list-tests
+++ b/modules/avltreehash-list-tests
@@ -5,6 +5,7 @@ tests/macros.h
 Depends-on:
 array-list
 stdcountof-h
+stdc_rotate_left
 streq
 
 configure.ac:
@@ -12,4 +13,3 @@ configure.ac:
 Makefile.am:
 TESTS += test-avltreehash_list
 check_PROGRAMS += test-avltreehash_list
-
diff --git a/modules/bitrotate b/modules/bitrotate
index 64193d1853..7f81401164 100644
--- a/modules/bitrotate
+++ b/modules/bitrotate
@@ -1,6 +1,12 @@
 Description:
 Rotate bits in unsigned 8, 16, and 32 bit integers.
 
+Status:
+deprecated
+
+Notice:
+This module is deprecated. Use stdc_rotate_left and std_rotate_right instead.
+
 Files:
 lib/bitrotate.h
 lib/bitrotate.c
diff --git a/modules/crypto/arctwo b/modules/crypto/arctwo
index b50d27d034..db36170a2b 100644
--- a/modules/crypto/arctwo
+++ b/modules/crypto/arctwo
@@ -8,7 +8,8 @@ m4/arctwo.m4
 
 Depends-on:
 stdint-h
-bitrotate
+stdc_rotate_left
+stdc_rotate_right
 
 configure.ac:
 AC_REQUIRE([AC_C_RESTRICT])
diff --git a/modules/getlocalename_l-simple b/modules/getlocalename_l-simple
index 39ddc8fd52..4678701be1 100644
--- a/modules/getlocalename_l-simple
+++ b/modules/getlocalename_l-simple
@@ -13,6 +13,7 @@ getlocalename_l-unsafe [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCAL
 flexmember             [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
 lock                   [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
 streq                  [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
+stdc_rotate_left       [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
 bool                   [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
 thread-optim           [test $HAVE_GETLOCALENAME_L = 0 || test $REPLACE_GETLOCALENAME_L = 1]
 
diff --git a/modules/getlocalename_l-unsafe b/modules/getlocalename_l-unsafe
index e7c9153047..c2b9afbfdc 100644
--- a/modules/getlocalename_l-unsafe
+++ b/modules/getlocalename_l-unsafe
@@ -15,6 +15,7 @@ locale-h
 getlocalename_l-unsafe-limited
 flexmember
 lock
+stdc_rotate_left
 streq
 bool
 thread-optim
diff --git a/modules/hash b/modules/hash
index 60ec6b4b56..caff594d32 100644
--- a/modules/hash
+++ b/modules/hash
@@ -6,13 +6,13 @@ lib/hash.c
 lib/hash.h
 
 Depends-on:
-bitrotate
 calloc-posix
 free-posix
 malloc-posix
 next-prime
 bool
 stdint-h
+stdc_rotate_right
 xalloc-oversized
 hashcode-string1
 
diff --git a/modules/hash-map-tests b/modules/hash-map-tests
index 999b5ee524..53da30c663 100644
--- a/modules/hash-map-tests
+++ b/modules/hash-map-tests
@@ -6,6 +6,7 @@ Depends-on:
 array-map
 xalloc
 stdcountof-h
+stdc_rotate_left
 streq
 
 configure.ac:
diff --git a/modules/hashcode-mem b/modules/hashcode-mem
index 1c6431a531..9e0a2a6466 100644
--- a/modules/hashcode-mem
+++ b/modules/hashcode-mem
@@ -7,6 +7,7 @@ lib/hashcode-mem.c
 lib/hash-pjw-bare.h
 
 Depends-on:
+stdc_rotate_left
 
 configure.ac:
 
diff --git a/modules/hashcode-string1 b/modules/hashcode-string1
index 49cf3f3fbe..93ffc01704 100644
--- a/modules/hashcode-string1
+++ b/modules/hashcode-string1
@@ -6,7 +6,7 @@ lib/hashcode-string1.h
 lib/hashcode-string1.c
 
 Depends-on:
-bitrotate
+stdc_rotate_left
 
 configure.ac:
 gl_MODULE_INDICATOR([hashcode-string1])
diff --git a/modules/hashcode-string2 b/modules/hashcode-string2
index 7a26702471..88c377360b 100644
--- a/modules/hashcode-string2
+++ b/modules/hashcode-string2
@@ -7,6 +7,7 @@ lib/hashcode-string2.c
 lib/hash-pjw.h
 
 Depends-on:
+stdc_rotate_left
 
 configure.ac:
 
diff --git a/modules/hashkey-string b/modules/hashkey-string
index 10d8341cb8..2b2b407bbb 100644
--- a/modules/hashkey-string
+++ b/modules/hashkey-string
@@ -7,6 +7,7 @@ lib/hashkey-string.c
 
 Depends-on:
 bool
+stdc_rotate_left
 streq
 
 configure.ac:
diff --git a/modules/linkedhash-list-tests b/modules/linkedhash-list-tests
index 0e36eaac65..7f5e410bfa 100644
--- a/modules/linkedhash-list-tests
+++ b/modules/linkedhash-list-tests
@@ -5,6 +5,7 @@ tests/macros.h
 Depends-on:
 array-list
 stdcountof-h
+stdc_rotate_left
 streq
 
 configure.ac:
diff --git a/modules/linkedhash-map-tests b/modules/linkedhash-map-tests
index b0ef90cb8e..8c3757b97c 100644
--- a/modules/linkedhash-map-tests
+++ b/modules/linkedhash-map-tests
@@ -6,6 +6,7 @@ Depends-on:
 array-map
 xalloc
 stdcountof-h
+stdc_rotate_left
 streq
 
 configure.ac:
diff --git a/modules/localename b/modules/localename
index e01af85e33..4bf7c88a19 100644
--- a/modules/localename
+++ b/modules/localename
@@ -11,6 +11,7 @@ locale-h
 localename-unsafe
 flexmember
 lock
+stdc_rotate_left
 streq
 bool
 thread-optim
diff --git a/modules/mem-hash-map b/modules/mem-hash-map
index cdb750c424..5c611bc5fa 100644
--- a/modules/mem-hash-map
+++ b/modules/mem-hash-map
@@ -9,6 +9,7 @@ Depends-on:
 next-prime
 obstack
 memeq
+stdc_rotate_left
 xalloc
 
 configure.ac:
diff --git a/modules/rbtree-list-tests b/modules/rbtree-list-tests
index f428e58ae9..f4bca8ecfd 100644
--- a/modules/rbtree-list-tests
+++ b/modules/rbtree-list-tests
@@ -5,6 +5,7 @@ tests/macros.h
 Depends-on:
 array-list
 stdcountof-h
+stdc_rotate_left
 
 configure.ac:
 
diff --git a/tests/test-array_map.c b/tests/test-array_map.c
index 5b3ec3bcf6..9d84d45a1c 100644
--- a/tests/test-array_map.c
+++ b/tests/test-array_map.c
@@ -20,6 +20,7 @@
 #include "gl_array_map.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,8 +35,6 @@ static const char *objects[30] =
     "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "<", ">", "[", "]"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -54,7 +53,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/tests/test-avltreehash_list.c b/tests/test-avltreehash_list.c
index b0348a9e70..d31cd1f718 100644
--- a/tests/test-avltreehash_list.c
+++ b/tests/test-avltreehash_list.c
@@ -20,6 +20,7 @@
 #include "gl_avltreehash_list.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,8 +35,6 @@ static const char *objects[15] =
     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -54,7 +53,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/tests/test-hash_map.c b/tests/test-hash_map.c
index 2a806b75ba..b9d02f3568 100644
--- a/tests/test-hash_map.c
+++ b/tests/test-hash_map.c
@@ -20,6 +20,7 @@
 #include "gl_hash_map.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,8 +35,6 @@ static const char *objects[30] =
     "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "<", ">", "[", "]"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -54,7 +53,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/tests/test-linkedhash_list.c b/tests/test-linkedhash_list.c
index a0de9b08e5..f8281f7bef 100644
--- a/tests/test-linkedhash_list.c
+++ b/tests/test-linkedhash_list.c
@@ -20,6 +20,7 @@
 #include "gl_linkedhash_list.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -32,8 +33,6 @@ static const char *objects[15] =
     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -52,7 +51,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/tests/test-linkedhash_map.c b/tests/test-linkedhash_map.c
index 1c6e5d9b59..22011e18af 100644
--- a/tests/test-linkedhash_map.c
+++ b/tests/test-linkedhash_map.c
@@ -20,6 +20,7 @@
 #include "gl_linkedhash_map.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,8 +35,6 @@ static const char *objects[30] =
     "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "<", ">", "[", "]"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -54,7 +53,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
diff --git a/tests/test-rbtreehash_list.c b/tests/test-rbtreehash_list.c
index 45cd3611a2..7709bf96e9 100644
--- a/tests/test-rbtreehash_list.c
+++ b/tests/test-rbtreehash_list.c
@@ -20,6 +20,7 @@
 #include "gl_rbtreehash_list.h"
 
 #include <limits.h>
+#include <stdbit.h>
 #include <stdcountof.h>
 #include <stdlib.h>
 #include <string.h>
@@ -34,8 +35,6 @@ static const char *objects[15] =
     "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o"
   };
 
-#define SIZE_BITS (sizeof (size_t) * CHAR_BIT)
-
 static bool
 string_equals (const void *x1, const void *x2)
 {
@@ -54,7 +53,7 @@ string_hash (const void *x)
   size_t h = 0;
 
   for (; *s; s++)
-    h = *s + ((h << 9) | (h >> (SIZE_BITS - 9)));
+    h = *s + stdc_rotate_left (h, 9);
 
   return h;
 }
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.