xo-ordinaltree: expand unittest + debug logging

This commit is contained in:
Roland Conybeare 2025-12-05 18:38:29 -05:00
commit 3d06980b42
10 changed files with 298 additions and 71 deletions

View file

@ -580,14 +580,19 @@ namespace xo {
* R is reduced-value for right child
* RB8. RedBlackTree.size() equals the #of nodes in tree
*/
bool verify_ok(bool /*throw_flag_not_implemented*/ = true) const {
bool verify_ok(bool /*throw_flag_not_implemented*/ = true) const
{
using xo::scope;
using xo::tostr;
using xo::xtag;
constexpr const char *c_self = "RedBlackTree::verify_ok";
scope log(XO_DEBUG(debug_flag_));
scope log(XO_DEBUG(debug_flag_), xtag("size", size_));
if (debug_flag_) {
// look forward to upgrading this to pp
this->display_to_log();
}
/* RB0. */
if (root_ == nullptr) {
@ -610,7 +615,8 @@ namespace xo {
int32_t black_height = 0;
/* n_node: #of nodes in this->root_ */
size_t n_node = RbUtil::verify_subtree_ok(this->reduce_fn_,
size_t n_node = RbUtil::verify_subtree_ok(this->node_alloc_,
this->reduce_fn_,
this->root_,
&black_height);

View file

@ -572,7 +572,7 @@ namespace xo {
for (uint32_t iter = 0;; ++iter) {
if (c_excessive_verify_enabled)
RbTreeUtil::verify_subtree_ok(reduce_fn, G, nullptr /*&black_height*/);
RbTreeUtil::verify_subtree_ok(alloc, reduce_fn, G, nullptr /*&black_height*/);
if (log.enabled()) {
if (G) {
@ -720,7 +720,7 @@ namespace xo {
RbTreeUtil::rotate(alloc, d, P, reduce_fn, debug_flag, pp_root);
if (c_excessive_verify_enabled)
RbTreeUtil::verify_subtree_ok(reduce_fn, S, nullptr /*&black_height*/);
RbTreeUtil::verify_subtree_ok(alloc, reduce_fn, S, nullptr /*&black_height*/);
/* (relabel S->P etc. for merged control flow below) */
R = P;
@ -755,7 +755,7 @@ namespace xo {
log("verify subtree at GG", xtag("GG", GG),
xtag("GG.key", GG->key()));
RbTreeUtil::verify_subtree_ok(reduce_fn, GG, nullptr /*&black_height*/);
RbTreeUtil::verify_subtree_ok(alloc, reduce_fn, GG, nullptr /*&black_height*/);
RbTreeUtil::display_aux(D_Invalid, GG, 0 /*depth*/, &log);
log("fixup complete");
@ -841,11 +841,28 @@ namespace xo {
RbNode * new_node = RbNode::make_leaf(alloc,
kv_pair,
reduce_fn.leaf(kv_pair.second));
log && log(xtag("act", "N gets new leaf"),
xtag("N", N),
xtag("d", d),
xtag("new_node", new_node));
N->assign_child_reparent(alloc,
d,
new_node);
{
using allocator_traits = xo::gc::gc_allocator_traits<NodeAllocator>;
typename allocator_traits::gc_interface_type gc(alloc);
const void * src = N;
const void * const * lhs
= reinterpret_cast<const void * const *>(&(N->child_v_[0]));
XO_EXPECT(gc.check_write_barrier(src, lhs, false),
tostr("RbTreeUtil::insert_aux",
": expect mlog entry for xgen child pointer"));
}
assert(is_red(N->child(d)));
/* recalculate Node sizes on path [root .. N] */
@ -1679,13 +1696,16 @@ namespace xo {
*
* returns the #of nodes in subtree rooted at N.
*/
static size_t verify_subtree_ok(Reduce const & reduce_fn,
template <typename NodeAllocator>
static size_t verify_subtree_ok(NodeAllocator & alloc,
Reduce const & reduce_fn,
RbNode const * N,
int32_t * p_black_height)
{
using xo::scope;
using xo::xtag;
using xo::print::ccs;
using allocator_traits = xo::gc::gc_allocator_traits<NodeAllocator>;
constexpr char const *c_self = "RbTreeUtil::verify_subtree_ok";
@ -1699,12 +1719,15 @@ namespace xo {
/* establish on first leaf node encountered */
uint32_t black_height = 0;
typename allocator_traits::gc_interface_type gc(alloc);
auto verify_fn = [c_self,
&gc,
&reduce_fn,
&i_node,
&last_key,
&i_black_height,
&black_height] (RbNode const *x,
&black_height] (RbNode const * x,
uint32_t bd)
{
XO_EXPECT(x->_is_forwarded() == false,
@ -1712,6 +1735,17 @@ namespace xo {
xtag("i", i_node), xtag("node[i]", x)
));
if (x->parent()) {
const void * src = x;
const void * const * lhs = reinterpret_cast<const void * const *>(&(x->parent_));
XO_EXPECT(gc.check_write_barrier(src, lhs, false),
tostr(c_self, (": expect mlog entry for xgen parent pointer"),
xtag("i", i_node), xtag("node[i]", x),
xtag("key[i]", x->key()),
xtag("parent", x->parent())));
}
/* RB2. if c=x->child(d), then c->parent()=x */
if (x->left_child()) {
@ -1721,6 +1755,17 @@ namespace xo {
xtag("key[i]", x->key()),
xtag("child", x->left_child())
));
{
const void * parent = x;
const void * const * lhs = reinterpret_cast<const void * const *>(&(x->child_v_[0]));
XO_EXPECT(gc.check_write_barrier(parent, lhs, false),
tostr(c_self, (": expect mlog entry for xgen left child pointer"),
xtag("i", i_node), xtag("node[i]", x),
xtag("key[i]", x->key()),
xtag("child", x->left_child())));
}
XO_EXPECT(x == x->left_child()->parent(),
tostr(c_self, (": expect symmetric child/parent pointers"),
@ -1731,6 +1776,7 @@ namespace xo {
xtag("child.parent", x->left_child()->parent_),
xtag("child.parent._is_forwarded", x->left_child()->parent_->_is_forwarded())
));
}
if (x->right_child()) {
@ -1741,6 +1787,17 @@ namespace xo {
xtag("child", x->right_child())
));
{
const void * parent = x;
const void * const * lhs = reinterpret_cast<const void * const *>(&(x->child_v_[1]));
XO_EXPECT(gc.check_write_barrier(parent, lhs, false),
tostr(c_self, (": expect mlog entry for xgen right child pointer"),
xtag("i", i_node), xtag("node[i]", x),
xtag("key[i]", x->key()),
xtag("child", x->right_child())));
}
XO_EXPECT(x == x->right_child()->parent(),
tostr(c_self, ": expect symmetric child/parent pointers",
xtag("i", i_node),
@ -1897,6 +1954,8 @@ namespace xo {
scope log(XO_DEBUG(true /*debug_flag*/));
display_aux(D_Invalid, N, d, &log);
assert(false);
} /*display*/
}; /*RbTreeUtil*/
} /*namespace detail*/