xo-ordinaltree: use Compare parameter throughout

This commit is contained in:
Roland Conybeare 2025-12-06 14:17:19 -05:00
commit d13d2f54ed
4 changed files with 77 additions and 26 deletions

View file

@ -53,6 +53,9 @@ namespace xo {
* 5. custom key compare
* 6. garbage collector integration
* 7. std library integration
*
* @tparam Compare : default to xo::tree::DefaultThreeWayCompare.
* std::three_way_compare rejects const ref arguments
**/
template <typename Key,
typename Value,
@ -280,7 +283,7 @@ namespace xo {
* on failure, return this->end()
*/
const_iterator find(Key const & x) const {
RbNode * node = RbUtil::find(this->root_, x);
RbNode * node = RbUtil::find(this->root_, x, this->compare_);
if(node) {
return const_iterator(detail::ID_Forward, detail::IL_Regular, node);
@ -290,7 +293,7 @@ namespace xo {
} /*find*/
iterator find(Key const & x) {
RbNode * node = RbUtil::find(this->root_, x);
RbNode * node = RbUtil::find(this->root_, x, this->compare_);
if (node) {
return const_iterator(detail::ID_Forward, detail::IL_Regular, node);
@ -313,8 +316,11 @@ namespace xo {
*
* even when ix.is_dereferenceable() is false
*/
const_iterator find_glb(Key const & k, bool is_closed) const {
RbNode * node = RbUtil::find_glb(this->root_, k, is_closed);
const_iterator find_glb(Key const & key, bool is_closed) const {
RbNode * node = RbUtil::find_glb(this->root_,
key,
this->compare_,
is_closed);
if (node) {
return const_iterator(detail::ID_Forward,
@ -337,7 +343,7 @@ namespace xo {
{
//scope log(XO_DEBUG(true), xtag("variant", "readonly"), xtag("key", k));
RbNode const * node = RbUtil::find(this->root_, k);
RbNode const * node = RbUtil::find(this->root_, k, this->compare_);
return RbTreeConstLhs(this, node);
} /*operator[]*/
@ -391,7 +397,8 @@ namespace xo {
* return reduce_fn.nil() if K is empty
*/
ReducedValue reduce_lub(Key const &lub_key, bool is_closed) const {
return RbUtil::reduce_lub(lub_key,
return RbUtil::reduce_lub(this->compare_,
lub_key,
this->reduce_fn_,
is_closed,
this->root_);
@ -548,7 +555,8 @@ namespace xo {
RbNode * adj_root = this->root_;
bool retval = RbUtil::erase_aux(this->node_alloc_,
bool retval = RbUtil::erase_aux(this->compare_,
this->node_alloc_,
key,
this->reduce_fn_,
debug_flag_,

View file

@ -65,7 +65,7 @@ namespace xo {
ReducedValue const & leaf_rv) {
using traits = xo::gc::gc_allocator_traits<NodeAllocator>;
/* verify Node is constructible. instead of relying on traits::construct */
/* verify Node is constructible. instead of immediately attempting traits::construct */
static_assert(std::is_constructible_v<Node,
value_type const &,
rvpair_type const &>);

View file

@ -198,13 +198,14 @@ namespace xo {
return nullptr;
} /*prev_inorder_node*/
/* compute value of reduce applied to the set K of all keys k[j] in subtree N
* with:
/* compute value of reduce applied to the set K of all keys k[j]
* in subtree N with:
* k[j] <= lub_key if is_closed = true
* k[j] < lub_key if is_closed = false
* return reduce_fn.nil() if K is empty
*/
static ReducedValue reduce_lub(Key const & lub_key,
static ReducedValue reduce_lub(Compare const & key_cmp,
Key const & lub_key,
Reduce const & reduce_fn,
bool is_closed,
RbNode * N)
@ -215,7 +216,9 @@ namespace xo {
if (!N)
return retval;
if ((N->key() < lub_key) || (is_closed && (N->key() == lub_key))) {
auto cmp = key_cmp(N->key(), lub_key);
if ((cmp < 0) || (is_closed && (cmp == 0))) {
/* all keys k[i] in left subtree of N satisfy k[i] < lub_key
* apply reduce to:
* - left subtree of N
@ -332,15 +335,17 @@ namespace xo {
/* find node in x with key k
* return nullptr iff no such node exists.
*/
static RbNode * find(RbNode * x, Key const & k) {
static RbNode * find(RbNode * x, Key const & k, Compare const & key_cmp) {
for (;;) {
if (!x)
return nullptr;
if (k < x->key()) {
auto cmp = key_cmp(k, x->key());
if (cmp < 0) {
/* search in left subtree */
x = x->left_child();
} else if (k == x->key()) {
} else if (cmp == 0) {
return x;
} else /* k > x->key() */ {
x = x->right_child();
@ -359,12 +364,15 @@ namespace xo {
static RbNode * find_glb_aux(RbNode * x,
RbNode * h,
Key const & k,
Compare const & key_cmp,
bool is_closed) {
for (;;) {
if (!x)
return h;
if (x->key() < k) {
auto cmp = key_cmp(x->key(), k);
if (cmp < 0) {
/* x.key is a lower bound for k */
if (x->right_child() == nullptr) {
@ -380,7 +388,7 @@ namespace xo {
h = x;
x = x->right_child();
continue;
} else if (is_closed && (x->key() == k)) {
} else if (is_closed && (cmp == 0)) {
/* x.key is exact match */
return x;
} else {
@ -400,8 +408,8 @@ namespace xo {
* is_open. if true, allow result with N->key = k exactly
* if false, require N->key < k
*/
static RbNode * find_glb(RbNode * x, Key const & k, bool is_closed) {
return find_glb_aux(x, nullptr, k, is_closed);
static RbNode * find_glb(RbNode * x, const Key & k, const Compare & key_cmp, bool is_closed) {
return find_glb_aux(x, nullptr, k, key_cmp, is_closed);
} /*find_glb*/
#ifdef NOT_IN_USE
@ -410,7 +418,9 @@ namespace xo {
* is_open. if true, allow result with N->key = k exactly
* if false, require N->key > k
*/
static RbNode *find_lub(RbNode *x, Key const &k, bool is_closed) {
static RbNode *find_lub(RbNode * x, const Key & k, const Compare & key_cmp, bool is_closed) {
auto cmp = key_cmp(x->key(), k);
if (x->key() > k) {
/* x.key is an upper bound for k */
if (x->left_child() == nullptr) {
@ -828,7 +838,7 @@ namespace xo {
return std::make_pair(false, N);
}
d = (cmp < 0 /*(kv_pair.first < N->key())*/ ? D_Left : D_Right);
d = ((cmp < 0 /*(kv_pair.first < N->key())*/) ? D_Left : D_Right);
/* insert into left subtree somewhere */
RbNode * C = N->child(d);
@ -1372,7 +1382,8 @@ namespace xo {
* return true if a node was removed; false otherwise.
*/
template <typename NodeAllocator>
static bool erase_aux(NodeAllocator & alloc,
static bool erase_aux(Compare const & key_cmp,
NodeAllocator & alloc,
Key const & k,
Reduce const & reduce_fn,
bool debug_flag,
@ -1404,9 +1415,11 @@ namespace xo {
*/
/* N is the candidate target node we will be deleting */
N = RbTreeUtil::find_glb(N, k, true /*is_closed*/);
N = RbTreeUtil::find_glb(N, k, key_cmp, true /*is_closed*/);
if (!N || (N->key() != k)) {
auto cmp = key_cmp(N->key(), k);
if (!N || (cmp != 0)) {
/* no node with .key = k present, so cannot remove it */
return false;
}

View file

@ -324,18 +324,48 @@ namespace xo {
.initial_tenured_z_ = 4096,
.incr_gc_threshold_ = 512,
.full_gc_threshold_ = 512,
.debug_flag_ = true
.debug_flag_ = false
}
);
REQUIRE(gc.get());
gc->disable_gc();
REQUIRE(gc->native_gc_statistics().n_gc() == 0);
gp<String> s0 = String::copy(gc.get(), "hello");
REQUIRE(s0->length() == 5);
gp<String> s1 = String::copy(gc.get(), "world!");
/* gp<String> comparison */
REQUIRE(s0 == s0);
REQUIRE((s0 != s0) == false);
REQUIRE((s0 >= s0) == true);
REQUIRE((s0 > s0) == false);
REQUIRE((s0 < s0) == false);
REQUIRE((s0 <= s0) == true);
REQUIRE((s0 == s1) == false);
REQUIRE(s0 != s1);
REQUIRE(s0 < s1);
REQUIRE(s0 <= s1);
REQUIRE((s0 > s1) == false);
REQUIRE((s0 >= s1) == false);
/* verify that we can allocate gp<Strings> through gc::allocator template.
*/
static_assert(std::is_constructible_v<gp<String>>);
//using Allocator = xo::gc::allocator<gp<String>>;
//using NodeAllocator = xo::gc::allocator<std::pair<const gp<String>, int>>;
//using RbNode = Node<gp<String>, int, SumReduce<int>, NodeAllocator>;
REQUIRE(true);
}
} /*namespace ut*/