xo-arena -> .xo-arena (prep subrepo)
This commit is contained in:
parent
b1b7133310
commit
f66ec58a2c
62 changed files with 0 additions and 0 deletions
|
|
@ -1,360 +0,0 @@
|
|||
/** @file DArenaHashMap.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Jan 2026
|
||||
**/
|
||||
|
||||
#include "DArenaHashMap.hpp"
|
||||
#include "random_hash_ops.hpp"
|
||||
#include <xo/randomgen/random_seed.hpp>
|
||||
#include <xo/indentlog/scope.hpp>
|
||||
#include <xo/indentlog/print/tag.hpp>
|
||||
#include <xo/indentlog/print/hex.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace xo {
|
||||
using xo::map::DArenaHashMapUtil;
|
||||
using xo::map::DArenaHashMap;
|
||||
using xo::rng::random_seed;
|
||||
using xo::rng::xoshiro256ss;
|
||||
using utest::UtestTools;
|
||||
using utest::HashMapUtil;
|
||||
|
||||
namespace ut {
|
||||
TEST_CASE("DArenaHashMap-ctor", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map("utest");
|
||||
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-ctor2", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map("utest", 257);
|
||||
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.capacity() == map.groups() * DArenaHashMapUtil::c_group_size);
|
||||
REQUIRE(map.capacity() == std::max(512ul,
|
||||
DArenaHashMapUtil::c_group_size));
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-try-insert", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map("utest");
|
||||
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
|
||||
{
|
||||
auto x = map.try_insert(std::make_pair(1, 11));
|
||||
|
||||
REQUIRE(x.first);
|
||||
REQUIRE(x.second);
|
||||
REQUIRE(!map.empty());
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
REQUIRE(map.load_factor() == 1/16.0);
|
||||
|
||||
/* verify iteration */
|
||||
{
|
||||
size_t n = 0;
|
||||
for (auto & ix : map) {
|
||||
REQUIRE(ix.first == 1);
|
||||
REQUIRE(ix.second == 11);
|
||||
++n;
|
||||
}
|
||||
REQUIRE(n == map.size());
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
{
|
||||
auto x = map.try_insert(std::make_pair(2, 9));
|
||||
|
||||
REQUIRE(x.first);
|
||||
REQUIRE(x.second);
|
||||
REQUIRE(!map.empty());
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
REQUIRE(map.load_factor() == 2/16.0);
|
||||
|
||||
/* verify iteration */
|
||||
{
|
||||
size_t n = 0;
|
||||
for (auto & ix : map) {
|
||||
++n;
|
||||
}
|
||||
REQUIRE(n == map.size());
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
{
|
||||
auto x = map.try_insert(std::make_pair(259, 12));
|
||||
|
||||
REQUIRE(x.first);
|
||||
REQUIRE(x.second);
|
||||
REQUIRE(!map.empty());
|
||||
REQUIRE(map.size() == 3);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
REQUIRE(map.load_factor() == 3/16.0);
|
||||
|
||||
/* verify iteration */
|
||||
{
|
||||
size_t n = 0;
|
||||
for (auto & ix : map) {
|
||||
switch (ix.first) {
|
||||
case 1:
|
||||
REQUIRE(ix.second == 11);
|
||||
break;
|
||||
case 2:
|
||||
REQUIRE(ix.second == 9);
|
||||
break;
|
||||
case 259:
|
||||
REQUIRE(ix.second == 12);
|
||||
break;
|
||||
default:
|
||||
REQUIRE(false);
|
||||
}
|
||||
++n;
|
||||
}
|
||||
REQUIRE(n == map.size());
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
{
|
||||
map.clear();
|
||||
|
||||
REQUIRE(map.empty());
|
||||
REQUIRE(map.size() == 0);
|
||||
REQUIRE(map.groups() == 0);
|
||||
REQUIRE(map.capacity() == 0);
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
/* slightly different starting point, 0 capacity! */
|
||||
{
|
||||
auto x = map.try_insert(std::make_pair(1, 11));
|
||||
|
||||
/* try_insert should fail - no capacity */
|
||||
REQUIRE(!x.first);
|
||||
REQUIRE(!x.second);
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
{
|
||||
/* insert will grow hash table */
|
||||
auto x = map.insert(std::make_pair(1, 11));
|
||||
|
||||
CHECK(x);
|
||||
REQUIRE(!map.empty());
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.groups() == 1);
|
||||
REQUIRE(map.capacity() == DArenaHashMapUtil::c_group_size);
|
||||
REQUIRE(map.load_factor() == 1/16.0);
|
||||
|
||||
/* verify iteration */
|
||||
{
|
||||
size_t n = 0;
|
||||
for (auto & ix : map) {
|
||||
REQUIRE(ix.first == 1);
|
||||
REQUIRE(ix.second == 11);
|
||||
++n;
|
||||
}
|
||||
REQUIRE(n == map.size());
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-try-insert2", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
std::uint64_t seed = 17747889312058974961ul;
|
||||
//random_seed(&seed); // to get new random seed
|
||||
//log && log(xtag("seed", seed));
|
||||
|
||||
auto rgen = xoshiro256ss(seed);
|
||||
|
||||
/* 1. Perform series of tests with increasing scale
|
||||
* 2. Each test may run in two modes:
|
||||
* a. silent fast fail. just report success.
|
||||
* In this mode avoid catch2 REQUIRE
|
||||
* b. noisy. run with logging enabled
|
||||
* This mode automatically invoked when silent mode
|
||||
* observes test failure
|
||||
*/
|
||||
|
||||
for (std::uint32_t n = 0; n <= 8; ) {
|
||||
HashMap hash_map("utest");
|
||||
|
||||
auto test_fn = [&rgen, &hash_map](bool dbg_flag,
|
||||
std::uint32_t n)
|
||||
{
|
||||
bool ok_flag = true;
|
||||
|
||||
ok_flag &= HashMapUtil<HashMap>::random_inserts(n, dbg_flag, &rgen, &hash_map);
|
||||
|
||||
ok_flag &= HashMapUtil<HashMap>::check_forward_iterator(0.0 /*dvalue*/,
|
||||
dbg_flag, hash_map);
|
||||
/* regular forward iterator, but start at hash_map.end() and use operator-- */
|
||||
ok_flag &= HashMapUtil<HashMap>::check_backward_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;
|
||||
};
|
||||
|
||||
bool ok_flag = UtestTools::bimodal_test("DArenaHashMap-try-insert2", test_fn, n);
|
||||
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
else
|
||||
n = 2*n;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-operator-bracket", "[arena][DArenaHashMap]")
|
||||
{
|
||||
scope log(XO_DEBUG(false));
|
||||
|
||||
using HashMap = DArenaHashMap<int, int>;
|
||||
|
||||
HashMap map("utest");
|
||||
|
||||
// copy keys here so we can print stuff
|
||||
std::vector<int> key_v;
|
||||
|
||||
// insert via operator[]
|
||||
map[1] = 100;
|
||||
key_v.push_back(1);
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
map[2] = 200;
|
||||
key_v.push_back(2);
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
map[3] = 300;
|
||||
key_v.push_back(3);
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
REQUIRE(map.size() == 3);
|
||||
|
||||
// read back via operator[]
|
||||
REQUIRE(map[1] == 100);
|
||||
REQUIRE(map[2] == 200);
|
||||
REQUIRE(map[3] == 300);
|
||||
|
||||
// update via operator[]
|
||||
map[2] = 250;
|
||||
REQUIRE(map[2] == 250);
|
||||
REQUIRE(map.size() == 3); // size unchanged
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
// verify via find
|
||||
{
|
||||
auto it = map.find(1);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 100);
|
||||
}
|
||||
{
|
||||
auto it = map.find(2);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 250);
|
||||
}
|
||||
{
|
||||
auto it = map.find(3);
|
||||
REQUIRE(it != map.end());
|
||||
REQUIRE(it->second == 300);
|
||||
}
|
||||
{
|
||||
auto it = map.find(4);
|
||||
REQUIRE(it == map.end());
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
// operator[] on non-existent key creates default entry
|
||||
int & val = map[999];
|
||||
key_v.push_back(999);
|
||||
|
||||
for (uint64_t i_slot = 0, N = map._store()->n_slot_; i_slot < N; ++i_slot) {
|
||||
auto key = map._store()->slots_[i_slot].first;
|
||||
auto ctrl = map._store()->control_
|
||||
[i_slot + DArenaHashMapUtil::c_control_stub];
|
||||
auto isdata = DArenaHashMapUtil::is_data(ctrl);
|
||||
auto [h1,h2] = map._hash(key);
|
||||
|
||||
if ((key != 0)
|
||||
|| (h1 != 0)
|
||||
|| (h2 != 0)
|
||||
|| (ctrl != DArenaHashMapUtil::c_empty_slot)
|
||||
|| isdata
|
||||
) {
|
||||
log && log(xtag("i", i_slot),
|
||||
xtag("key[i]", key),
|
||||
xtag("h1", h1), xtag("h2", h2),
|
||||
xtag("ctrl[i]", (int)ctrl),
|
||||
xtag("isdata", isdata));
|
||||
}
|
||||
}
|
||||
|
||||
REQUIRE(map.verify_ok(verify_policy::chatty()));
|
||||
|
||||
REQUIRE(map.size() == 4);
|
||||
REQUIRE(val == 0); // default-initialized
|
||||
val = 999;
|
||||
REQUIRE(map[999] == 999);
|
||||
}
|
||||
|
||||
TEST_CASE("DArenaHashMap-string_view-key", "[arena][DArenaHashMap]")
|
||||
{
|
||||
using HashMap = DArenaHashMap<std::string_view, int>;
|
||||
|
||||
HashMap map("utest", 1024);
|
||||
|
||||
REQUIRE(map.verify_ok());
|
||||
|
||||
map["hello"] = 42;
|
||||
REQUIRE(map.size() == 1);
|
||||
REQUIRE(map.verify_ok());
|
||||
|
||||
map["world"] = 100;
|
||||
REQUIRE(map.size() == 2);
|
||||
REQUIRE(map.verify_ok());
|
||||
|
||||
REQUIRE(map["hello"] == 42);
|
||||
REQUIRE(map["world"] == 100);
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// - let's try getting lcov to work in xo-umbrella2
|
||||
}
|
||||
}
|
||||
|
||||
/* end DArenaHashMap.test.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue