aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatt Armstrong2022-10-10 09:07:42 -0700
committerMatt Armstrong2022-10-10 19:37:51 -0700
commit51a8e375ebea2e6e05eed623bddfb323b8e408f0 (patch)
treebdf6ee616d2b349617869b66943e14c4ef483ad9 /src
parent67b9e89a5aa0052b1abdcd8971a0fa83f52e13a5 (diff)
downloademacs-51a8e375ebea2e6e05eed623bddfb323b8e408f0.tar.gz
emacs-51a8e375ebea2e6e05eed623bddfb323b8e408f0.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/itree.c80
1 files changed, 46 insertions, 34 deletions
diff --git a/src/itree.c b/src/itree.c
index aa8a5f7f3b9..7ac400398bd 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -222,7 +222,8 @@ struct check_subtree_result
222}; 222};
223 223
224static struct check_subtree_result 224static struct check_subtree_result
225check_subtree (struct interval_node *node, uintmax_t tree_otick, 225check_subtree (struct interval_node *node,
226 bool check_red_black_invariants, uintmax_t tree_otick,
226 int max_depth, ptrdiff_t offset, ptrdiff_t min_begin, 227 int max_depth, ptrdiff_t offset, ptrdiff_t min_begin,
227 ptrdiff_t max_begin) 228 ptrdiff_t max_begin)
228{ 229{
@@ -251,23 +252,9 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick,
251 eassert (node->left == ITREE_NULL || node->left->parent == node); 252 eassert (node->left == ITREE_NULL || node->left->parent == node);
252 eassert (node->right == ITREE_NULL || node->right->parent == node); 253 eassert (node->right == ITREE_NULL || node->right->parent == node);
253 254
254 /* We don't normally check the RB invariants here (neither the 255 /* No red nodes have red parents. */
255 absence of red+red nor the equal-black-depth), so that we can use 256 if (check_red_black_invariants && node->parent != ITREE_NULL)
256 this check even while the tree is temporarily breaking some of 257 eassert (!node->red || !node->parent->red);
257 those invarints. You can enable them if you want. */
258 if (false)
259 {
260 /* If a node is red then both of its children are black. Red
261 nodes cannot have red parents. */
262 if (node->red)
263 {
264 eassert (node->left == ITREE_NULL
265 || node->left->red == false);
266 eassert (node->right == ITREE_NULL
267 || node->right->red == false);
268 eassert (node->parent == ITREE_NULL || !node->parent->red);
269 }
270 }
271 258
272 /* Validate otick. A node's otick must be <= to the tree's otick 259 /* Validate otick. A node's otick must be <= to the tree's otick
273 and <= to its parent's otick. 260 and <= to its parent's otick.
@@ -292,11 +279,13 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick,
292 eassert (end <= limit); 279 eassert (end <= limit);
293 280
294 struct check_subtree_result left_result 281 struct check_subtree_result left_result
295 = check_subtree (node->left, tree_otick, max_depth - 1, offset, 282 = check_subtree (node->left, check_red_black_invariants,
296 min_begin, begin); 283 tree_otick, max_depth - 1, offset, min_begin,
284 begin);
297 struct check_subtree_result right_result 285 struct check_subtree_result right_result
298 = check_subtree (node->right, tree_otick, max_depth - 1, offset, 286 = check_subtree (node->right, check_red_black_invariants,
299 begin, max_begin); 287 tree_otick, max_depth - 1, offset, begin,
288 max_begin);
300 289
301 eassert (left_result.limit <= limit); 290 eassert (left_result.limit <= limit);
302 eassert (right_result.limit <= limit); 291 eassert (right_result.limit <= limit);
@@ -304,24 +293,29 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick,
304 result.complete = left_result.complete && right_result.complete; 293 result.complete = left_result.complete && right_result.complete;
305 if (result.complete) 294 if (result.complete)
306 { 295 {
307 /* Every path from a node to a descendent leaf contains the same
308 number of black nodes. Often said this way: all nodes have
309 the same "black height". */
310 eassert (left_result.black_height == right_result.black_height);
311 result.black_height
312 = (node->red ? 0 : 1) + left_result.black_height;
313
314 result.size = 1 + left_result.size + right_result.size; 296 result.size = 1 + left_result.size + right_result.size;
315 result.limit 297 result.limit
316 = max (end, max (left_result.limit, right_result.limit)); 298 = max (end, max (left_result.limit, right_result.limit));
317 299
318 eassert (limit == result.limit); 300 eassert (limit == result.limit);
301
302 if (check_red_black_invariants)
303 {
304 /* Every path from a node to a descendent leaf contains the
305 same number of black nodes. Often said this way: all
306 nodes have the same "black height". */
307 eassert (left_result.black_height
308 == right_result.black_height);
309 result.black_height
310 = (node->red ? 0 : 1) + left_result.black_height;
311 }
319 } 312 }
320 313
321 return result; 314 return result;
322} 315}
323 316
324/* Validate invariants for TREE. 317/* Validate invariants for TREE. If CHECK_RED_BLACK_INVARIANTS, red
318 nodes with red children are considered invalid.
325 319
326 This runs in constant time when ENABLE_OVERLAY_CHECKING is 0 320 This runs in constant time when ENABLE_OVERLAY_CHECKING is 0
327 (i.e. Emacs is not configured with 321 (i.e. Emacs is not configured with
@@ -330,7 +324,8 @@ check_subtree (struct interval_node *node, uintmax_t tree_otick,
330 entire tree and validates all invariants. 324 entire tree and validates all invariants.
331*/ 325*/
332static bool 326static bool
333check_tree (struct interval_tree *tree) 327check_tree_common (struct interval_tree *tree,
328 bool check_red_black_invariants)
334{ 329{
335 eassert (tree != NULL); 330 eassert (tree != NULL);
336 eassert (tree->size >= 0); 331 eassert (tree->size >= 0);
@@ -353,8 +348,9 @@ check_tree (struct interval_tree *tree)
353 348
354 struct interval_node *node = tree->root; 349 struct interval_node *node = tree->root;
355 struct check_subtree_result result 350 struct check_subtree_result result
356 = check_subtree (node, tree->otick, max_height, node->offset, 351 = check_subtree (node, check_red_black_invariants, tree->otick,
357 PTRDIFF_MIN, PTRDIFF_MAX); 352 max_height, node->offset, PTRDIFF_MIN,
353 PTRDIFF_MAX);
358 eassert (result.complete); 354 eassert (result.complete);
359 eassert (result.size == tree->size); 355 eassert (result.size == tree->size);
360 356
@@ -362,6 +358,22 @@ check_tree (struct interval_tree *tree)
362 return true; 358 return true;
363} 359}
364 360
361/* Check the tree with all invariant checks enabled. */
362static bool
363check_tree (struct interval_tree *tree)
364{
365 return check_tree_common (tree, true);
366}
367
368/* Check the tree with all invariant checks enabled, except for the
369 red-black tree invariants. Useful for asserting the other
370 invariants while inserting or removing. */
371static bool
372check_tree_no_rb (struct interval_tree *tree)
373{
374 return check_tree_common (tree, false);
375}
376
365/* +===================================================================================+ 377/* +===================================================================================+
366 * | Stack 378 * | Stack
367 * +===================================================================================+ */ 379 * +===================================================================================+ */
@@ -626,7 +638,7 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node)
626 638
627 /* Fix/update the tree */ 639 /* Fix/update the tree */
628 ++tree->size; 640 ++tree->size;
629 eassert (check_tree (tree)); 641 eassert (check_tree_no_rb (tree));
630 interval_tree_insert_fix (tree, node); 642 interval_tree_insert_fix (tree, node);
631} 643}
632 644