[llvm] [ADT] Use a C++17 fold expression in hash_combine (NFC) (PR #159901)

Kazu Hirata via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 20 08:13:50 PDT 2025


https://github.com/kazutakahirata updated https://github.com/llvm/llvm-project/pull/159901

>From 9eb8958fc2177f4cdbb16827c705f3f359f594ed Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Sun, 14 Sep 2025 22:22:45 -0700
Subject: [PATCH 1/2] [ADT] Use a C++17 fold expression in hash_combine (NFC)

combine() combines hash values with recursion on variadic parameters.

This patch replaces the recursion with a C++17 fold expression:

  (combine_data(length, buffer_ptr, buffer_end, get_hashable_data(args)),
   ...);

which expands to:

  combine_data(length, buffer_ptr, buffer_end, get_hashable_data(a));
  combine_data(length, buffer_ptr, buffer_end, get_hashable_data(b));
  combine_data(length, buffer_ptr, buffer_end, get_hashable_data(c));
  :

A key benefit of this change is the unification of the recursive step
and the base case. The argument processing and finalization logic now
exist as straight-line code within a single function.

combine_data now takes buffer_ptr by reference. This is necessary
because the previous assignment pattern:

  buffer_ptr = combine_data(...)

is syntactically incompatible with a fold expression. The new pattern:

  (combine_data(...), ...)

discards return values, so combine_data must update buffer_ptr
directly.

For readability, this patch does the bare minimum to use a fold
expression, leaving further cleanups to subsequent patches.  For
example, buffer_ptr and buffer_end could become member variables, and
several comments that mention recursion still need updating.
---
 llvm/include/llvm/ADT/Hashing.h | 22 ++++++++--------------
 1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h
index 41a730e24a6b1..ffe231249a5c2 100644
--- a/llvm/include/llvm/ADT/Hashing.h
+++ b/llvm/include/llvm/ADT/Hashing.h
@@ -503,7 +503,8 @@ struct hash_combine_recursive_helper {
   /// hash_state, empties it, and then merges the new chunk in. This also
   /// handles cases where the data straddles the end of the buffer.
   template <typename T>
-  char *combine_data(size_t &length, char *buffer_ptr, char *buffer_end, T data) {
+  char *combine_data(size_t &length, char *&buffer_ptr, char *buffer_end,
+                     T data) {
     if (!store_and_advance(buffer_ptr, buffer_end, data)) {
       // Check for skew which prevents the buffer from being packed, and do
       // a partial store into the buffer to fill it. This is only a concern
@@ -541,21 +542,14 @@ struct hash_combine_recursive_helper {
   ///
   /// This function recurses through each argument, combining that argument
   /// into a single hash.
-  template <typename T, typename ...Ts>
+  template <typename... Ts>
   hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
-                    const T &arg, const Ts &...args) {
-    buffer_ptr = combine_data(length, buffer_ptr, buffer_end, get_hashable_data(arg));
+                    const Ts &...args) {
+    (combine_data(length, buffer_ptr, buffer_end, get_hashable_data(args)),
+     ...);
 
-    // Recurse to the next argument.
-    return combine(length, buffer_ptr, buffer_end, args...);
-  }
-
-  /// Base case for recursive, variadic combining.
-  ///
-  /// The base case when combining arguments recursively is reached when all
-  /// arguments have been handled. It flushes the remaining buffer and
-  /// constructs a hash_code.
-  hash_code combine(size_t length, char *buffer_ptr, char *buffer_end) {
+    // Finalize the hash by flushing any remaining data in the buffer.
+    //
     // Check whether the entire set of values fit in the buffer. If so, we'll
     // use the optimized short hashing routine and skip state entirely.
     if (length == 0)

>From 527ced122470e689035fcaa53deebd1aae589785 Mon Sep 17 00:00:00 2001
From: Kazu Hirata <kazu at google.com>
Date: Sat, 20 Sep 2025 08:13:33 -0700
Subject: [PATCH 2/2] Address a comment.

---
 llvm/include/llvm/ADT/Hashing.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ADT/Hashing.h b/llvm/include/llvm/ADT/Hashing.h
index ffe231249a5c2..dffe3791e51c7 100644
--- a/llvm/include/llvm/ADT/Hashing.h
+++ b/llvm/include/llvm/ADT/Hashing.h
@@ -545,7 +545,8 @@ struct hash_combine_recursive_helper {
   template <typename... Ts>
   hash_code combine(size_t length, char *buffer_ptr, char *buffer_end,
                     const Ts &...args) {
-    (combine_data(length, buffer_ptr, buffer_end, get_hashable_data(args)),
+    ((void)combine_data(length, buffer_ptr, buffer_end,
+                        get_hashable_data(args)),
      ...);
 
     // Finalize the hash by flushing any remaining data in the buffer.



More information about the llvm-commits mailing list