diff --git a/src/libutil/hash.cc b/src/libutil/hash.cc index 38ef5dd90..a9603b6fc 100644 --- a/src/libutil/hash.cc +++ b/src/libutil/hash.cc @@ -72,7 +72,19 @@ static std::string printHash16(const Hash & hash) } // omitted: E O U T -const std::string nix32Chars = "0123456789abcdfghijklmnpqrsvwxyz"; +constexpr char nix32Chars[] = "0123456789abcdfghijklmnpqrsvwxyz"; + +constexpr const std::array reverseNix32Map = [] { + std::array map{}; + + for (size_t i = 0; i < map.size(); ++i) + map[i] = 0xFF; // invalid + + for (unsigned char i = 0; i < 32; ++i) + map[static_cast(nix32Chars[i])] = i; + + return map; +}(); static std::string printHash32(const Hash & hash) { @@ -217,12 +229,11 @@ Hash::Hash(std::string_view rest, HashAlgorithm algo, bool isSRI) for (unsigned int n = 0; n < rest.size(); ++n) { char c = rest[rest.size() - n - 1]; - unsigned char digit; - for (digit = 0; digit < nix32Chars.size(); ++digit) /* !!! slow */ - if (nix32Chars[digit] == c) - break; - if (digit >= 32) - throw BadHash("invalid base-32 hash '%s'", rest); + unsigned char digit = reverseNix32Map[static_cast(c)]; + + if (digit == 0xFF) + throw BadHash("invalid base-32 hash: '%s'", rest); + unsigned int b = n * 5; unsigned int i = b / 8; unsigned int j = b % 8; diff --git a/src/libutil/include/nix/util/hash.hh b/src/libutil/include/nix/util/hash.hh index daacd7adf..9661fd489 100644 --- a/src/libutil/include/nix/util/hash.hh +++ b/src/libutil/include/nix/util/hash.hh @@ -35,7 +35,7 @@ constexpr inline size_t regularHashSize(HashAlgorithm type) extern const StringSet hashAlgorithms; -extern const std::string nix32Chars; +extern const std::array reverseNix32Map; /** * @brief Enumeration representing the hash formats. diff --git a/src/libutil/references.cc b/src/libutil/references.cc index cd8a46754..6b88da0c6 100644 --- a/src/libutil/references.cc +++ b/src/libutil/references.cc @@ -13,20 +13,11 @@ static size_t refLength = 32; /* characters */ static void search(std::string_view s, StringSet & hashes, StringSet & seen) { - static std::once_flag initialised; - static bool isBase32[256]; - std::call_once(initialised, []() { - for (unsigned int i = 0; i < 256; ++i) - isBase32[i] = false; - for (unsigned int i = 0; i < nix32Chars.size(); ++i) - isBase32[(unsigned char) nix32Chars[i]] = true; - }); - for (size_t i = 0; i + refLength <= s.size();) { int j; bool match = true; for (j = refLength - 1; j >= 0; --j) - if (!isBase32[(unsigned char) s[i + j]]) { + if (reverseNix32Map[(unsigned char) s[i + j]] == 0xFF) { i += j + 1; match = false; break;