diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/itree.c | 156 |
1 files changed, 126 insertions, 30 deletions
diff --git a/src/itree.c b/src/itree.c index bbab70dac7c..aa8a5f7f3b9 100644 --- a/src/itree.c +++ b/src/itree.c | |||
| @@ -205,14 +205,44 @@ itree_init (void) | |||
| 205 | iter = interval_generator_create (NULL); | 205 | iter = interval_generator_create (NULL); |
| 206 | } | 206 | } |
| 207 | 207 | ||
| 208 | static ptrdiff_t | 208 | struct check_subtree_result |
| 209 | recurse_check_tree (struct interval_node *node, uintmax_t tree_otick, | 209 | { |
| 210 | ptrdiff_t offset, ptrdiff_t min_begin, | 210 | /* Were all nodes visited? */ |
| 211 | ptrdiff_t max_begin, intmax_t *size) | 211 | bool complete; |
| 212 | |||
| 213 | /* Computed node count of the tree. */ | ||
| 214 | int size; | ||
| 215 | |||
| 216 | /* Computed limit of the tree (max END). */ | ||
| 217 | ptrdiff_t limit; | ||
| 218 | |||
| 219 | /* Computed black height of the tree (count of black nodes from the | ||
| 220 | bottom up to the root). */ | ||
| 221 | int black_height; | ||
| 222 | }; | ||
| 223 | |||
| 224 | static struct check_subtree_result | ||
| 225 | check_subtree (struct interval_node *node, uintmax_t tree_otick, | ||
| 226 | int max_depth, ptrdiff_t offset, ptrdiff_t min_begin, | ||
| 227 | ptrdiff_t max_begin) | ||
| 212 | { | 228 | { |
| 229 | struct check_subtree_result result = { .complete = false, | ||
| 230 | .size = 0, | ||
| 231 | .limit = PTRDIFF_MIN, | ||
| 232 | .black_height = 0 }; | ||
| 213 | if (node == ITREE_NULL) | 233 | if (node == ITREE_NULL) |
| 214 | return PTRDIFF_MIN; | 234 | { |
| 215 | ++*size; | 235 | /* Every nil node of a Red-Black tree is black */ |
| 236 | result.black_height = 1; | ||
| 237 | result.complete = true; | ||
| 238 | return result; | ||
| 239 | }; | ||
| 240 | |||
| 241 | if (max_depth == 0) | ||
| 242 | { | ||
| 243 | result.complete = false; | ||
| 244 | return result; | ||
| 245 | } | ||
| 216 | 246 | ||
| 217 | /* Validate structure. */ | 247 | /* Validate structure. */ |
| 218 | eassert ( | 248 | eassert ( |
| @@ -221,14 +251,35 @@ recurse_check_tree (struct interval_node *node, uintmax_t tree_otick, | |||
| 221 | eassert (node->left == ITREE_NULL || node->left->parent == node); | 251 | eassert (node->left == ITREE_NULL || node->left->parent == node); |
| 222 | eassert (node->right == ITREE_NULL || node->right->parent == node); | 252 | eassert (node->right == ITREE_NULL || node->right->parent == node); |
| 223 | 253 | ||
| 224 | /* We don't check the RB invariants here (neither the absence of | 254 | /* We don't normally check the RB invariants here (neither the |
| 225 | red+red nor the equal-black-depth), so that we can use this check | 255 | absence of red+red nor the equal-black-depth), so that we can use |
| 226 | even while the tree is temporarily breaking some of those invarints. */ | 256 | this check even while the tree is temporarily breaking some of |
| 227 | /* Red nodes cannot have red parents. */ | 257 | those invarints. You can enable them if you want. */ |
| 228 | /* eassert (node->parent == ITREE_NULL | 258 | if (false) |
| 229 | || !(node->red && node->parent->red)); */ | 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 | } | ||
| 230 | 271 | ||
| 231 | eassert (node->offset == 0 || node->otick < tree_otick); | 272 | /* Validate otick. A node's otick must be <= to the tree's otick |
| 273 | and <= to its parent's otick. | ||
| 274 | |||
| 275 | Note: we cannot assert that (NODE.otick == NODE.parent.otick) | ||
| 276 | implies (NODE.offset == 0) because interval_tree_inherit_offset() | ||
| 277 | doesn't always update otick. It could, but it is not clear there | ||
| 278 | is a need. */ | ||
| 279 | eassert (node->otick <= tree_otick); | ||
| 280 | eassert (node->parent == ITREE_NULL | ||
| 281 | || node->otick <= node->parent->otick); | ||
| 282 | eassert (node->otick != tree_otick || node->offset == 0); | ||
| 232 | 283 | ||
| 233 | offset += node->offset; | 284 | offset += node->offset; |
| 234 | ptrdiff_t begin = node->begin + offset; | 285 | ptrdiff_t begin = node->begin + offset; |
| @@ -240,29 +291,74 @@ recurse_check_tree (struct interval_node *node, uintmax_t tree_otick, | |||
| 240 | eassert (begin <= max_begin); | 291 | eassert (begin <= max_begin); |
| 241 | eassert (end <= limit); | 292 | eassert (end <= limit); |
| 242 | 293 | ||
| 243 | ptrdiff_t left_limit | 294 | struct check_subtree_result left_result |
| 244 | = recurse_check_tree (node->left, tree_otick, offset, min_begin, | 295 | = check_subtree (node->left, tree_otick, max_depth - 1, offset, |
| 245 | begin, size); | 296 | min_begin, begin); |
| 246 | ptrdiff_t right_limit | 297 | struct check_subtree_result right_result |
| 247 | = recurse_check_tree (node->right, tree_otick, offset, begin, | 298 | = check_subtree (node->right, tree_otick, max_depth - 1, offset, |
| 248 | max_begin, size); | 299 | begin, max_begin); |
| 249 | eassert (left_limit <= limit); | 300 | |
| 250 | eassert (right_limit <= limit); | 301 | eassert (left_result.limit <= limit); |
| 251 | eassert (limit == max (end, max (left_limit, right_limit))); | 302 | eassert (right_result.limit <= limit); |
| 252 | return limit; | 303 | |
| 304 | result.complete = left_result.complete && right_result.complete; | ||
| 305 | if (result.complete) | ||
| 306 | { | ||
| 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; | ||
| 315 | result.limit | ||
| 316 | = max (end, max (left_result.limit, right_result.limit)); | ||
| 317 | |||
| 318 | eassert (limit == result.limit); | ||
| 319 | } | ||
| 320 | |||
| 321 | return result; | ||
| 253 | } | 322 | } |
| 254 | 323 | ||
| 324 | /* Validate invariants for TREE. | ||
| 325 | |||
| 326 | This runs in constant time when ENABLE_OVERLAY_CHECKING is 0 | ||
| 327 | (i.e. Emacs is not configured with | ||
| 328 | "--enable_checking=yes,overlays"). In this mode it can't check all | ||
| 329 | the invariants. When ENABLE_OVERLAY_CHECKING is 1 it checks the | ||
| 330 | entire tree and validates all invariants. | ||
| 331 | */ | ||
| 255 | static bool | 332 | static bool |
| 256 | check_tree (struct interval_tree *tree) | 333 | check_tree (struct interval_tree *tree) |
| 257 | { | 334 | { |
| 258 | eassert (tree != NULL); | 335 | eassert (tree != NULL); |
| 336 | eassert (tree->size >= 0); | ||
| 259 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); | 337 | eassert ((tree->size == 0) == (tree->root == ITREE_NULL)); |
| 260 | if (tree->root == ITREE_NULL) | 338 | if (tree->root == ITREE_NULL) |
| 261 | return true; | 339 | return true; |
| 262 | 340 | ||
| 263 | intmax_t size = 0; | 341 | /* Limit the traversal depth to what 'interval_tree_max_height' |
| 264 | recurse_check_tree (tree->root, tree->otick, 0, | 342 | returns. Later, verify that this is enough height to traverse |
| 265 | PTRDIFF_MIN, PTRDIFF_MAX, &size); | 343 | the complete tree. */ |
| 344 | const int max_height = interval_tree_max_height (tree); | ||
| 345 | eassert (max_height >= 0); | ||
| 346 | eassert (max_height <= 120); | ||
| 347 | |||
| 348 | /* NOTE: if this check is too expensive an easy fix is to reduce | ||
| 349 | max_height to for large trees, then relax the assertion on | ||
| 350 | result.complete. Assertions in check_subtree will still be made | ||
| 351 | at the bottom of the tree (where they are probably most | ||
| 352 | interesting), but some will be skipped closer to the root. */ | ||
| 353 | |||
| 354 | struct interval_node *node = tree->root; | ||
| 355 | struct check_subtree_result result | ||
| 356 | = check_subtree (node, tree->otick, max_height, node->offset, | ||
| 357 | PTRDIFF_MIN, PTRDIFF_MAX); | ||
| 358 | eassert (result.complete); | ||
| 359 | eassert (result.size == tree->size); | ||
| 360 | |||
| 361 | /* The only way this function fails is eassert(). */ | ||
| 266 | return true; | 362 | return true; |
| 267 | } | 363 | } |
| 268 | 364 | ||
| @@ -1145,10 +1241,10 @@ interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node) | |||
| 1145 | } | 1241 | } |
| 1146 | 1242 | ||
| 1147 | /* Offsets can be inherited from dirty nodes (with out of date | 1243 | /* Offsets can be inherited from dirty nodes (with out of date |
| 1148 | otick) during insert and remove. Offsets aren't inherited | 1244 | otick) during removal, since we do not travel down from the root |
| 1149 | downward from the root for these operations so rotations are | 1245 | in that case. In this case rotations are performed on |
| 1150 | performed on potentially "dirty" nodes, where we only make sure | 1246 | potentially "dirty" nodes, where we only need to make sure the |
| 1151 | the *local* offsets are all zero. */ | 1247 | *local* offsets are zero. */ |
| 1152 | 1248 | ||
| 1153 | if (node->offset) | 1249 | if (node->offset) |
| 1154 | { | 1250 | { |