* src/itree.h (interval_tree_iter_start): Adjust type.
(interval_tree_nodes): Delete declaration.
(ITREE_FOREACH, ITREE_FOREACH_ABORT, ITREE_FOREACH_NARROW): New macros.
* src/itree.c (interval_tree_contains, interval_tree_insert_gap):
Use the new ITREE_FOREACH macro.
(interval_tree_nodes): Delete function.
(interval_tree_iter_start): Return the iterator.
(interval_generator_next, interval_tree_destroy):
Don't accept a NULL arg any more.
* src/xdisp.c (load_overlay_strings, strings_with_newlines):
* src/textprop.c (get_char_property_and_overlay):
* src/buffer.c (copy_overlays, delete_all_overlays)
(set_overlays_multibyte, swap_buffer_overlays, overlays_in)
(next_overlay_change, previous_overlay_change, overlay_touches_p)
(overlay_strings, Foverlay_lists, report_overlay_modification)
(evaporate_overlays): Use the new ITREE_FOREACH macro.
* src/buffer.h (buffer_overlay_iter_start1)
(buffer_overlay_iter_start, buffer_overlay_iter_next)
(buffer_overlay_iter_finish, buffer_overlay_iter_narrow):
Delete declarations.
eassert (to && ! to->overlays);
struct interval_node *node;
- buffer_overlay_iter_start (from, PTRDIFF_MIN, PTRDIFF_MAX, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (from)))
+ ITREE_FOREACH (node, from->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
{
Lisp_Object ov = node->data;
Lisp_Object copy = build_overlay (node->begin, node->end,
Fcopy_sequence (OVERLAY_PLIST (ov)));
add_buffer_overlay (to, XOVERLAY (copy));
}
- buffer_overlay_iter_finish (from);
}
bool
Of course, we can't set them to NULL from within the iteration
because the iterator may need them (tho we could if we added
an ITREE_POST_ORDER iteration order). */
- buffer_overlay_iter_start (b, PTRDIFF_MIN, PTRDIFF_MAX, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (b)))
+ ITREE_FOREACH (node, b->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
{
modify_overlay (b, node->begin, node->end);
/* Where are the nodes freed ? --ap */
XOVERLAY (node->data)->buffer = NULL;
}
- buffer_overlay_iter_finish (b);
interval_tree_clear (b->overlays);
}
free_buffer_overlays (struct buffer *b)
{
/* Actually this does not free any overlay, but the tree only. --ap */
- eassert (! b->overlays || 0 == interval_tree_size (b->overlays));
if (b->overlays)
{
interval_tree_destroy (b->overlays);
struct interval_tree *tree = current_buffer->overlays;
const intmax_t size = interval_tree_size (tree);
+ /* We can't use `interval_node_set_region` at the same time
+ as we iterate over the itree, so we need an auxiliary storage
+ to keep the list of nodes. */
USE_SAFE_ALLOCA;
SAFE_NALLOCA (nodes, 1, size);
- interval_tree_nodes (tree, nodes, ITREE_ASCENDING);
+ {
+ struct interval_node *node, **cursor = nodes;
+ ITREE_FOREACH (node, tree, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
+ *(cursor++) = node;
+ }
for (int i = 0; i < size; ++i, ++nodes)
{
{
struct interval_node *node;
- buffer_overlay_iter_start (buffer, PTRDIFF_MIN, PTRDIFF_MAX, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (buffer)))
+ ITREE_FOREACH (node, buffer->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
XOVERLAY (node->data)->buffer = other;
- buffer_overlay_iter_finish (buffer);
- buffer_overlay_iter_start (other, PTRDIFF_MIN, PTRDIFF_MAX, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (other)))
+ ITREE_FOREACH (node, other->overlays, PTRDIFF_MIN, PTRDIFF_MAX, ASCENDING)
XOVERLAY (node->data)->buffer = buffer;
- buffer_overlay_iter_finish (other);
/* Swap the interval trees. */
void *tmp = buffer->overlays;
Lisp_Object *vec = *vec_ptr;
struct interval_node *node;
- buffer_overlay_iter_start (current_buffer, beg,
- /* Find empty OV at Z ? */
- (end >= ZV && empty) ? ZV + 1 : ZV,
- ITREE_ASCENDING);
-
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, beg,
+ /* Find empty OV at Z ? */
+ (end >= ZV && empty) ? ZV + 1 : ZV, ASCENDING)
{
if (node->begin > end)
{
next = min (next, node->begin);
+ ITREE_FOREACH_ABORT ();
break;
}
else if (node->begin == end)
{
next = node->begin;
if ((! empty || end < ZV) && beg < end)
- break;
+ {
+ ITREE_FOREACH_ABORT ();
+ break;
+ }
}
if (! empty && node->begin == node->end)
/* Keep counting overlays even if we can't return them all. */
idx++;
}
- buffer_overlay_iter_finish (current_buffer);
if (next_ptr)
*next_ptr = next ? next : ZV;
ptrdiff_t next = ZV;
struct interval_node *node;
- buffer_overlay_iter_start (current_buffer, pos, next, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, pos, next, ASCENDING)
{
if (node->begin > pos)
{
of pos, because the search is limited to [pos,next) . */
eassert (node->begin < next);
next = node->begin;
+ ITREE_FOREACH_ABORT ();
break;
}
else if (node->begin < node->end && node->end < next)
{
next = node->end;
- buffer_overlay_iter_narrow (current_buffer, pos, next);
+ ITREE_FOREACH_NARROW (pos, next);
}
}
- buffer_overlay_iter_finish (current_buffer);
return next;
}
struct interval_node *node;
ptrdiff_t prev = BEGV;
- buffer_overlay_iter_start (current_buffer, prev, pos, ITREE_DESCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, prev, pos, DESCENDING)
{
if (node->end < pos)
prev = node->end;
else
prev = max (prev, node->begin);
- buffer_overlay_iter_narrow (current_buffer, prev, pos);
+ ITREE_FOREACH_NARROW (prev, pos);
}
- buffer_overlay_iter_finish (current_buffer);
return prev;
}
overlay_touches_p (ptrdiff_t pos)
{
struct interval_node *node;
- bool result = false;
/* We need to find overlays ending in pos, as well as empty ones at
pos. */
- buffer_overlay_iter_start (current_buffer,
- pos - 1, pos + 1, ITREE_DESCENDING);
-
- while (! result && (node = buffer_overlay_iter_next (current_buffer)))
- result = (node->begin == pos || node->end == pos);
-
- buffer_overlay_iter_finish (current_buffer);
-
- return result;
+ ITREE_FOREACH (node, current_buffer->overlays, pos - 1, pos + 1, DESCENDING)
+ if (node->begin == pos || node->end == pos)
+ {
+ ITREE_FOREACH_ABORT ();
+ return true;
+ }
+ return false;
}
\f
overlay_heads.used = overlay_heads.bytes = 0;
overlay_tails.used = overlay_tails.bytes = 0;
- buffer_overlay_iter_start (current_buffer,
- pos - 1, pos + 1, ITREE_DESCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, pos - 1, pos + 1, DESCENDING)
{
Lisp_Object overlay = node->data;
eassert (OVERLAYP (overlay));
if (WINDOWP (window) && XWINDOW (window) != w)
continue;
Lisp_Object str;
+ /* FIXME: Are we really sure that `record_overlay_string` can
+ never cause a non-local exit? */
if (startpos == pos
&& (str = Foverlay_get (overlay, Qbefore_string), STRINGP (str)))
record_overlay_string (&overlay_heads, str,
Foverlay_get (overlay, Qpriority),
endpos - startpos);
}
- buffer_overlay_iter_finish (current_buffer);
if (overlay_tails.used > 1)
qsort (overlay_tails.buf, overlay_tails.used, sizeof (struct sortstr),
Lisp_Object overlays = Qnil;
struct interval_node *node;
- buffer_overlay_iter_start (current_buffer, BEG, Z, ITREE_DESCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, BEG, Z, DESCENDING)
overlays = Fcons (node->data, overlays);
- buffer_overlay_iter_finish (current_buffer);
return Fcons (overlays, Qnil);
}
if (! current_buffer->overlays)
return;
- buffer_overlay_iter_start (current_buffer,
- begin_arg - (insertion ? 1 : 0),
- end_arg + (insertion ? 1 : 0),
- ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays,
+ begin_arg - (insertion ? 1 : 0),
+ end_arg + (insertion ? 1 : 0),
+ ASCENDING)
{
Lisp_Object overlay = node->data;
ptrdiff_t obegin = OVERLAY_START (overlay);
add_overlay_mod_hooklist (prop, overlay);
}
}
- buffer_overlay_iter_finish (current_buffer);
}
{
/* Call the functions recorded in last_overlay_modification_hooks.
Lisp_Object hit_list = Qnil;
struct interval_node *node;
- buffer_overlay_iter_start (current_buffer, pos, pos, ITREE_ASCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, pos, pos, ASCENDING)
{
if (node->end == pos
&& ! NILP (Foverlay_get (node->data, Qevaporate)))
hit_list = Fcons (node->data, hit_list);
}
- buffer_overlay_iter_finish (current_buffer);
for (; CONSP (hit_list); hit_list = XCDR (hit_list))
Fdelete_overlay (XCAR (hit_list));
ov->buffer = NULL;
}
-INLINE void
-buffer_overlay_iter_start1 (struct buffer *b, ptrdiff_t begin, ptrdiff_t end,
- enum interval_tree_order order, const char* file, int line)
-{
- if (b->overlays)
- interval_tree_iter_start (b->overlays, begin, end, order, file, line);
-}
-
-#define buffer_overlay_iter_start(b, begin, end, order) \
- buffer_overlay_iter_start1 ((b), (begin), (end), (order), __FILE__, __LINE__)
-
-INLINE struct interval_node*
-buffer_overlay_iter_next (struct buffer *b)
-{
- if (! b->overlays)
- return NULL;
- return interval_generator_next (b->overlays->iter);
-}
-
-INLINE void
-buffer_overlay_iter_finish (struct buffer *b)
-{
- if (b->overlays)
- interval_tree_iter_finish (b->overlays->iter);
-}
-
-INLINE void
-buffer_overlay_iter_narrow (struct buffer *b, ptrdiff_t begin, ptrdiff_t end)
-{
- if (b->overlays)
- interval_generator_narrow (b->overlays->iter, begin, end);
-}
-
/* Return the start of OV in its buffer, or -1 if OV is not associated
with any buffer. */
return tree;
}
-/* Reset the tree TREE to its empty state. */
+/* Reset the tree TREE to its empty state. */
void
interval_tree_clear (struct interval_tree *tree)
}
#ifdef ITREE_TESTING
-/* Initialize a pre-allocated tree (presumably on the stack). */
+/* Initialize a pre-allocated tree (presumably on the stack). */
static void
interval_tree_init (struct interval_tree *tree)
}
#endif
-/* Release a tree, freeing its allocated memory. */
+/* Release a tree, freeing its allocated memory. */
void
interval_tree_destroy (struct interval_tree *tree)
{
- if (! tree)
- return;
+ eassert (tree->root == ITREE_NULL);
if (tree->iter)
interval_generator_destroy (tree->iter);
xfree (tree);
ptrdiff_t offset = 0;
/* Find the insertion point, accumulate node's offset and update
- ancestors limit values. */
+ ancestors limit values. */
while (child != ITREE_NULL)
{
parent = child;
offset += child->offset;
child->limit = max (child->limit, node->end - offset);
/* This suggests that nodes in the right subtree are strictly
- greater. But this is not true due to later rotations. */
+ greater. But this is not true due to later rotations. */
child = node->begin <= child->begin ? child->left : child->right;
}
bool
interval_tree_contains (struct interval_tree *tree, struct interval_node *node)
{
+ eassert (node);
struct interval_node *other;
-
- interval_tree_iter_start (tree, node->begin, PTRDIFF_MAX, ITREE_ASCENDING, __FILE__, __LINE__);
- while ((other = interval_generator_next (tree->iter)))
+ ITREE_FOREACH (other, tree, node->begin, PTRDIFF_MAX, ASCENDING)
if (other == node)
- break;
+ {
+ ITREE_FOREACH_ABORT ();
+ return true;
+ }
- interval_tree_iter_finish (tree->iter);
- return other == node;
+ return false;
}
/* Remove NODE from TREE and return it. NODE must exist in TREE. */
return node;
}
-/* Fill memory pointed at via NODES with all nodes of TREE in the
- given ORDER.
-
- The size of NODES must be sufficiently large.
- */
-
-void
-interval_tree_nodes (struct interval_tree *tree,
- struct interval_node **nodes,
- enum interval_tree_order order)
-{
- struct interval_node *node;
-
- interval_tree_iter_start (tree, PTRDIFF_MIN, PTRDIFF_MAX, order, __FILE__, __LINE__);
- while ((node = interval_generator_next (tree->iter)))
- {
- *nodes = node;
- ++nodes;
- }
- interval_tree_iter_finish (tree->iter);
-}
-
/* Start a generator iterating all intervals in [BEGIN,END) in the
given ORDER. Only one iterator per tree can be running at any
time.
*/
-void
+struct interval_generator *
interval_tree_iter_start (struct interval_tree *tree,
ptrdiff_t begin, ptrdiff_t end,
enum interval_tree_order order,
iter->running = true;
iter->file = file;
iter->line = line;
+ return iter;
}
/* Stop using the iterator. */
order, so we need to remove them first. */
struct interval_stack *saved = interval_stack_create (0);
struct interval_node *node = NULL;
- interval_tree_iter_start (tree, pos, pos + 1,
- ITREE_PRE_ORDER, __FILE__, __LINE__);
- while ((node = interval_generator_next (tree->iter)))
+ ITREE_FOREACH (node, tree, pos, pos + 1, PRE_ORDER)
{
if (node->begin == pos && node->front_advance
&& (node->begin != node->end || node->rear_advance))
interval_stack_push (saved, node);
}
- interval_tree_iter_finish (tree->iter);
for (int i = 0; i < saved->length; ++i)
interval_tree_remove (tree, nav_nodeptr (saved->nodes[i]));
interval_generator_next (struct interval_generator *g)
{
eassert (g->running);
- if (! g) return NULL;
struct interval_node * const null = ITREE_NULL;
struct interval_node *node;
struct interval_node *root;
uintmax_t otick; /* offset tick, compared with node's otick. */
intmax_t size; /* Number of nodes in the tree. */
+ /* FIXME: We can only have one iteration active per tree, which is very
+ restrictive. Actually, in practice this is no better than limiting
+ to a single active iteration *globally*, so we could move this `iter`
+ to a global variable! */
struct interval_generator *iter;
};
void interval_tree_insert (struct interval_tree *, struct interval_node *);
bool interval_tree_contains (struct interval_tree *, struct interval_node *);
struct interval_node *interval_tree_remove (struct interval_tree *, struct interval_node *);
-void interval_tree_iter_start (struct interval_tree *, ptrdiff_t, ptrdiff_t, enum interval_tree_order,
+struct interval_generator *interval_tree_iter_start (struct interval_tree *, ptrdiff_t, ptrdiff_t, enum interval_tree_order,
const char* file, int line);
void interval_generator_narrow (struct interval_generator *, ptrdiff_t, ptrdiff_t);
void interval_tree_iter_finish (struct interval_generator *);
struct interval_node *interval_generator_next (struct interval_generator *);
void interval_tree_insert_gap (struct interval_tree *, ptrdiff_t, ptrdiff_t);
void interval_tree_delete_gap (struct interval_tree *, ptrdiff_t, ptrdiff_t);
-void interval_tree_nodes (struct interval_tree *tree, struct interval_node **nodes, enum interval_tree_order order);
+
+/* Iterate over the intervals between BEG and END in the tree T.
+ N will hold successive nodes. ORDER can be one of : `ASCENDING`,
+ `DESCENDING`, or `PRE_ORDER`.
+ It should be used as:
+
+ ITREE_FOREACH (n, t, beg, end, order)
+ {
+ .. do the thing with n ..
+ }
+
+ BEWARE:
+ - The expression T may be evaluated more than once, so make sure
+ it is cheap a pure.
+ - Only a single iteration can happen at a time, so make sure none of the
+ code within the loop can start another tree_itertion.
+ - If you need to exit the loop early, you *have* to call `ITREE_ABORT`
+ just before exiting (e.g. with `break` or `return`).
+ - Non-local exits are not supported within the body of the loop,
+ unless the caller makes sure `ITREE_ABORT` is called via some
+ kind of unwind_protect.
+ - Don't modify the tree during the iteration.
+ */
+#define ITREE_FOREACH(n, t, beg, end, order) \
+ /* FIXME: We'd want to declare `x` right here, but I can't figure out
+ how to make that work here: the `for` syntax only allows a single
+ clause for the var declarations where we need 2 different types.
+ We could use the `struct {foo x; bar y; } p;` trick to declare two
+ vars `p.x` and `p.y` of unrelated types, but then none of the names
+ of the vars matches the `n` we receive :-(. */ \
+ if (!t) \
+ { } \
+ else \
+ for (struct interval_generator *itree_iter_ \
+ = interval_tree_iter_start (t, beg, end, ITREE_##order, \
+ __FILE__, __LINE__); \
+ ((n = interval_generator_next (itree_iter_)) \
+ || (interval_tree_iter_finish (itree_iter_), false));)
+
+#define ITREE_FOREACH_ABORT() \
+ interval_tree_iter_finish (itree_iter_)
+
+#define ITREE_FOREACH_NARROW(beg, end) \
+ interval_generator_narrow (itree_iter_, beg, end)
+
#endif
&& pos <= BUF_ZV (b)))
xsignal1 (Qargs_out_of_range, position);
- buffer_overlay_iter_start (b, pos, pos + 1, ITREE_ASCENDING);
-
/* Now check the overlays in order of decreasing priority. */
- while ((node = buffer_overlay_iter_next (b)))
+ ITREE_FOREACH (node, b->overlays, pos, pos + 1, ASCENDING)
{
Lisp_Object tem = Foverlay_get (node->data, prop);
struct sortvec *this;
result_tem = tem;
}
}
- buffer_overlay_iter_finish (b);
if (result)
{
if (overlay)
while (false)
- buffer_overlay_iter_start (current_buffer,
- charpos - 1, charpos + 1, ITREE_DESCENDING);
/* Process overlays. */
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ ITREE_FOREACH (node, current_buffer->overlays, charpos - 1, charpos + 1, DESCENDING)
{
Lisp_Object overlay = node->data;
eassert (OVERLAYP (overlay));
&& SCHARS (str))
RECORD_OVERLAY_STRING (overlay, str, true);
}
- buffer_overlay_iter_finish (current_buffer);
#undef RECORD_OVERLAY_STRING
strings_with_newlines (ptrdiff_t startpos, ptrdiff_t endpos, struct window *w)
{
struct interval_node *node;
- /* Process overlays before the overlay center. */
- buffer_overlay_iter_start (current_buffer,
- startpos, endpos, ITREE_DESCENDING);
- while ((node = buffer_overlay_iter_next (current_buffer)))
+ /* Process overlays. */
+ ITREE_FOREACH (node, current_buffer->overlays, startpos, endpos, DESCENDING)
{
Lisp_Object overlay = node->data;
eassert (OVERLAYP (overlay));
if (STRINGP (str) && SCHARS (str)
&& memchr (SDATA (str), '\n', SBYTES (str)))
{
- buffer_overlay_iter_finish (current_buffer);
+ ITREE_FOREACH_ABORT ();
return true;
}
str = Foverlay_get (overlay, Qafter_string);
if (STRINGP (str) && SCHARS (str)
&& memchr (SDATA (str), '\n', SBYTES (str)))
{
- buffer_overlay_iter_finish (current_buffer);
+ ITREE_FOREACH_ABORT ();
return true;
}
}
- buffer_overlay_iter_finish (current_buffer);
-
/* Check for 'display' properties whose values include strings. */
Lisp_Object cpos = make_fixnum (startpos);
Lisp_Object limpos = make_fixnum (endpos);