guix_mirror_bot pushed a commit to branch master
in repository guix.

commit 64a0824955aa40ea8e59bd4328ecaaf8caaa2acc
Author: Reepca Russelstein <[email protected]>
AuthorDate: Sun Jun 21 07:13:16 2026 -0500

    daemon: libutil: add base32Values and use them.
    
    Recognizing base32 characters and/or parsing them into byte sequences is 
done
    in several places, so it makes sense to provide a common lookup table.
    
    * nix/libutil/hash.hh (base32Values, base32ValuesInitialized): new 
variables.
      (initializeBase32Values, getBase32Value): new functions.
    * nix/libutil/hash.cc (base32Values, base32ValuesInitialized): provide
      definition for variables.
      (initializeBase32Values, getBase32Value): provide function 
implementations.
      (parseHash32): use base32Values.
    * nix/libstore/references.cc (search): use base32Values.
    
    Signed-off-by: Ludovic Courtès <[email protected]>
---
 nix/libstore/references.cc | 11 +----------
 nix/libutil/hash.cc        | 19 +++++++++++++++----
 nix/libutil/hash.hh        |  3 +++
 3 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/nix/libstore/references.cc b/nix/libstore/references.cc
index a8ec39ee34..20b55db6ab 100644
--- a/nix/libstore/references.cc
+++ b/nix/libstore/references.cc
@@ -17,20 +17,11 @@ static unsigned int refLength = 32; /* characters */
 static void search(const unsigned char * s, unsigned int len,
     StringSet & hashes, StringSet & seen)
 {
-    static bool initialised = false;
-    static bool isBase32[256];
-    if (!initialised) {
-        for (unsigned int i = 0; i < 256; ++i) isBase32[i] = false;
-        for (unsigned int i = 0; i < base32Chars.size(); ++i)
-            isBase32[(unsigned char) base32Chars[i]] = true;
-        initialised = true;
-    }
-
     for (unsigned int i = 0; i + refLength <= len; ) {
         int j;
         bool match = true;
         for (j = refLength - 1; j >= 0; --j)
-            if (!isBase32[(unsigned char) s[i + j]]) {
+            if (base32Values[(unsigned char) s[i + j]] == -1) {
                 i += j + 1;
                 match = false;
                 break;
diff --git a/nix/libutil/hash.cc b/nix/libutil/hash.cc
index ac9eb14514..06753d1961 100644
--- a/nix/libutil/hash.cc
+++ b/nix/libutil/hash.cc
@@ -17,6 +17,18 @@
 
 namespace nix {
 
+static std::vector<char> getBase32Values()
+{
+    assert(base32Chars.size() <= std::numeric_limits<unsigned char>::max()+1);
+    assert(base32Chars.size() <= std::numeric_limits<char>::max()+1);
+    std::vector<char> values(std::numeric_limits<unsigned char>::max()+1, -1);
+    for (string::size_type j = 0; j < base32Chars.size(); j++)
+        values[(unsigned char) base32Chars[j]] = (char) j;
+    return values;
+}
+
+const std::vector<char> base32Values = getBase32Values();
+
 
 Hash::Hash()
 {
@@ -139,11 +151,10 @@ Hash parseHash32(HashType ht, std::string_view s)
 
     for (unsigned int n = 0; n < len; ++n) {
         char c = s[len - n - 1];
-        unsigned char digit;
-        for (digit = 0; digit < base32Chars.size(); ++digit) /* !!! slow */
-            if (base32Chars[digit] == c) break;
-        if (digit >= 32)
+        char sdigit = base32Values[(unsigned char) c];
+        if (sdigit < 0)
             throw Error(std::format("invalid base-32 hash '{}'", s));
+        unsigned char digit = (unsigned char) sdigit;
         unsigned int b = n * 5;
         unsigned int i = b / 8;
         unsigned int j = b % 8;
diff --git a/nix/libutil/hash.hh b/nix/libutil/hash.hh
index cedb5077c1..fabe50c11c 100644
--- a/nix/libutil/hash.hh
+++ b/nix/libutil/hash.hh
@@ -1,6 +1,7 @@
 #pragma once
 
 #include <gcrypt.h>
+#include <limits>
 
 #include "archive.hh"
 #include "types.hh"
@@ -11,6 +12,8 @@ namespace nix {
 
 // omitted: E O U T
 inline const string base32Chars {"0123456789abcdfghijklmnpqrsvwxyz"};
+/* Maps character to value, or -1 if not part of base32 character set. */
+extern const std::vector<char> base32Values;
 
 typedef enum {
     htUnknown = 0,

Reply via email to