1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-16 07:22:43 +01:00

Improve base-32 hash decoding performance with reverse map

The changes include:

* Defining nix32Chars as a constexpr char[].
* Adding a constexpr std::array<unsigned char, 256> (reverseNix32Map) to map characters to their base-32 digit values at compile time.
* Replacing the slow character search loop with a direct lookup using reverseNix32Map.
* Removing std::once_flag/isBase32 logic in references.cc in favor of reverseNix32Map

Signed-off-by: Alexander V. Nikolaev <avn@avnik.info>
This commit is contained in:
Alexander V. Nikolaev 2025-08-03 18:03:47 +03:00
parent 51a32e4645
commit 4bfc007a7b
No known key found for this signature in database
GPG key ID: B8AF18ABCA6271D2
3 changed files with 20 additions and 18 deletions

View file

@ -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<unsigned char, 256> reverseNix32Map = [] {
std::array<unsigned char, 256> 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<unsigned char>(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<unsigned char>(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;

View file

@ -35,7 +35,7 @@ constexpr inline size_t regularHashSize(HashAlgorithm type)
extern const StringSet hashAlgorithms;
extern const std::string nix32Chars;
extern const std::array<unsigned char, 256> reverseNix32Map;
/**
* @brief Enumeration representing the hash formats.

View file

@ -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;