Use if based mod in HashMap and HashSet in loops (faster than fastmod).

This commit is contained in:
Lukas Tenbrink
2025-05-18 19:43:07 +02:00
parent 34f005d810
commit 6fe17b264e
2 changed files with 33 additions and 13 deletions

View File

@@ -91,9 +91,19 @@ private:
return hash; return hash;
} }
_FORCE_INLINE_ static constexpr void _increment_mod(uint32_t &r_pos, const uint32_t p_capacity) {
r_pos++;
// `if` is faster than both fastmod and mod.
if (unlikely(r_pos == p_capacity)) {
r_pos = 0;
}
}
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); const uint32_t distance_pos = p_pos - original_pos + p_capacity;
// At most p_capacity over 0, so we can use an if (faster than fastmod).
return distance_pos >= p_capacity ? distance_pos - p_capacity : distance_pos;
} }
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
@@ -121,7 +131,7 @@ private:
return true; return true;
} }
pos = fastmod((pos + 1), capacity_inv, capacity); _increment_mod(pos, capacity);
distance++; distance++;
} }
} }
@@ -152,7 +162,7 @@ private:
distance = existing_probe_len; distance = existing_probe_len;
} }
pos = fastmod((pos + 1), capacity_inv, capacity); _increment_mod(pos, capacity);
distance++; distance++;
} }
} }
@@ -357,7 +367,7 @@ public:
SWAP(hashes[next_pos], hashes[pos]); SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]); SWAP(elements[next_pos], elements[pos]);
pos = next_pos; pos = next_pos;
next_pos = fastmod((pos + 1), capacity_inv, capacity); _increment_mod(next_pos, capacity);
} }
hashes[pos] = EMPTY_HASH; hashes[pos] = EMPTY_HASH;
@@ -406,7 +416,7 @@ public:
SWAP(hashes[next_pos], hashes[pos]); SWAP(hashes[next_pos], hashes[pos]);
SWAP(elements[next_pos], elements[pos]); SWAP(elements[next_pos], elements[pos]);
pos = next_pos; pos = next_pos;
next_pos = fastmod((pos + 1), capacity_inv, capacity); _increment_mod(next_pos, capacity);
} }
hashes[pos] = EMPTY_HASH; hashes[pos] = EMPTY_HASH;
elements[pos] = nullptr; elements[pos] = nullptr;

View File

@@ -70,9 +70,19 @@ private:
return hash; return hash;
} }
_FORCE_INLINE_ static constexpr void _increment_mod(uint32_t &r_pos, const uint32_t p_capacity) {
r_pos++;
// `if` is faster than both fastmod and mod.
if (unlikely(r_pos == p_capacity)) {
r_pos = 0;
}
}
static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) { static _FORCE_INLINE_ uint32_t _get_probe_length(const uint32_t p_pos, const uint32_t p_hash, const uint32_t p_capacity, const uint64_t p_capacity_inv) {
const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity); const uint32_t original_pos = fastmod(p_hash, p_capacity_inv, p_capacity);
return fastmod(p_pos - original_pos + p_capacity, p_capacity_inv, p_capacity); const uint32_t distance_pos = p_pos - original_pos + p_capacity;
// At most p_capacity over 0, so we can use an if (faster than fastmod).
return distance_pos >= p_capacity ? distance_pos - p_capacity : distance_pos;
} }
bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const { bool _lookup_pos(const TKey &p_key, uint32_t &r_pos) const {
@@ -91,16 +101,16 @@ private:
return false; return false;
} }
if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
return false;
}
if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) { if (hashes[pos] == hash && Comparator::compare(keys[hash_to_key[pos]], p_key)) {
r_pos = hash_to_key[pos]; r_pos = hash_to_key[pos];
return true; return true;
} }
pos = fastmod(pos + 1, capacity_inv, capacity); if (distance > _get_probe_length(pos, hashes[pos], capacity, capacity_inv)) {
return false;
}
_increment_mod(pos, capacity);
distance++; distance++;
} }
} }
@@ -130,7 +140,7 @@ private:
distance = existing_probe_len; distance = existing_probe_len;
} }
pos = fastmod(pos + 1, capacity_inv, capacity); _increment_mod(pos, capacity);
distance++; distance++;
} }
} }
@@ -274,7 +284,7 @@ public:
SWAP(hash_to_key[next_pos], hash_to_key[pos]); SWAP(hash_to_key[next_pos], hash_to_key[pos]);
pos = next_pos; pos = next_pos;
next_pos = fastmod(pos + 1, capacity_inv, capacity); _increment_mod(next_pos, capacity);
} }
hashes[pos] = EMPTY_HASH; hashes[pos] = EMPTY_HASH;