]> git.eshelyaron.com Git - emacs.git/commitdiff
Tighten up handling of `otick`
authorStefan Monnier <monnier@iro.umontreal.ca>
Sun, 9 Oct 2022 23:45:26 +0000 (19:45 -0400)
committerStefan Monnier <monnier@iro.umontreal.ca>
Sun, 9 Oct 2022 23:45:26 +0000 (19:45 -0400)
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.

src/alloc.c
src/buffer.c
src/buffer.h
src/itree.c
src/itree.h
src/lisp.h

index 50968b7e121e429ae8cc059b505c72a85f07ed19..00f2991f2502df67cdf58ac39df25419d7e878af 100644 (file)
@@ -3702,19 +3702,17 @@ build_symbol_with_pos (Lisp_Object symbol, Lisp_Object position)
   return val;
 }
 
-/* Return a new overlay with specified START, END and PLIST.  */
+/* Return a new (deleted) overlay with PLIST.  */
 
 Lisp_Object
-build_overlay (ptrdiff_t begin, ptrdiff_t end,
-               bool front_advance, bool rear_advance,
+build_overlay (bool front_advance, bool rear_advance,
                Lisp_Object plist)
 {
   struct Lisp_Overlay *p = ALLOCATE_PSEUDOVECTOR (struct Lisp_Overlay, plist,
                                                  PVEC_OVERLAY);
   Lisp_Object overlay = make_lisp_ptr (p, Lisp_Vectorlike);
   struct interval_node *node = xmalloc (sizeof (*node));
-  interval_node_init (node, begin, end, front_advance,
-                      rear_advance, overlay);
+  interval_node_init (node, front_advance, rear_advance, overlay);
   p->interval = node;
   p->buffer = NULL;
   set_overlay_plist (overlay, plist);
index f59fddcbdebc265ac09a53b949c44280a90f76c8..e1303f2a880bda022e5e1bf61d41dd5b8f73a202 100644 (file)
@@ -638,6 +638,16 @@ even if it is dead.  The return value is never nil.  */)
   return buffer;
 }
 
+static void
+add_buffer_overlay (struct buffer *b, struct Lisp_Overlay *ov,
+                    ptrdiff_t begin, ptrdiff_t end)
+{
+  eassert (! ov->buffer);
+  if (! b->overlays)
+    b->overlays = interval_tree_create ();
+  ov->buffer = b;
+  itree_insert_node (b->overlays, ov->interval, begin, end);
+}
 
 /* Copy overlays of buffer FROM to buffer TO.  */
 
@@ -650,11 +660,10 @@ copy_overlays (struct buffer *from, struct buffer *to)
   ITREE_FOREACH (node, from->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
     {
       Lisp_Object ov = node->data;
-      Lisp_Object copy = build_overlay (node->begin, node->end,
-                                        node->front_advance,
+      Lisp_Object copy = build_overlay (node->front_advance,
                                         node->rear_advance,
                                         Fcopy_sequence (OVERLAY_PLIST (ov)));
-      add_buffer_overlay (to, XOVERLAY (copy));
+      add_buffer_overlay (to, XOVERLAY (copy), node->begin, node->end);
     }
 }
 
@@ -897,6 +906,15 @@ does not run the hooks `kill-buffer-hook',
   return buf;
 }
 
+static void
+remove_buffer_overlay (struct buffer *b, struct Lisp_Overlay *ov)
+{
+  eassert (b->overlays);
+  eassert (ov->buffer == b);
+  interval_tree_remove (ov->buffer->overlays, ov->interval);
+  ov->buffer = NULL;
+}
+
 /* Mark OV as no longer associated with its buffer.  */
 
 static void
@@ -3486,12 +3504,11 @@ for the rear of the overlay advance when text is inserted there
       temp = beg; beg = end; end = temp;
     }
 
-  ptrdiff_t obeg = clip_to_bounds (BEG, XFIXNUM (beg), b->text->z);
-  ptrdiff_t oend = clip_to_bounds (obeg, XFIXNUM (end), b->text->z);
-  ov = build_overlay (obeg, oend,
-                      ! NILP (front_advance),
+  ptrdiff_t obeg = clip_to_bounds (BUF_BEG (b), XFIXNUM (beg), BUF_Z (b));
+  ptrdiff_t oend = clip_to_bounds (obeg, XFIXNUM (end), BUF_Z (b));
+  ov = build_overlay (! NILP (front_advance),
                       ! NILP (rear_advance), Qnil);
-  add_buffer_overlay (b, XOVERLAY (ov));
+  add_buffer_overlay (b, XOVERLAY (ov), obeg, oend);
 
   /* We don't need to redisplay the region covered by the overlay, because
      the overlay has no properties at the moment.  */
@@ -3518,6 +3535,15 @@ modify_overlay (struct buffer *buf, ptrdiff_t start, ptrdiff_t end)
   modiff_incr (&BUF_OVERLAY_MODIFF (buf), 1);
 }
 
+INLINE void
+set_overlay_region (struct Lisp_Overlay *ov, ptrdiff_t begin, ptrdiff_t end)
+{
+  eassert (ov->buffer);
+  begin = clip_to_bounds (BEG, begin, ov->buffer->text->z);
+  end = clip_to_bounds (begin, end, ov->buffer->text->z);
+  interval_node_set_region (ov->buffer->overlays, ov->interval, begin, end);
+}
+
 DEFUN ("move-overlay", Fmove_overlay, Smove_overlay, 3, 4, 0,
        doc: /* Set the endpoints of OVERLAY to BEG and END in BUFFER.
 If BUFFER is omitted, leave OVERLAY in the same buffer it inhabits now.
@@ -3528,7 +3554,6 @@ buffer.  */)
   struct buffer *b, *ob = 0;
   Lisp_Object obuffer;
   specpdl_ref count = SPECPDL_INDEX ();
-  ptrdiff_t n_beg, n_end;
   ptrdiff_t o_beg UNINIT, o_end UNINIT;
 
   CHECK_OVERLAY (overlay);
@@ -3555,11 +3580,14 @@ buffer.  */)
       temp = beg; beg = end; end = temp;
     }
 
-  specbind (Qinhibit_quit, Qt);
+  specbind (Qinhibit_quit, Qt); /* FIXME: Why?  */
 
   obuffer = Foverlay_buffer (overlay);
   b = XBUFFER (buffer);
 
+  ptrdiff_t n_beg = clip_to_bounds (BUF_BEG (b), XFIXNUM (beg), BUF_Z (b));
+  ptrdiff_t n_end = clip_to_bounds (n_beg, XFIXNUM (end), BUF_Z (b));
+
   if (!NILP (obuffer))
     {
       ob = XBUFFER (obuffer);
@@ -3572,13 +3600,11 @@ buffer.  */)
     {
       if (! NILP (obuffer))
         remove_buffer_overlay (XBUFFER (obuffer), XOVERLAY (overlay));
-      add_buffer_overlay (XBUFFER (buffer), XOVERLAY (overlay));
+      add_buffer_overlay (XBUFFER (buffer), XOVERLAY (overlay), n_beg, n_end);
     }
-  /* Set the overlay boundaries, which may clip them.  */
-  set_overlay_region (XOVERLAY (overlay), XFIXNUM (beg), XFIXNUM (end));
-
-  n_beg = OVERLAY_START (overlay);
-  n_end = OVERLAY_END (overlay);
+  else
+    interval_node_set_region (b->overlays, XOVERLAY (overlay)->interval,
+                              n_beg, n_end);
 
   /* If the overlay has changed buffers, do a thorough redisplay.  */
   if (!BASE_EQ (buffer, obuffer))
index a4e3934cad2b39a59d1cb82adee3dc053269f6c5..288acd4f5ee56c5ebce1265b887ab9cba9ed6107 100644 (file)
@@ -1189,6 +1189,7 @@ extern void fix_overlays_before (struct buffer *, ptrdiff_t, ptrdiff_t);
 extern void mmap_set_vars (bool);
 extern void restore_buffer (Lisp_Object);
 extern void set_buffer_if_live (Lisp_Object);
+extern Lisp_Object build_overlay (bool, bool, Lisp_Object);
 
 /* Return B as a struct buffer pointer, defaulting to the current buffer.  */
 
@@ -1408,40 +1409,6 @@ overlay_end (struct Lisp_Overlay *ov)
   return interval_node_end (ov->buffer->overlays, ov->interval);
 }
 
-INLINE void
-set_overlay_region (struct Lisp_Overlay *ov, ptrdiff_t begin, ptrdiff_t end)
-{
-  eassert (ov->buffer);
-  begin = clip_to_bounds (BEG, begin, ov->buffer->text->z);
-  end = clip_to_bounds (begin, end, ov->buffer->text->z);
-  interval_node_set_region (ov->buffer->overlays, ov->interval, begin, end);
-}
-
-INLINE void
-maybe_alloc_buffer_overlays (struct buffer *b)
-{
-  if (! b->overlays)
-    b->overlays = interval_tree_create ();
-}
-
-INLINE void
-add_buffer_overlay (struct buffer *b, struct Lisp_Overlay *ov)
-{
-  eassert (! ov->buffer);
-  maybe_alloc_buffer_overlays (b);
-  ov->buffer = b;
-  interval_tree_insert (b->overlays, ov->interval);
-}
-
-INLINE void
-remove_buffer_overlay (struct buffer *b, struct Lisp_Overlay *ov)
-{
-  eassert (b->overlays);
-  eassert (ov->buffer == b);
-  interval_tree_remove (ov->buffer->overlays, ov->interval);
-  ov->buffer = NULL;
-}
-
 /* Return the start of OV in its buffer, or -1 if OV is not associated
    with any buffer.  */
 
index b57c3cc656f6c9d3a43a2be8bbff3073d2614a7d..bbab70dac7cc6e858d0aad4fcf9d87f4ffa8d9f2 100644 (file)
@@ -142,6 +142,7 @@ static void interval_tree_rotate_right (struct interval_tree *, struct interval_
 static void interval_tree_insert_fix (struct interval_tree *, struct interval_node *);
 static void interval_tree_transplant (struct interval_tree *, struct interval_node *, struct interval_node *);
 static struct interval_generator* interval_generator_create (struct interval_tree *);
+static void interval_tree_insert (struct interval_tree *, struct interval_node *);
 
 /* The sentinel node, the null node.  */
 struct interval_node itree_null;
@@ -260,11 +261,8 @@ check_tree (struct interval_tree *tree)
     return true;
 
   intmax_t size = 0;
-  ptrdiff_t offset = tree->root->offset;
-  ptrdiff_t limit
-    = recurse_check_tree (tree->root, tree->otick, offset,
-                          PTRDIFF_MIN, PTRDIFF_MAX, &size);
-  eassert (limit == tree->root->limit + offset);
+  recurse_check_tree (tree->root, tree->otick, 0,
+                      PTRDIFF_MIN, PTRDIFF_MAX, &size);
   return true;
 }
 
@@ -375,12 +373,11 @@ interval_stack_pop (struct interval_stack *stack)
 
 void
 interval_node_init (struct interval_node *node,
-                    ptrdiff_t begin, ptrdiff_t end,
                     bool front_advance, bool rear_advance,
                     Lisp_Object data)
 {
-  node->begin = begin;
-  node->end = max (begin, end);
+  node->begin = -1;
+  node->end = -1;
   node->front_advance = front_advance;
   node->rear_advance = rear_advance;
   node->data = data;
@@ -488,7 +485,7 @@ interval_tree_size (struct interval_tree *tree)
    Note, that inserting a node twice results in undefined behaviour.
 */
 
-void
+static void
 interval_tree_insert (struct interval_tree *tree, struct interval_node *node)
 {
   eassert (node && node->begin <= node->end && node != ITREE_NULL);
@@ -497,6 +494,9 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node)
   struct interval_node *parent = ITREE_NULL;
   struct interval_node *child = tree->root;
   uintmax_t otick = tree->otick;
+  /* It's the responsability of the caller to set `otick` on the node,
+     to "confirm" that the begin/end fields are uptodate.  */
+  eassert (node->otick == otick);
 
   /* Find the insertion point, accumulate node's offset and update
      ancestors limit values.  */
@@ -526,7 +526,7 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node)
   node->red = true;
   node->offset = 0;
   node->limit = node->end;
-  node->otick = otick;
+  eassert (node->parent == ITREE_NULL || node->parent->otick >= node->otick);
 
   /* Fix/update the tree */
   ++tree->size;
@@ -534,6 +534,16 @@ interval_tree_insert (struct interval_tree *tree, struct interval_node *node)
   interval_tree_insert_fix (tree, node);
 }
 
+void
+itree_insert_node (struct interval_tree *tree, struct interval_node *node,
+                   ptrdiff_t begin, ptrdiff_t end)
+{
+  node->begin = begin;
+  node->end = end;
+  node->otick = tree->otick;
+  interval_tree_insert (tree, node);
+}
+
 /* Return true, if NODE is a member of TREE. */
 
 static bool
@@ -849,6 +859,7 @@ interval_tree_insert_gap (struct interval_tree *tree, ptrdiff_t pos, ptrdiff_t l
 {
   if (length <= 0 || tree->root == ITREE_NULL)
     return;
+  uintmax_t ootick = tree->otick;
 
   /* FIXME: Don't allocate generator/stack anew every time. */
 
@@ -907,13 +918,16 @@ interval_tree_insert_gap (struct interval_tree *tree, ptrdiff_t pos, ptrdiff_t l
     }
 
   /* Reinsert nodes starting at POS having front-advance. */
+  uintmax_t notick = tree->otick;
   nodeptr_and_flag nav;
   while ((nav = interval_stack_pop (saved),
           node = nav_nodeptr (nav)))
     {
+      eassert (node->otick == ootick);
       node->begin += length;
       if (node->end != pos || node->rear_advance)
         node->end += length;
+      node->otick = notick;
       interval_tree_insert (tree, node);
     }
 
@@ -1123,12 +1137,19 @@ interval_tree_update_limit (struct interval_node *node)
 static void
 interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node)
 {
+  eassert (node->parent == ITREE_NULL || node->parent->otick >= node->otick);
   if (node->otick == otick)
     {
       eassert (node->offset == 0);
       return;
     }
 
+  /* Offsets can be inherited from dirty nodes (with out of date
+     otick) during insert and remove.  Offsets aren't inherited
+     downward from the root for these operations so rotations are
+     performed on potentially "dirty" nodes, where we only make sure
+     the *local* offsets are all zero.  */
+
   if (node->offset)
     {
       node->begin += node->offset;
@@ -1140,17 +1161,9 @@ interval_tree_inherit_offset (uintmax_t otick, struct interval_node *node)
         node->right->offset += node->offset;
       node->offset = 0;
     }
-  /* FIXME: I wonder when/why this condition can be false, and more
-     generally why we'd want to propagate offsets that may not be
-     fully up-to-date. --stef
-
-     Offsets can be inherited from dirty nodes (with out of date
-     otick) during insert and remove.  Offsets aren't inherited
-     downward from the root for these operations so rotations are
-     performed on potentially "dirty" nodes.  We could fix this by
-     always inheriting offsets downward from the root for every insert
-     and remove.  --matt
-  */
+  /* The only thing that matters about `otick` is whether it's equal to
+     that of the tree.  We could also "blindly" inherit from parent->otick,
+     but we need to tree's `otick` anyway for when there's no parent.  */
   if (node->parent == ITREE_NULL || node->parent->otick == otick)
     node->otick = otick;
 }
index 7fdc9c07c935bf9465f40128bd0b89fe68a9dfcf..5733ec153055c323d4f73f2b6537e575783a943d 100644 (file)
@@ -112,7 +112,7 @@ enum interval_tree_order {
   ITREE_PRE_ORDER,
 };
 
-void interval_node_init (struct interval_node *, ptrdiff_t, ptrdiff_t, bool, bool, Lisp_Object);
+void interval_node_init (struct interval_node *, bool, bool, Lisp_Object);
 ptrdiff_t interval_node_begin (struct interval_tree *, struct interval_node *);
 ptrdiff_t interval_node_end (struct interval_tree *, struct interval_node *);
 void interval_node_set_region (struct interval_tree *, struct interval_node *, ptrdiff_t, ptrdiff_t);
@@ -120,7 +120,8 @@ struct interval_tree *interval_tree_create (void);
 void interval_tree_destroy (struct interval_tree *);
 intmax_t interval_tree_size (struct interval_tree *);
 void interval_tree_clear (struct interval_tree *);
-void interval_tree_insert (struct interval_tree *, struct interval_node *);
+void itree_insert_node (struct interval_tree *tree, struct interval_node *node,
+                        ptrdiff_t begin, ptrdiff_t end);
 struct interval_node *interval_tree_remove (struct interval_tree *, struct interval_node *);
 struct interval_generator *interval_tree_iter_start (struct interval_tree *, ptrdiff_t, ptrdiff_t, enum interval_tree_order,
                               const char* file, int line);
index 7d838afb5c91e09e18163ae8d4aae9784cf6cb21..7cd78712814dc02b7857ae5ad642cc18c99fca04 100644 (file)
@@ -4415,7 +4415,6 @@ extern Lisp_Object make_float (double);
 extern void display_malloc_warning (void);
 extern specpdl_ref inhibit_garbage_collection (void);
 extern Lisp_Object build_symbol_with_pos (Lisp_Object, Lisp_Object);
-extern Lisp_Object build_overlay (ptrdiff_t, ptrdiff_t, bool, bool, Lisp_Object);
 extern void free_cons (struct Lisp_Cons *);
 extern void init_alloc_once (void);
 extern void init_alloc (void);