xo-arena: DArenaHashMap: find() + utest

This commit is contained in:
Roland Conybeare 2026-01-08 17:04:07 -05:00
commit 4b73706625
3 changed files with 75 additions and 18 deletions

View file

@ -457,6 +457,11 @@ namespace xo {
/** reset to empty state **/
void clear();
/** find element with key @p key.
* @return iterator to element if found, end() otherwise
**/
iterator find(const key_type & key);
private:
/** insert @p kv_pair,
* where key hashes to @p hash_value, into @p *store
@ -745,6 +750,59 @@ namespace xo {
this->store_.clear();
}
template <typename Key,
typename Value,
typename Hash,
typename Equal>
auto
DArenaHashMap<Key, Value, Hash, Equal>::find(const key_type & key) -> iterator
{
size_type N = store_.capacity();
if (N == 0) [[unlikely]] {
return this->end();
}
size_type h = hash_(key);
size_type h1 = h >> 7;
uint8_t h2 = h & 0x7f;
size_type ix = h1 & (N - 1);
for (;;) {
auto grp = store_._load_group(ix);
{
uint16_t m = grp.all_matches(h2);
while (m) {
int skip = __builtin_ctz(m);
size_type slot_ix = (ix + skip) & (N - 1);
auto & slot = store_.slots_[slot_ix];
if (equal_(slot.first, key)) {
return iterator(&(store_.control_[c_control_stub + slot_ix]),
&(store_.control_[c_control_stub + N]),
&slot);
}
m &= (m - 1);
}
}
{
uint16_t e = grp.empty_matches();
if (e) {
return this->end();
}
}
ix = (ix + c_group_size) & (N - 1);
}
}
/**
* Verify DArenaHashMap class invariants.
*

View file

@ -208,6 +208,9 @@ namespace xo {
ok_flag &= HashMapUtil<HashMap>::check_forward_iterator(0.0 /*dvalue*/,
dbg_flag, hash_map);
ok_flag &= HashMapUtil<HashMap>::random_lookups(0.0 /*dvalue*/,
dbg_flag, &rgen, hash_map);
return ok_flag;
};

View file

@ -329,15 +329,15 @@ namespace utest {
} /*random_removes*/
#endif
#ifdef NOT_YET
/* Require:
* - tree has keys [0..n-1], where n=treẹsize()
* - for each key k, associated value is 10*k
* - map has keys [0..n-1], where n=map.size()
* - for each key k, associated value is dvalue+10*k
*/
static bool
random_lookups(bool catch_flag,
Tree const & tree,
xo::rng::xoshiro256ss * p_rgen)
random_lookups(uint32_t dvalue,
bool catch_flag,
xo::rng::xoshiro256ss * p_rgen,
HashMap & map)
{
using xo::scope;
using xo::xtag;
@ -347,9 +347,9 @@ namespace utest {
/* -> false if/when verification fails */
bool ok_flag = true;
REQUIRE_ORFAIL(ok_flag, catch_flag, tree.verify_ok(catch_flag));
REQUIRE_ORFAIL(ok_flag, catch_flag, map.verify_ok());
size_t n = tree.size();
size_t n = map.size();
std::vector<std::uint32_t> u
= random_permutation(n, p_rgen);
@ -358,27 +358,23 @@ namespace utest {
for (std::uint32_t x : u) {
INFO(tostr(xtag("i", i), xtag("n", n), xtag("x", x)));
REQUIRE_ORFAIL(ok_flag, catch_flag, tree[x] == x*10);
REQUIRE_ORFAIL(ok_flag, catch_flag, tree.verify_ok(catch_flag));
REQUIRE_ORFAIL(ok_flag, catch_flag, tree.size() == n);
auto find_ix = map.find(x);
/* also test treẹfind() */
auto find_ix = tree.find(x);
REQUIRE_ORFAIL(ok_flag, catch_flag, find_ix != tree.end());
REQUIRE_ORFAIL(ok_flag, catch_flag, find_ix != map.end());
REQUIRE_ORFAIL(ok_flag, catch_flag, find_ix->first == x);
REQUIRE_ORFAIL(ok_flag, catch_flag, find_ix->second == x*10);
REQUIRE_ORFAIL(ok_flag, catch_flag, find_ix->second == dvalue + x*10);
REQUIRE_ORFAIL(ok_flag, catch_flag, map.verify_ok());
REQUIRE_ORFAIL(ok_flag, catch_flag, map.size() == n);
++i;
}
REQUIRE_ORFAIL(ok_flag, catch_flag, tree.size() == n);
REQUIRE_ORFAIL(ok_flag, catch_flag, map.size() == n);
log.end_scope();
return ok_flag;
} /*random_lookups*/
#endif
/* Require:
* - hash has keys [0..n-1] where n=map size