diff --git a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp index f052e482..0770d60b 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/RedBlackTree.hpp @@ -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 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_, diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp index 2bbe2cd8..6a390a2f 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/Node.hpp @@ -65,7 +65,7 @@ namespace xo { ReducedValue const & leaf_rv) { using traits = xo::gc::gc_allocator_traits; - /* 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); diff --git a/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp b/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp index d7d2ab76..01169d3b 100644 --- a/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp +++ b/xo-ordinaltree/include/xo/ordinaltree/rbtree/RbTreeUtil.hpp @@ -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 - 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; } diff --git a/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp b/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp index 9de4a50f..53a94104 100644 --- a/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp +++ b/xo-ordinaltree/utest/RedBlackTree-gc.test.cpp @@ -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 s0 = String::copy(gc.get(), "hello"); REQUIRE(s0->length() == 5); + gp s1 = String::copy(gc.get(), "world!"); + + /* gp 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 through gc::allocator template. + */ + + static_assert(std::is_constructible_v>); + //using Allocator = xo::gc::allocator>; + + //using NodeAllocator = xo::gc::allocator, int>>; //using RbNode = Node, int, SumReduce, NodeAllocator>; - REQUIRE(true); + + } } /*namespace ut*/