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);
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. */
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);
}
}
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
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. */
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.
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);
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);
{
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))
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. */
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. */
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;
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;
}
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;
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);
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. */
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;
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
{
if (length <= 0 || tree->root == ITREE_NULL)
return;
+ uintmax_t ootick = tree->otick;
/* FIXME: Don't allocate generator/stack anew every time. */
}
/* 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);
}
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;
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;
}
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);
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);
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);