diff options
| author | Stefan Monnier | 2022-10-11 11:17:44 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2022-10-11 11:17:44 -0400 |
| commit | 12836db6e4e09378d41301b3d4e1fcff58132d3a (patch) | |
| tree | 0a49a20b0ca6cfa602571620aa2e1970f42328ee /src/itree.c | |
| parent | da0387f0fe79f577fae6d5453c758f600e1ae495 (diff) | |
| download | emacs-12836db6e4e09378d41301b3d4e1fcff58132d3a.tar.gz emacs-12836db6e4e09378d41301b3d4e1fcff58132d3a.zip | |
itree.c (check_tree): Simplify
* src/itree.c (struct check_subtree_result): Remove `complete`.
(check_subtree): Remove `max_depth` arg (and adjust callers).
Use 0 as black-depth of empty tree.
Remove redundant `node->parent` check (already performed by the caller).
(check_tree): Replace with `check_tree_common` (update all callers).
Check the root's `parent` field.
(check_tree_no_rb): Delete function, inlined in its sole caller.
(interval_tree_remove): Add call to `check_tree` (without RB checks)
before `interval_tree_remove_fix`. Move update of `size`
field accordingly.
Diffstat (limited to 'src/itree.c')
| -rw-r--r-- | src/itree.c | 132 |
1 files changed, 32 insertions, 100 deletions
diff --git a/src/itree.c b/src/itree.c index 9c5d8ce1426..ef623d0850a 100644 --- a/src/itree.c +++ b/src/itree.c | |||
| @@ -221,55 +221,27 @@ itree_init (void) | |||
| 221 | 221 | ||
| 222 | struct check_subtree_result | 222 | struct check_subtree_result |
| 223 | { | 223 | { |
| 224 | /* Were all nodes visited? */ | 224 | int size; /* Node count of the tree. */ |
| 225 | bool complete; | 225 | ptrdiff_t limit; /* Limit of the tree (max END). */ |
| 226 | 226 | int black_height; /* Black height of the tree. */ | |
| 227 | /* Computed node count of the tree. */ | ||
| 228 | int size; | ||
| 229 | |||
| 230 | /* Computed limit of the tree (max END). */ | ||
| 231 | ptrdiff_t limit; | ||
| 232 | |||
| 233 | /* Computed black height of the tree (count of black nodes from the | ||
| 234 | bottom up to the root). */ | ||
| 235 | int black_height; | ||
| 236 | }; | 227 | }; |
| 237 | 228 | ||
| 238 | static struct check_subtree_result | 229 | static struct check_subtree_result |
| 239 | check_subtree (struct interval_node *node, | 230 | check_subtree (struct interval_node *node, |
| 240 | bool check_red_black_invariants, uintmax_t tree_otick, | 231 | bool check_red_black_invariants, uintmax_t tree_otick, |
| 241 | int max_depth, ptrdiff_t offset, ptrdiff_t min_begin, | 232 | ptrdiff_t offset, ptrdiff_t min_begin, |
| 242 | ptrdiff_t max_begin) | 233 | ptrdiff_t max_begin) |
| 243 | { | 234 | { |
| 244 | struct check_subtree_result result = { .complete = false, | 235 | struct check_subtree_result result = { .size = 0, |
| 245 | .size = 0, | ||
| 246 | .limit = PTRDIFF_MIN, | 236 | .limit = PTRDIFF_MIN, |
| 247 | .black_height = 0 }; | 237 | .black_height = 0 }; |
| 248 | if (node == ITREE_NULL) | 238 | if (node == ITREE_NULL) |
| 249 | { | 239 | return result; |
| 250 | /* Every nil node of a Red-Black tree is black */ | ||
| 251 | result.black_height = 1; | ||
| 252 | result.complete = true; | ||
| 253 | return result; | ||
| 254 | }; | ||
| 255 | |||
| 256 | if (max_depth == 0) | ||
| 257 | { | ||
| 258 | result.complete = false; | ||
| 259 | return result; | ||
| 260 | } | ||
| 261 | 240 | ||
| 262 | /* Validate structure. */ | 241 | /* Validate structure. */ |
| 263 | eassert ( | ||
| 264 | node->parent == ITREE_NULL | ||
| 265 | || (node->parent->left == node || node->parent->right == node)); | ||
| 266 | eassert (node->left == ITREE_NULL || node->left->parent == node); | 242 | eassert (node->left == ITREE_NULL || node->left->parent == node); |
| 267 | eassert (node->right == ITREE_NULL || node->right->parent == node); | 243 | eassert (node->right == ITREE_NULL || node->right->parent == node); |
| 268 | 244 | ||
| 269 | /* No red nodes have red parents. */ | ||
| 270 | if (check_red_black_invariants && node->parent != ITREE_NULL) | ||
| 271 | eassert (!node->red || !node->parent->red); | ||
| 272 | |||
| 273 | /* Validate otick. A node's otick must be <= to the tree's otick | 245 | /* Validate otick. A node's otick must be <= to the tree's otick |
| 274 | and <= to its parent's otick. | 246 | and <= to its parent's otick. |
| 275 | 247 | ||
| @@ -278,8 +250,7 @@ check_subtree (struct interval_node *node, | |||
| 278 | doesn't always update otick. It could, but it is not clear there | 250 | doesn't always update otick. It could, but it is not clear there |
| 279 | is a need. */ | 251 | is a need. */ |
| 280 | eassert (node->otick <= tree_otick); | 252 | eassert (node->otick <= tree_otick); |
| 281 | eassert (node->parent == ITREE_NULL | 253 | eassert (node->parent == ITREE_NULL || node->otick <= node->parent->otick); |
| 282 | || node->otick <= node->parent->otick); | ||
| 283 | eassert (node->otick != tree_otick || node->offset == 0); | 254 | eassert (node->otick != tree_otick || node->offset == 0); |
| 284 | 255 | ||
| 285 | offset += node->offset; | 256 | offset += node->offset; |
| @@ -294,37 +265,24 @@ check_subtree (struct interval_node *node, | |||
| 294 | 265 | ||
| 295 | struct check_subtree_result left_result | 266 | struct check_subtree_result left_result |
| 296 | = check_subtree (node->left, check_red_black_invariants, | 267 | = check_subtree (node->left, check_red_black_invariants, |
| 297 | tree_otick, max_depth - 1, offset, min_begin, | 268 | tree_otick, offset, min_begin, begin); |
| 298 | begin); | ||
| 299 | struct check_subtree_result right_result | 269 | struct check_subtree_result right_result |
| 300 | = check_subtree (node->right, check_red_black_invariants, | 270 | = check_subtree (node->right, check_red_black_invariants, |
| 301 | tree_otick, max_depth - 1, offset, begin, | 271 | tree_otick, offset, begin, max_begin); |
| 302 | max_begin); | ||
| 303 | 272 | ||
| 304 | eassert (left_result.limit <= limit); | 273 | eassert (left_result.limit <= limit); |
| 305 | eassert (right_result.limit <= limit); | 274 | eassert (right_result.limit <= limit); |
| 275 | eassert (limit == max (end, max (left_result.limit, right_result.limit))); | ||
| 306 | 276 | ||
| 307 | result.complete = left_result.complete && right_result.complete; | 277 | if (check_red_black_invariants) |
| 308 | if (result.complete) | ||
| 309 | { | 278 | { |
| 310 | result.size = 1 + left_result.size + right_result.size; | 279 | eassert (left_result.black_height == right_result.black_height); |
| 311 | result.limit | 280 | eassert (node->parent != ITREE_NULL || !node->red || !node->parent->red); |
| 312 | = max (end, max (left_result.limit, right_result.limit)); | ||
| 313 | |||
| 314 | eassert (limit == result.limit); | ||
| 315 | |||
| 316 | if (check_red_black_invariants) | ||
| 317 | { | ||
| 318 | /* Every path from a node to a descendent leaf contains the | ||
| 319 | same number of black nodes. Often said this way: all | ||
| 320 | nodes have the same "black height". */ | ||
| 321 | eassert (left_result.black_height | ||
| 322 | == right_result.black_height); | ||
| 323 | result.black_height | ||
| 324 | = (node->red ? 0 : 1) + left_result.black_height; | ||
| 325 | } | ||
| 326 | } | 281 | } |
| 327 | 282 | ||
| 283 | result.size = 1 + left_result.size + right_result.size; | ||
| 284 | result.limit = limit; | ||
| 285 | result.black_height = (node->red ? 0 : 1) + left_result.black_height; | ||
| 328 | return result; | 286 | return result; |
| 329 | } | 287 | } |
| 330 | 288 | ||
| @@ -338,8 +296,8 @@ check_subtree (struct interval_node *node, | |||
| 338 | entire tree and validates all invariants. | 296 | entire tree and validates all invariants. |
| 339 | */ | 297 | */ |
| 340 | static bool | 298 | static bool |
| 341 | check_tree_common (struct interval_tree *tree, | 299 | check_tree (struct interval_tree *tree, |
| 342 | bool check_red_black_invariants) | 300 | bool check_red_black_invariants) |
| 343 | { | 301 | { |
| 344 | eassert (null_is_sane ()); | 302 | eassert (null_is_sane ()); |
| 345 | 303 | ||
| @@ -348,48 +306,19 @@ check_tree_common (struct interval_tree *tree, | |||
| 348 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); | 306 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); |
| 349 | if (tree->root == ITREE_NULL) | 307 | if (tree->root == ITREE_NULL) |
| 350 | return true; | 308 | return true; |
| 351 | 309 | eassert (tree->root->parent == ITREE_NULL); | |
| 352 | /* Limit the traversal depth to what 'interval_tree_max_height' | ||
| 353 | returns. Later, verify that this is enough height to traverse | ||
| 354 | the complete tree. */ | ||
| 355 | const int max_height = interval_tree_max_height (tree); | ||
| 356 | eassert (max_height >= 0); | ||
| 357 | eassert (max_height <= 120); | ||
| 358 | |||
| 359 | /* NOTE: if this check is too expensive an easy fix is to reduce | ||
| 360 | max_height to for large trees, then relax the assertion on | ||
| 361 | result.complete. Assertions in check_subtree will still be made | ||
| 362 | at the bottom of the tree (where they are probably most | ||
| 363 | interesting), but some will be skipped closer to the root. */ | ||
| 364 | 310 | ||
| 365 | struct interval_node *node = tree->root; | 311 | struct interval_node *node = tree->root; |
| 366 | struct check_subtree_result result | 312 | struct check_subtree_result result |
| 367 | = check_subtree (node, check_red_black_invariants, tree->otick, | 313 | = check_subtree (node, check_red_black_invariants, tree->otick, |
| 368 | max_height, node->offset, PTRDIFF_MIN, | 314 | node->offset, PTRDIFF_MIN, |
| 369 | PTRDIFF_MAX); | 315 | PTRDIFF_MAX); |
| 370 | eassert (result.complete); | ||
| 371 | eassert (result.size == tree->size); | 316 | eassert (result.size == tree->size); |
| 372 | 317 | ||
| 373 | /* The only way this function fails is eassert(). */ | 318 | /* The only way this function fails is eassert(). */ |
| 374 | return true; | 319 | return true; |
| 375 | } | 320 | } |
| 376 | 321 | ||
| 377 | /* Check the tree with all invariant checks enabled. */ | ||
| 378 | static bool | ||
| 379 | check_tree (struct interval_tree *tree) | ||
| 380 | { | ||
| 381 | return check_tree_common (tree, true); | ||
| 382 | } | ||
| 383 | |||
| 384 | /* Check the tree with all invariant checks enabled, except for the | ||
| 385 | red-black tree invariants. Useful for asserting the other | ||
| 386 | invariants while inserting or removing. */ | ||
| 387 | static bool | ||
| 388 | check_tree_no_rb (struct interval_tree *tree) | ||
| 389 | { | ||
| 390 | return check_tree_common (tree, false); | ||
| 391 | } | ||
| 392 | |||
| 393 | /* +===================================================================================+ | 322 | /* +===================================================================================+ |
| 394 | * | Stack | 323 | * | Stack |
| 395 | * +===================================================================================+ */ | 324 | * +===================================================================================+ */ |
| @@ -613,7 +542,7 @@ static void | |||
| 613 | interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | 542 | interval_tree_insert (struct interval_tree *tree, struct interval_node *node) |
| 614 | { | 543 | { |
| 615 | eassert (node && node->begin <= node->end && node != ITREE_NULL); | 544 | eassert (node && node->begin <= node->end && node != ITREE_NULL); |
| 616 | eassert (check_tree (tree)); | 545 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ |
| 617 | 546 | ||
| 618 | struct interval_node *parent = ITREE_NULL; | 547 | struct interval_node *parent = ITREE_NULL; |
| 619 | struct interval_node *child = tree->root; | 548 | struct interval_node *child = tree->root; |
| @@ -654,7 +583,7 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | |||
| 654 | 583 | ||
| 655 | /* Fix/update the tree */ | 584 | /* Fix/update the tree */ |
| 656 | ++tree->size; | 585 | ++tree->size; |
| 657 | eassert (check_tree_no_rb (tree)); | 586 | eassert (check_tree (tree, false)); /* FIXME: Too expensive. */ |
| 658 | interval_tree_insert_fix (tree, node); | 587 | interval_tree_insert_fix (tree, node); |
| 659 | } | 588 | } |
| 660 | 589 | ||
| @@ -815,7 +744,7 @@ struct interval_node* | |||
| 815 | interval_tree_remove (struct interval_tree *tree, struct interval_node *node) | 744 | interval_tree_remove (struct interval_tree *tree, struct interval_node *node) |
| 816 | { | 745 | { |
| 817 | eassert (interval_tree_contains (tree, node)); | 746 | eassert (interval_tree_contains (tree, node)); |
| 818 | eassert (check_tree (tree)); | 747 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ |
| 819 | 748 | ||
| 820 | /* `broken`, if non-NULL, holds a node that's being moved up to where a black | 749 | /* `broken`, if non-NULL, holds a node that's being moved up to where a black |
| 821 | node used to be, which may thus require further fixups in its parents | 750 | node used to be, which may thus require further fixups in its parents |
| @@ -884,15 +813,18 @@ interval_tree_remove (struct interval_tree *tree, struct interval_node *node) | |||
| 884 | interval_tree_propagate_limit (min_parent); | 813 | interval_tree_propagate_limit (min_parent); |
| 885 | } | 814 | } |
| 886 | interval_tree_propagate_limit (node->parent); | 815 | interval_tree_propagate_limit (node->parent); |
| 816 | --tree->size; | ||
| 887 | 817 | ||
| 888 | if (broken) | 818 | if (broken) |
| 889 | interval_tree_remove_fix (tree, broken, broken_parent); | 819 | { |
| 820 | eassert (check_tree (tree, false)); /* FIXME: Too expensive. */ | ||
| 821 | interval_tree_remove_fix (tree, broken, broken_parent); | ||
| 822 | } | ||
| 890 | 823 | ||
| 891 | node->right = node->left = node->parent = NULL; | 824 | node->right = node->left = node->parent = NULL; |
| 892 | --tree->size; | ||
| 893 | 825 | ||
| 894 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); | 826 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); |
| 895 | eassert (check_tree (tree)); | 827 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ |
| 896 | 828 | ||
| 897 | return node; | 829 | return node; |
| 898 | } | 830 | } |
| @@ -1462,10 +1394,10 @@ interval_tree_insert_fix (struct interval_tree *tree, struct interval_node *node | |||
| 1462 | } | 1394 | } |
| 1463 | } | 1395 | } |
| 1464 | 1396 | ||
| 1465 | /* The root may have been changed to red due to the algorithm. Set | 1397 | /* The root may have been changed to red due to the algorithm. |
| 1466 | it to black so that property #5 is satisfied. */ | 1398 | Set it to black so that property #5 is satisfied. */ |
| 1467 | tree->root->red = false; | 1399 | tree->root->red = false; |
| 1468 | eassert (check_tree (tree)); | 1400 | eassert (check_tree (tree, true)); /* FIXME: Too expensive. */ |
| 1469 | } | 1401 | } |
| 1470 | 1402 | ||
| 1471 | /* Return accumulated offsets of NODE's parents. */ | 1403 | /* Return accumulated offsets of NODE's parents. */ |