diff options
| author | Stefan Monnier | 2022-10-09 19:45:26 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2022-10-09 19:45:26 -0400 |
| commit | 7cbeeabc7e6271948e7bb93020c2e4e50c65f384 (patch) | |
| tree | 777b281d62878ab7cc5a12b7e3fbc8952bf95dbc /src/itree.c | |
| parent | 4f3f7aebc957732f4fbe5c799da5367f46607680 (diff) | |
| download | emacs-7cbeeabc7e6271948e7bb93020c2e4e50c65f384.tar.gz emacs-7cbeeabc7e6271948e7bb93020c2e4e50c65f384.zip | |
Tighten up handling of `otick`
Move args between `build_overlay` and `add_buffer_overlay`,
to try and keep buffer positions together with their buffer.
Be more strict in the `otick` values passed to `interval_tree_insert`.
Move a few things around to try and reduce dependencies through `.h` files.
Fix a thinko bug in `check_tree`.
* src/alloc.c (build_overlay): Remove `begin` and `end` args.
* src/buffer.c (add_buffer_overlay): Move from `buffer.h`.
Add `begin` and `end` args.
(copy_overlays): Adjust accordingly.
(Fmake_overlay): Use BUF_BEG and BUF_Z; adjust call to `build_overlay`
and `add_buffer_overlay`.
(Fmove_overlay): Use BUF_BEG and BUF_Z; Use the new `begin` and `end`
args of `add_buffer_overlay` so we don't need to use
`interval_node_set_region` when moving to a new buffer.
(remove_buffer_overlay, set_overlay_region): Move from `buffer.h`.
* src/buffer.h (set_overlay_region, add_buffer_overlay)
(remove_buffer_overlay): Move to `buffer.c`.
(build_overlay): Move from `lisp.h`.
(maybe_alloc_buffer_overlays): Delete function (inline into its only
caller).
* src/itree.c (interval_tree_insert): Move declaration `from buffer.h`.
(check_tree): Fix initial offset in call to `recurse_check_tree`.
Remove redundant check of the `limit` value.
(interval_node_init): Remove `begin` and `end` args.
(interval_tree_insert): Mark it as static.
Assert that the new node's `otick` should already be uptodate and its
new parent as well.
(itree_insert_node): New function.
(interval_tree_insert_gap): Assert the otick of the removed+added nodes
were uptodate and mark them as uptodate again after adjusting
their positions.
(interval_tree_inherit_offset): Check that the parent is at least as
uptodate as the child.
* src/lisp.h (build_overlay): Move to `buffer.h`.
* src/itree.h (interval_node_init): Adjust accordingly.
(interval_tree_insert): Remove declaration.
(itree_insert_node): New declaration.
Diffstat (limited to 'src/itree.c')
| -rw-r--r-- | src/itree.c | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/src/itree.c b/src/itree.c index b57c3cc656f..bbab70dac7c 100644 --- a/src/itree.c +++ b/src/itree.c | |||
| @@ -142,6 +142,7 @@ static void interval_tree_rotate_right (struct interval_tree *, struct interval_ | |||
| 142 | static void interval_tree_insert_fix (struct interval_tree *, struct interval_node *); | 142 | static void interval_tree_insert_fix (struct interval_tree *, struct interval_node *); |
| 143 | static void interval_tree_transplant (struct interval_tree *, struct interval_node *, struct interval_node *); | 143 | static void interval_tree_transplant (struct interval_tree *, struct interval_node *, struct interval_node *); |
| 144 | static struct interval_generator* interval_generator_create (struct interval_tree *); | 144 | static struct interval_generator* interval_generator_create (struct interval_tree *); |
| 145 | static void interval_tree_insert (struct interval_tree *, struct interval_node *); | ||
| 145 | 146 | ||
| 146 | /* The sentinel node, the null node. */ | 147 | /* The sentinel node, the null node. */ |
| 147 | struct interval_node itree_null; | 148 | struct interval_node itree_null; |
| @@ -260,11 +261,8 @@ check_tree (struct interval_tree *tree) | |||
| 260 | return true; | 261 | return true; |
| 261 | 262 | ||
| 262 | intmax_t size = 0; | 263 | intmax_t size = 0; |
| 263 | ptrdiff_t offset = tree->root->offset; | 264 | recurse_check_tree (tree->root, tree->otick, 0, |
| 264 | ptrdiff_t limit | 265 | PTRDIFF_MIN, PTRDIFF_MAX, &size); |
| 265 | = recurse_check_tree (tree->root, tree->otick, offset, | ||
| 266 | PTRDIFF_MIN, PTRDIFF_MAX, &size); | ||
| 267 | eassert (limit == tree->root->limit + offset); | ||
| 268 | return true; | 266 | return true; |
| 269 | } | 267 | } |
| 270 | 268 | ||
| @@ -375,12 +373,11 @@ interval_stack_pop (struct interval_stack *stack) | |||
| 375 | 373 | ||
| 376 | void | 374 | void |
| 377 | interval_node_init (struct interval_node *node, | 375 | interval_node_init (struct interval_node *node, |
| 378 | ptrdiff_t begin, ptrdiff_t end, | ||
| 379 | bool front_advance, bool rear_advance, | 376 | bool front_advance, bool rear_advance, |
| 380 | Lisp_Object data) | 377 | Lisp_Object data) |
| 381 | { | 378 | { |
| 382 | node->begin = begin; | 379 | node->begin = -1; |
| 383 | node->end = max (begin, end); | 380 | node->end = -1; |
| 384 | node->front_advance = front_advance; | 381 | node->front_advance = front_advance; |
| 385 | node->rear_advance = rear_advance; | 382 | node->rear_advance = rear_advance; |
| 386 | node->data = data; | 383 | node->data = data; |
| @@ -488,7 +485,7 @@ interval_tree_size (struct interval_tree *tree) | |||
| 488 | Note, that inserting a node twice results in undefined behaviour. | 485 | Note, that inserting a node twice results in undefined behaviour. |
| 489 | */ | 486 | */ |
| 490 | 487 | ||
| 491 | void | 488 | static void |
| 492 | interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | 489 | interval_tree_insert (struct interval_tree *tree, struct interval_node *node) |
| 493 | { | 490 | { |
| 494 | eassert (node && node->begin <= node->end && node != ITREE_NULL); | 491 | eassert (node && node->begin <= node->end && node != ITREE_NULL); |
| @@ -497,6 +494,9 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | |||
| 497 | struct interval_node *parent = ITREE_NULL; | 494 | struct interval_node *parent = ITREE_NULL; |
| 498 | struct interval_node *child = tree->root; | 495 | struct interval_node *child = tree->root; |
| 499 | uintmax_t otick = tree->otick; | 496 | uintmax_t otick = tree->otick; |
| 497 | /* It's the responsability of the caller to set `otick` on the node, | ||
| 498 | to "confirm" that the begin/end fields are uptodate. */ | ||
| 499 | eassert (node->otick == otick); | ||
| 500 | 500 | ||
| 501 | /* Find the insertion point, accumulate node's offset and update | 501 | /* Find the insertion point, accumulate node's offset and update |
| 502 | ancestors limit values. */ | 502 | ancestors limit values. */ |
| @@ -526,7 +526,7 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | |||
| 526 | node->red = true; | 526 | node->red = true; |
| 527 | node->offset = 0; | 527 | node->offset = 0; |
| 528 | node->limit = node->end; | 528 | node->limit = node->end; |
| 529 | node->otick = otick; | 529 | eassert (node->parent == ITREE_NULL || node->parent->otick >= node->otick); |
| 530 | 530 | ||
| 531 | /* Fix/update the tree */ | 531 | /* Fix/update the tree */ |
| 532 | ++tree->size; | 532 | ++tree->size; |
| @@ -534,6 +534,16 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node) | |||
| 534 | interval_tree_insert_fix (tree, node); | 534 | interval_tree_insert_fix (tree, node); |
| 535 | } | 535 | } |
| 536 | 536 | ||
| 537 | void | ||
| 538 | itree_insert_node (struct interval_tree *tree, struct interval_node *node, | ||
| 539 | ptrdiff_t begin, ptrdiff_t end) | ||
| 540 | { | ||
| 541 | node->begin = begin; | ||
| 542 | node->end = end; | ||
| 543 | node->otick = tree->otick; | ||
| 544 | interval_tree_insert (tree, node); | ||
| 545 | } | ||
| 546 | |||
| 537 | /* Return true, if NODE is a member of TREE. */ | 547 | /* Return true, if NODE is a member of TREE. */ |
| 538 | 548 | ||
| 539 | static bool | 549 | static bool |
| @@ -849,6 +859,7 @@ interval_tree_insert_gap (struct interval_tree *tree, ptrdiff_t pos, ptrdiff_t l | |||
| 849 | { | 859 | { |
| 850 | if (length <= 0 || tree->root == ITREE_NULL) | 860 | if (length <= 0 || tree->root == ITREE_NULL) |
| 851 | return; | 861 | return; |
| 862 | uintmax_t ootick = tree->otick; | ||
| 852 | 863 | ||
| 853 | /* FIXME: Don't allocate generator/stack anew every time. */ | 864 | /* FIXME: Don't allocate generator/stack anew every time. */ |
| 854 | 865 | ||
| @@ -907,13 +918,16 @@ interval_tree_insert_gap (struct interval_tree *tree, ptrdiff_t pos, ptrdiff_t l | |||
| 907 | } | 918 | } |
| 908 | 919 | ||
| 909 | /* Reinsert nodes starting at POS having front-advance. */ | 920 | /* Reinsert nodes starting at POS having front-advance. */ |
| 921 | uintmax_t notick = tree->otick; | ||
| 910 | nodeptr_and_flag nav; | 922 | nodeptr_and_flag nav; |
| 911 | while ((nav = interval_stack_pop (saved), | 923 | while ((nav = interval_stack_pop (saved), |
| 912 | node = nav_nodeptr (nav))) | 924 | node = nav_nodeptr (nav))) |
| 913 | { | 925 | { |
| 926 | eassert (node->otick == ootick); | ||
| 914 | node->begin += length; | 927 | node->begin += length; |
| 915 | if (node->end != pos || node->rear_advance) | 928 | if (node->end != pos || node->rear_advance) |
| 916 | node->end += length; | 929 | node->end += length; |
| 930 | node->otick = notick; | ||
| 917 | interval_tree_insert (tree, node); | 931 | interval_tree_insert (tree, node); |
| 918 | } | 932 | } |
| 919 | 933 | ||
| @@ -1123,12 +1137,19 @@ interval_tree_update_limit (struct interval_node *node) | |||
| 1123 | static void | 1137 | static void |
| 1124 | interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node) | 1138 | interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node) |
| 1125 | { | 1139 | { |
| 1140 | eassert (node->parent == ITREE_NULL || node->parent->otick >= node->otick); | ||
| 1126 | if (node->otick == otick) | 1141 | if (node->otick == otick) |
| 1127 | { | 1142 | { |
| 1128 | eassert (node->offset == 0); | 1143 | eassert (node->offset == 0); |
| 1129 | return; | 1144 | return; |
| 1130 | } | 1145 | } |
| 1131 | 1146 | ||
| 1147 | /* Offsets can be inherited from dirty nodes (with out of date | ||
| 1148 | otick) during insert and remove. Offsets aren't inherited | ||
| 1149 | downward from the root for these operations so rotations are | ||
| 1150 | performed on potentially "dirty" nodes, where we only make sure | ||
| 1151 | the *local* offsets are all zero. */ | ||
| 1152 | |||
| 1132 | if (node->offset) | 1153 | if (node->offset) |
| 1133 | { | 1154 | { |
| 1134 | node->begin += node->offset; | 1155 | node->begin += node->offset; |
| @@ -1140,17 +1161,9 @@ interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node) | |||
| 1140 | node->right->offset += node->offset; | 1161 | node->right->offset += node->offset; |
| 1141 | node->offset = 0; | 1162 | node->offset = 0; |
| 1142 | } | 1163 | } |
| 1143 | /* FIXME: I wonder when/why this condition can be false, and more | 1164 | /* The only thing that matters about `otick` is whether it's equal to |
| 1144 | generally why we'd want to propagate offsets that may not be | 1165 | that of the tree. We could also "blindly" inherit from parent->otick, |
| 1145 | fully up-to-date. --stef | 1166 | but we need to tree's `otick` anyway for when there's no parent. */ |
| 1146 | |||
| 1147 | Offsets can be inherited from dirty nodes (with out of date | ||
| 1148 | otick) during insert and remove. Offsets aren't inherited | ||
| 1149 | downward from the root for these operations so rotations are | ||
| 1150 | performed on potentially "dirty" nodes. We could fix this by | ||
| 1151 | always inheriting offsets downward from the root for every insert | ||
| 1152 | and remove. --matt | ||
| 1153 | */ | ||
| 1154 | if (node->parent == ITREE_NULL || node->parent->otick == otick) | 1167 | if (node->parent == ITREE_NULL || node->parent->otick == otick) |
| 1155 | node->otick = otick; | 1168 | node->otick = otick; |
| 1156 | } | 1169 | } |