diff --git a/include/xo/arena/DArenaHashMap.hpp b/include/xo/arena/DArenaHashMap.hpp index df6e15f..3621b3c 100644 --- a/include/xo/arena/DArenaHashMap.hpp +++ b/include/xo/arena/DArenaHashMap.hpp @@ -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 + auto + DArenaHashMap::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. * diff --git a/utest/DArenaHashMap.test.cpp b/utest/DArenaHashMap.test.cpp index 0d51d19..dc2562b 100644 --- a/utest/DArenaHashMap.test.cpp +++ b/utest/DArenaHashMap.test.cpp @@ -208,6 +208,9 @@ namespace xo { ok_flag &= HashMapUtil::check_forward_iterator(0.0 /*dvalue*/, dbg_flag, hash_map); + ok_flag &= HashMapUtil::random_lookups(0.0 /*dvalue*/, + dbg_flag, &rgen, hash_map); + return ok_flag; }; diff --git a/utest/random_hash_ops.hpp b/utest/random_hash_ops.hpp index d7f2167..dd42c39 100644 --- a/utest/random_hash_ops.hpp +++ b/utest/random_hash_ops.hpp @@ -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 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