Additional debugging

This commit is contained in:
Michael Theall 2018-09-19 23:36:21 -05:00
parent 431fd9aa9c
commit 888569bba1
14 changed files with 149 additions and 45 deletions

View File

@ -4,6 +4,7 @@
*/
#pragma once
#include <3ds/synchronization.h>
#include <stdint.h>
#include <stddef.h>
@ -21,16 +22,21 @@ typedef int (*rbtree_node_comparator_t)(const rbtree_node_t *lhs,
/// An rbtree node.
struct rbtree_node
{
uintptr_t parent_color; ///< Parent color.
rbtree_node_t *child[2]; ///< Node children.
char nodeTag[4]; ///< Node tag.
uintptr_t parent_color; ///< Parent color.
rbtree_node_t *child[2]; ///< Node children.
rbtree_t *tree; ///< Owning tree.
};
/// An rbtree.
struct rbtree
{
char treeTag[4]; ///< Tree tag.
rbtree_node_t *root; ///< Root node.
rbtree_node_comparator_t comparator; ///< Node comparator.
size_t size; ///< Size.
LightLock lock; ///< Tree mutex.
bool busy; ///< Busy flag.
};
#ifdef __cplusplus

View File

@ -5,27 +5,28 @@ void
rbtree_clear(rbtree_t *tree,
rbtree_node_destructor_t destructor)
{
rbtree_set_busy(tree);
rbtree_validate(tree);
rbtree_node_t *node = tree->root;
while(tree->root != NULL)
while(tree->root)
{
while(node->child[LEFT] != NULL)
while(node->child[LEFT])
node = node->child[LEFT];
if(node->child[RIGHT] != NULL)
if(node->child[RIGHT])
node = node->child[RIGHT];
else
{
rbtree_node_t *parent = get_parent(node);
if(parent == NULL)
if(!parent)
tree->root = NULL;
else
parent->child[node != parent->child[LEFT]] = NULL;
if(destructor != NULL)
if(destructor)
(*destructor)(node);
node = parent;
@ -35,4 +36,5 @@ rbtree_clear(rbtree_t *tree,
tree->size = 0;
rbtree_validate(tree);
rbtree_clear_busy(tree);
}

View File

@ -4,7 +4,11 @@
int
rbtree_empty(const rbtree_t *tree)
{
rbtree_set_busy((rbtree_t*)tree);
rbtree_validate(tree);
return tree->root == NULL;
bool empty = !tree->root;
rbtree_clear_busy((rbtree_t*)tree);
return empty;
}

View File

@ -5,12 +5,13 @@ rbtree_node_t*
rbtree_find(const rbtree_t *tree,
const rbtree_node_t *node)
{
rbtree_set_busy((rbtree_t*)tree);
rbtree_validate(tree);
rbtree_node_t *tmp = tree->root;
rbtree_node_t *save = NULL;
while(tmp != NULL)
while(tmp)
{
int rc = (*tree->comparator)(node, tmp);
if(rc < 0)
@ -29,6 +30,7 @@ rbtree_find(const rbtree_t *tree,
}
rbtree_validate(tree);
rbtree_clear_busy((rbtree_t*)tree);
return save;
}

View File

@ -5,9 +5,15 @@ void
rbtree_init(rbtree_t *tree,
rbtree_node_comparator_t comparator)
{
tree->treeTag[3] = 'T';
tree->treeTag[2] = 'R';
tree->treeTag[1] = 'E';
tree->treeTag[0] = 'E';
tree->root = NULL;
tree->comparator = comparator;
tree->size = 0;
tree->busy = false;
LightLock_Init(&tree->lock);
rbtree_validate(tree);
}

View File

@ -6,14 +6,24 @@ do_insert(rbtree_t *tree,
rbtree_node_t *node,
int multi)
{
rbtree_set_busy(tree);
rbtree_validate(tree);
node->nodeTag[3] = 'N';
node->nodeTag[2] = 'O';
node->nodeTag[1] = 'D';
node->nodeTag[0] = 'E';
node->parent_color = 0;
node->child[LEFT] = NULL;
node->child[RIGHT] = NULL;
node->tree = tree;
rbtree_node_t *original = node;
rbtree_node_t **tmp = &tree->root;
rbtree_node_t *parent = NULL;
rbtree_node_t *save = NULL;
while(*tmp != NULL)
while(*tmp)
{
int cmp = (*(tree->comparator))(node, *tmp);
parent = *tmp;
@ -31,9 +41,19 @@ do_insert(rbtree_t *tree,
}
}
if(save != NULL)
if(save)
{
node->nodeTag[3] = 'D';
node->nodeTag[2] = 'O';
node->nodeTag[1] = 'N';
node->nodeTag[0] = 'E';
node->parent_color = 0;
node->child[LEFT] = NULL;
node->child[RIGHT] = NULL;
node->tree = NULL;
rbtree_validate(tree);
rbtree_clear_busy(tree);
return save;
}
@ -83,6 +103,7 @@ do_insert(rbtree_t *tree,
tree->size += 1;
rbtree_validate(tree);
rbtree_clear_busy(tree);
return original;
}

View File

@ -29,7 +29,7 @@ set_red(rbtree_node_t *node)
static inline rbtree_color_t
get_color(const rbtree_node_t *node)
{
if(node == NULL)
if(!node)
return BLACK;
return (rbtree_color_t)(node->parent_color & COLOR_MASK);
}
@ -59,6 +59,12 @@ set_parent(rbtree_node_t *node,
node->parent_color = (get_color(node)) | ((uintptr_t)parent);
}
void
rbtree_set_busy(rbtree_t *tree);
void
rbtree_clear_busy(rbtree_t *tree);
void
rbtree_rotate(rbtree_t *tree,
rbtree_node_t *node,

View File

@ -7,16 +7,16 @@ do_iterate(const rbtree_node_t *node,
{
rbtree_node_t *it = (rbtree_node_t*)node;
if(it->child[next] != NULL)
if(it->child[next])
{
it = it->child[next];
while(it->child[!next] != NULL)
while(it->child[!next])
it = it->child[!next];
}
else
{
rbtree_node_t *parent = get_parent(node);
while(parent != NULL && it == parent->child[next])
while(parent && it == parent->child[next])
{
it = parent;
parent = get_parent(it);

View File

@ -5,35 +5,32 @@ static inline rbtree_node_t*
do_minmax(const rbtree_t *tree,
int max)
{
rbtree_set_busy((rbtree_t*)tree);
rbtree_validate(tree);
rbtree_node_t *node = tree->root;
if(node == NULL)
if(!node)
{
rbtree_clear_busy((rbtree_t*)tree);
return NULL;
}
while(node->child[max] != NULL)
while(node->child[max])
node = node->child[max];
rbtree_clear_busy((rbtree_t*)tree);
return node;
}
rbtree_node_t*
rbtree_min(const rbtree_t *tree)
{
rbtree_node_t *node;
node = do_minmax(tree, LEFT);
return node;
return do_minmax(tree, LEFT);
}
rbtree_node_t*
rbtree_max(const rbtree_t *tree)
{
rbtree_node_t *node;
node = do_minmax(tree, RIGHT);
return node;
return do_minmax(tree, RIGHT);
}

View File

@ -51,15 +51,37 @@ recolor(rbtree_t *tree,
}
}
if(node != NULL)
if(node)
set_black(node);
}
static bool
in_tree(const rbtree_t *tree,
const rbtree_node_t *node)
{
if(tree->root == node)
return true;
const rbtree_node_t *parent = get_parent(node);
while(parent)
{
if(tree->root == parent)
return true;
parent = get_parent(parent);
}
return false;
}
rbtree_node_t*
rbtree_remove(rbtree_t *tree,
rbtree_node_t *node,
rbtree_node_destructor_t destructor)
{
rbtree_set_busy(tree);
if(!in_tree(tree, node))
svcBreak(USERBREAK_PANIC);
rbtree_validate(tree);
rbtree_color_t color;
@ -68,16 +90,16 @@ rbtree_remove(rbtree_t *tree,
next = rbtree_node_next(node);
if(node->child[LEFT] != NULL && node->child[RIGHT] != NULL)
if(node->child[LEFT] && node->child[RIGHT])
{
rbtree_node_t *old = node;
node = node->child[RIGHT];
while(node->child[LEFT] != NULL)
while(node->child[LEFT])
node = node->child[LEFT];
parent = get_parent(old);
if(parent != NULL)
if(parent)
{
if(parent->child[LEFT] == old)
parent->child[LEFT] = node;
@ -95,7 +117,7 @@ rbtree_remove(rbtree_t *tree,
parent = node;
else
{
if(child != NULL)
if(child)
set_parent(child, parent);
parent->child[LEFT] = child;
@ -109,7 +131,7 @@ rbtree_remove(rbtree_t *tree,
}
else
{
if(node->child[LEFT] == NULL)
if(!node->child[LEFT])
child = node->child[RIGHT];
else
child = node->child[LEFT];
@ -117,9 +139,9 @@ rbtree_remove(rbtree_t *tree,
parent = get_parent(node);
color = get_color(node);
if(child != NULL)
if(child)
set_parent(child, parent);
if(parent != NULL)
if(parent)
{
if(parent->child[LEFT] == node)
parent->child[LEFT] = child;
@ -133,12 +155,22 @@ rbtree_remove(rbtree_t *tree,
if(color == BLACK)
recolor(tree, parent, child);
if(destructor != NULL)
original->nodeTag[3] = 'D';
original->nodeTag[2] = 'O';
original->nodeTag[1] = 'N';
original->nodeTag[0] = 'E';
original->parent_color = 0;
original->child[LEFT] = NULL;
original->child[RIGHT] = NULL;
original->tree = NULL;
if(destructor)
(*destructor)(original);
tree->size -= 1;
rbtree_validate(tree);
rbtree_clear_busy(tree);
return next;
}

View File

@ -10,12 +10,12 @@ rbtree_rotate(rbtree_t *tree,
rbtree_node_t *parent = get_parent(node);
node->child[left] = tmp->child[!left];
if(tmp->child[!left] != NULL)
if(tmp->child[!left])
set_parent(tmp->child[!left], node);
tmp->child[!left] = node;
set_parent(tmp, parent);
if(parent != NULL)
if(parent)
{
if(node == parent->child[!left])
parent->child[!left] = tmp;

View File

@ -4,7 +4,11 @@
size_t
rbtree_size(const rbtree_t *tree)
{
rbtree_set_busy((rbtree_t*)tree);
rbtree_validate(tree);
return tree->size;
size_t size = tree->size;
rbtree_clear_busy((rbtree_t*)tree);
return size;
}

View File

@ -9,7 +9,6 @@
abort(); \
} while(0)
void
rbtree_validate(const rbtree_t *tree)
{
@ -23,7 +22,7 @@ rbtree_validate(const rbtree_t *tree)
// root node's parent must be null
if(tree->root)
{
if(get_parent(tree->root) != NULL)
if(get_parent(tree->root))
panic();
}
@ -42,7 +41,7 @@ rbtree_node_validate(const rbtree_t *tree, const rbtree_node_t *node, size_t *si
if(!node) // implies is_black
{
if(black)
*black += 1;
*black = 1;
if(depth)
*depth = 1;
@ -108,14 +107,14 @@ rbtree_node_validate(const rbtree_t *tree, const rbtree_node_t *node, size_t *si
// size is left+right subtrees plus self
if(size)
*size += left_size + right_size + 1;
*size = left_size + right_size + 1;
// all possible paths to leaf nodes must have the same number of black nodes along the path
if(left_black != right_black)
panic();
if(black)
*black += left_black + (is_black(node) ? 1 : 0);
*black = left_black + (is_black(node) ? 1 : 0);
// depth of one subtree must not exceed 2x depth of the other subtree
if(left_depth < right_depth)
@ -134,3 +133,25 @@ rbtree_node_validate(const rbtree_t *tree, const rbtree_node_t *node, size_t *si
*depth = right_depth + 1;
}
}
void
rbtree_set_busy(rbtree_t *tree)
{
LightLock_Lock(&tree->lock);
if(tree->busy)
panic();
tree->busy = true;
LightLock_Unlock(&tree->lock);
}
void
rbtree_clear_busy(rbtree_t *tree)
{
LightLock_Lock(&tree->lock);
if(!tree->busy)
panic();
tree->busy = false;
LightLock_Unlock(&tree->lock);
}

View File

@ -111,7 +111,8 @@ int main(int argc, char *argv[])
else
nodes.emplace_back(node);
if(remove() < chance)
// remove random node
if(remove() <= chance)
{
auto it = std::begin(nodes) + (eng() % nodes.size());
rbtree_remove(&tree, &(*it)->node, IntNodeDestructor);
@ -122,5 +123,7 @@ int main(int argc, char *argv[])
}
}
std::printf("Ended with %zu nodes in tree\n", rbtree_size(&tree));
rbtree_clear(&tree, IntNodeDestructor);
}