From f2c25af5217e8ab7e8c00ab3e0084bce2bdf93e8 Mon Sep 17 00:00:00 2001 From: Matt Armstrong Date: Mon, 10 Oct 2022 09:07:42 -0700 Subject: [PATCH 3/4] Check red-black invariants in most places Stefan recently disabled this but I happened to want it back soon after. * src/itree.c (check_subtree): new arg: allow_red_red (check_tree_common): renamed from check_tree, pass allow_red_red through. (check_tree): new function, pass allow_red_red=false (interval_tree_insert): check_tree -> check_tree_common with allow_red_red=true. --- src/itree.c | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/itree.c b/src/itree.c index 60bc2b5c89..9dfac57930 100644 --- a/src/itree.c +++ b/src/itree.c @@ -222,9 +222,9 @@ itree_init (void) }; static struct check_subtree_result -check_subtree (struct interval_node *node, uintmax_t tree_otick, - int max_depth, ptrdiff_t offset, ptrdiff_t min_begin, - ptrdiff_t max_begin) +check_subtree (struct interval_node *node, bool allow_red_red, + uintmax_t tree_otick, int max_depth, ptrdiff_t offset, + ptrdiff_t min_begin, ptrdiff_t max_begin) { struct check_subtree_result result = { .complete = false, .size = 0, @@ -251,22 +251,14 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick, eassert (node->left == ITREE_NULL || node->left->parent == node); eassert (node->right == ITREE_NULL || node->right->parent == node); - /* We don't normally check the RB invariants here (neither the - absence of red+red nor the equal-black-depth), so that we can use - this check even while the tree is temporarily breaking some of - those invarints. You can enable them if you want. */ - if (false) + if (!allow_red_red && node->red) { /* If a node is red then both of its children are black. Red nodes cannot have red parents. */ - if (node->red) - { - eassert (node->left == ITREE_NULL - || node->left->red == false); - eassert (node->right == ITREE_NULL - || node->right->red == false); - eassert (node->parent == ITREE_NULL || !node->parent->red); - } + eassert (node->left == ITREE_NULL || node->left->red == false); + eassert (node->right == ITREE_NULL + || node->right->red == false); + eassert (node->parent == ITREE_NULL || !node->parent->red); } eassert (node->offset == 0 || node->otick < tree_otick); @@ -282,11 +274,11 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick, eassert (end <= limit); struct check_subtree_result left_result - = check_subtree (node->left, tree_otick, max_depth - 1, offset, - min_begin, begin); + = check_subtree (node->left, allow_red_red, tree_otick, + max_depth - 1, offset, min_begin, begin); struct check_subtree_result right_result - = check_subtree (node->right, tree_otick, max_depth - 1, offset, - begin, max_begin); + = check_subtree (node->right, allow_red_red, tree_otick, + max_depth - 1, offset, begin, max_begin); eassert (left_result.limit <= limit); eassert (right_result.limit <= limit); @@ -311,7 +303,8 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick, return result; } -/* Validate invariants for TREE. +/* Validate invariants for TREE. If ALLOW_RED_RED, red nodes with red + children are considered valid. This runs in constant time when ENABLE_OVERLAY_CHECKING is 0 (i.e. Emacs is not configured with @@ -320,7 +313,7 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick, entire tree and validates all invariants. */ static bool -check_tree (struct interval_tree *tree) +check_tree_common (struct interval_tree *tree, bool allow_red_red) { eassert (tree != NULL); eassert (tree->size >= 0); @@ -343,8 +336,8 @@ check_tree (struct interval_tree *tree) struct interval_node *node = tree->root; struct check_subtree_result result - = check_subtree (node, tree->otick, max_height, node->offset, - PTRDIFF_MIN, PTRDIFF_MAX); + = check_subtree (node, allow_red_red, tree->otick, max_height, + node->offset, PTRDIFF_MIN, PTRDIFF_MAX); eassert (result.complete); eassert (result.size == tree->size); @@ -352,6 +345,13 @@ check_tree (struct interval_tree *tree) return true; } +/* Syntactic sugar for check_tree(tree, false) */ +static bool +check_tree (struct interval_tree *tree) +{ + return check_tree_common (tree, /* allow_red_red= */ false); +} + /* +===================================================================================+ * | Stack * +===================================================================================+ */ @@ -616,7 +616,7 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node) /* Fix/update the tree */ ++tree->size; - eassert (check_tree (tree)); + eassert (check_tree_common (tree, /* allow_red_red= */ true)); interval_tree_insert_fix (tree, node); } -- 2.35.1