xo-arena: DArenaHashMap: improve sentinel abstraction for control
This commit is contained in:
parent
25ab314492
commit
dcd8ced1cd
2 changed files with 27 additions and 69 deletions
|
|
@ -64,6 +64,8 @@ namespace xo {
|
||||||
using size_type = std::size_t;
|
using size_type = std::size_t;
|
||||||
using control_type = std::uint8_t;
|
using control_type = std::uint8_t;
|
||||||
|
|
||||||
|
/** control: mask for sentinel states **/
|
||||||
|
static constexpr uint8_t c_sentinel_mask = 0xF0;
|
||||||
/** control: sentinel for empty slot **/
|
/** control: sentinel for empty slot **/
|
||||||
static constexpr uint8_t c_empty_slot = 0xFF;
|
static constexpr uint8_t c_empty_slot = 0xFF;
|
||||||
/** control: tombstone for deleted slot **/
|
/** control: tombstone for deleted slot **/
|
||||||
|
|
@ -75,6 +77,16 @@ namespace xo {
|
||||||
/** max load factor **/
|
/** max load factor **/
|
||||||
static constexpr float c_max_load_factor = 0.875;
|
static constexpr float c_max_load_factor = 0.875;
|
||||||
|
|
||||||
|
/** control: true for sentinel values **/
|
||||||
|
static constexpr bool is_sentinel(control_type ctrl) {
|
||||||
|
return ctrl & c_sentinel_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** control; true for non-sentinel values **/
|
||||||
|
static constexpr bool is_data(control_type ctrl) {
|
||||||
|
return 0 == (ctrl & c_sentinel_mask);
|
||||||
|
}
|
||||||
|
|
||||||
/** find smallest multiple k : k * c_group_size >= n **/
|
/** find smallest multiple k : k * c_group_size >= n **/
|
||||||
static size_type lub_group_mult(size_t n) {
|
static size_type lub_group_mult(size_t n) {
|
||||||
return (n + c_group_size - 1) / c_group_size;
|
return (n + c_group_size - 1) / c_group_size;
|
||||||
|
|
@ -288,7 +300,7 @@ namespace xo {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_sentinel() const {
|
bool is_sentinel() const {
|
||||||
return ((*ctrl_ == c_tombstone) || (*ctrl_ == c_empty_slot));
|
return DArenaHashMapUtil::is_sentinel(*ctrl_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -605,20 +617,18 @@ namespace xo {
|
||||||
uint8_t ctrl = store_.control_[i];
|
uint8_t ctrl = store_.control_[i];
|
||||||
value_type & kv_pair = store_.slots_[i];
|
value_type & kv_pair = store_.slots_[i];
|
||||||
|
|
||||||
if ((ctrl != c_empty_slot)
|
if (DArenaHashMapUtil::is_data(ctrl)) {
|
||||||
&& (ctrl != c_tombstone))
|
size_type h = hash_(kv_pair.first);
|
||||||
{
|
auto chk = this->_try_insert_aux(h, kv_pair, &store_2x);
|
||||||
size_type h = hash_(kv_pair.first);
|
|
||||||
auto chk = this->_try_insert_aux(h, kv_pair, &store_2x);
|
|
||||||
|
|
||||||
if (!chk.second) {
|
if (!chk.second) {
|
||||||
// shenanigans - something isn't right.
|
// shenanigans - something isn't right.
|
||||||
// - may have run out of memory
|
// - may have run out of memory
|
||||||
assert(false);
|
assert(false);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->store_ = std::move(store_2x);
|
this->store_ = std::move(store_2x);
|
||||||
|
|
@ -778,7 +788,7 @@ namespace xo {
|
||||||
size_type occupied_count = 0;
|
size_type occupied_count = 0;
|
||||||
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
||||||
uint8_t c = store_.control_[i];
|
uint8_t c = store_.control_[i];
|
||||||
if ((c != c_empty_slot) && (c != c_tombstone)) {
|
if (DArenaHashMapUtil::is_data(c)) {
|
||||||
++occupied_count;
|
++occupied_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -793,7 +803,7 @@ namespace xo {
|
||||||
/* SM4.1.1: if control_[i] is non-sentinel, control_[i] = hash_(slots_[i].first) & 0x7f */
|
/* SM4.1.1: if control_[i] is non-sentinel, control_[i] = hash_(slots_[i].first) & 0x7f */
|
||||||
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
||||||
uint8_t c = store_.control_[i];
|
uint8_t c = store_.control_[i];
|
||||||
if ((c != c_empty_slot) && (c != c_tombstone)) {
|
if (DArenaHashMapUtil::is_data(c)) {
|
||||||
uint8_t expected_h2 = hash_(store_.slots_[i].first) & 0x7f;
|
uint8_t expected_h2 = hash_(store_.slots_[i].first) & 0x7f;
|
||||||
if (c != expected_h2) {
|
if (c != expected_h2) {
|
||||||
return policy.report_error(log,
|
return policy.report_error(log,
|
||||||
|
|
@ -810,12 +820,12 @@ namespace xo {
|
||||||
*/
|
*/
|
||||||
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
||||||
uint8_t c = store_.control_[i];
|
uint8_t c = store_.control_[i];
|
||||||
if ((c != c_empty_slot) && (c != c_tombstone)) {
|
if (DArenaHashMapUtil::is_data(c)) {
|
||||||
size_type h = (hash_(store_.slots_[i].first) >> 7) & (store_.n_slot_ - 1);
|
size_type h = (hash_(store_.slots_[i].first) >> 7) & (store_.n_slot_ - 1);
|
||||||
size_type j = h;
|
size_type j = h;
|
||||||
while (j != i) {
|
while (j != i) {
|
||||||
uint8_t cj = store_.control_[j];
|
uint8_t cj = store_.control_[j];
|
||||||
if ((cj == c_empty_slot) || (cj == c_tombstone)) {
|
if (DArenaHashMapUtil::is_sentinel(cj)) {
|
||||||
return policy.report_error(log,
|
return policy.report_error(log,
|
||||||
c_self, ": expect non-empty slot in probe range [h..i]",
|
c_self, ": expect non-empty slot in probe range [h..i]",
|
||||||
xtag("i", i),
|
xtag("i", i),
|
||||||
|
|
@ -831,7 +841,7 @@ namespace xo {
|
||||||
/* SM4.2: if control_[i] is empty or tombstone, slots_[i].first = key_type() */
|
/* SM4.2: if control_[i] is empty or tombstone, slots_[i].first = key_type() */
|
||||||
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
for (size_type i = 0; i < store_.n_slot_; ++i) {
|
||||||
uint8_t c = store_.control_[i];
|
uint8_t c = store_.control_[i];
|
||||||
if ((c == c_empty_slot) || (c == c_tombstone)) {
|
if (DArenaHashMapUtil::is_sentinel(c)) {
|
||||||
if (!(store_.slots_[i].first == key_type())) {
|
if (!(store_.slots_[i].first == key_type())) {
|
||||||
return policy.report_error(log,
|
return policy.report_error(log,
|
||||||
c_self, ": expect empty/tombstone slot has default key",
|
c_self, ": expect empty/tombstone slot has default key",
|
||||||
|
|
|
||||||
|
|
@ -596,58 +596,6 @@ namespace utest {
|
||||||
} /*check_bidirectional_iterator*/
|
} /*check_bidirectional_iterator*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NOT_YET
|
|
||||||
/** Require:
|
|
||||||
* - tree has keys [0..n-1], where n=treesize()
|
|
||||||
* - tree valu at key k is dvalue+10*k
|
|
||||||
*
|
|
||||||
* @p catch_flag. control behavior at each test assertion.
|
|
||||||
* true -> log to console + interact with catch2
|
|
||||||
* false -> verify iteration behavior for return code.
|
|
||||||
*
|
|
||||||
**/
|
|
||||||
static bool
|
|
||||||
check_reduced_sum(uint32_t dvalue,
|
|
||||||
bool catch_flag,
|
|
||||||
Tree const & rbtree)
|
|
||||||
{
|
|
||||||
using xo::scope;
|
|
||||||
using xo::xtag;
|
|
||||||
|
|
||||||
scope log(XO_DEBUG(catch_flag));
|
|
||||||
|
|
||||||
/* -> false if/when check fails */
|
|
||||||
bool ok_flag = true;
|
|
||||||
|
|
||||||
size_t const n = rbtree.size();
|
|
||||||
|
|
||||||
for(size_t i = 0; i < n; ++i) {
|
|
||||||
/* compute reduction up to key=i */
|
|
||||||
double reduced_upto
|
|
||||||
= rbtree.reduce_lub(i /*key*/,
|
|
||||||
true /*is_closed*/);
|
|
||||||
|
|
||||||
double reduced = (i+1) * (5*i + dvalue);
|
|
||||||
|
|
||||||
INFO(tostr(xtag("i", i), xtag("n", n),
|
|
||||||
xtag("tree.reduced_upto", reduced_upto),
|
|
||||||
xtag("reduced", reduced),
|
|
||||||
xtag("dvalue", dvalue)));
|
|
||||||
|
|
||||||
auto glb_ix = rbtree.cfind_sum_glb(reduced);
|
|
||||||
|
|
||||||
REQUIRE_ORFAIL(ok_flag, catch_flag, reduced_upto == reduced);
|
|
||||||
REQUIRE_ORFAIL(ok_flag, catch_flag, glb_ix.is_dereferenceable());
|
|
||||||
/* glb_ix is truth-y */
|
|
||||||
REQUIRE_ORFAIL(ok_flag, catch_flag, glb_ix);
|
|
||||||
|
|
||||||
REQUIRE_ORFAIL(ok_flag, catch_flag, glb_ix->first == i);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok_flag;
|
|
||||||
} /*check_reduced_sum*/
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NOT_YET
|
#ifdef NOT_YET
|
||||||
/* Require:
|
/* Require:
|
||||||
* - *p_rbtree has keys [0..n-1], where n=rbtree.size()
|
* - *p_rbtree has keys [0..n-1], where n=rbtree.size()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue