Skip to content

Instantly share code, notes, and snippets.

@jweinst1
Created January 23, 2026 22:01
Show Gist options
  • Select an option

  • Save jweinst1/c8c6589a01173318fc0f08175c510165 to your computer and use it in GitHub Desktop.

Select an option

Save jweinst1/c8c6589a01173318fc0f08175c510165 to your computer and use it in GitHub Desktop.
Basic probing map in C++
enum class HashQueryRes {
Empty,
Occupied,
Found
};
class HashOnlyLinearMap {
struct KVPair {
uint32_t _hash = 0;
uint32_t _value;
inline bool add(uint32_t hash, uint32_t val) {
if (_hash == 0) {
_hash = hash;
_value = val;
return true;
} else if (_hash == hash) {
_value = val;
return true;
}
return false;
}
inline HashQueryRes find(uint32_t hash, uint32_t* val) const {
if (_hash == 0) {
return HashQueryRes::Empty;
} else if (_hash == hash) {
*val = _value;
return HashQueryRes::Found;
}
return HashQueryRes::Occupied;
}
};
struct Slot {
KVPair pair;
inline bool add(uint32_t hash, uint32_t val) {
return pair.add(hash, val);
}
inline HashQueryRes find(uint32_t hash, uint32_t* val) const {
return pair.find(hash, val);
}
};
std::vector<Slot> table;
size_t mask;
public:
explicit HashOnlyLinearMap(size_t power_of_two_capacity) {
size_t cap = 1ULL << power_of_two_capacity;
table.resize(cap);
mask = cap - 1;
}
void insert(uint32_t hash, uint32_t value) {
size_t idx = hash & mask;
while (true) {
Slot& s = table[idx];
if (s.add(hash, value)) {
return;
}
idx = (idx + 1) & mask; // linear probe
}
}
uint32_t find(uint32_t hash) const {
size_t idx = hash & mask;
uint32_t myNum;
while (true) {
const Slot& s = table[idx];
const HashQueryRes res = s.find(hash, &myNum);
if (res == HashQueryRes::Found) {
return myNum;
} else if (res == HashQueryRes::Empty) {
return 0;
}
idx = (idx + 1) & mask;
}
}
};
static void hashperftest() {
static constexpr size_t keyMask3 = (size_t{1} << 20) - 1;
IdGen gens;
std::vector<uint32_t> nums;
for (int i = 0; i < 4000000; ++i)
{
nums.push_back(gens.next() & keyMask3);
}
HashOnlyLinearMap foobar(22);
auto startIns = std::chrono::high_resolution_clock::now();
for (const auto& num : nums)
{
foobar.insert(num, num);
}
auto endIns = std::chrono::high_resolution_clock::now();
std::cout << "hash ins " << std::chrono::duration_cast<std::chrono::microseconds>(endIns - startIns).count() << "us\n";
auto startFind = std::chrono::high_resolution_clock::now();
uint32_t total = 0;
for (const auto& num : nums)
{
total += foobar.find(num);
}
auto endFind = std::chrono::high_resolution_clock::now();
std::cout << total << "hash find " << std::chrono::duration_cast<std::chrono::microseconds>(endFind - startFind).count() << "us\n";
}
int main(int argc, char const *argv[])
{
hashperftest();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment