1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-08 19:46:02 +01:00

Merge pull request #13680 from avnik/avnik/fast-base32

Improve base-32 hash decoding performance with reverse map
This commit is contained in:
John Ericson 2025-08-04 14:22:59 -04:00 committed by GitHub
commit 6ab8cbe31a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
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;