aboutsummaryrefslogtreecommitdiffstats
path: root/src/itree.c
diff options
context:
space:
mode:
authorStefan Monnier2022-10-11 11:17:44 -0400
committerStefan Monnier2022-10-11 11:17:44 -0400
commit12836db6e4e09378d41301b3d4e1fcff58132d3a (patch)
tree0a49a20b0ca6cfa602571620aa2e1970f42328ee /src/itree.c
parentda0387f0fe79f577fae6d5453c758f600e1ae495 (diff)
downloademacs-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.c132
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
222struct check_subtree_result 222struct 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
238static struct check_subtree_result 229static struct check_subtree_result
239check_subtree (struct interval_node *node, 230check_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*/
340static bool 298static bool
341check_tree_common (struct interval_tree *tree, 299check_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. */
378static bool
379check_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. */
387static bool
388check_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
613interval_tree_insert (struct interval_tree *tree, struct interval_node *node) 542interval_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*
815interval_tree_remove (struct interval_tree *tree, struct interval_node *node) 744interval_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. */