mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-12-22 10:26:20 +00:00
FOR_EACH_TAIL now checks for quit
As per Eli Zaretskii (Bug#25606#20). Although these calls to maybe_quit are unnecessary in practice, Eli was not convinced that the calls are unnecessary. * src/lisp.h (FOR_EACH_TAIL, FOR_EACH_TAIL_CONS): Call maybe_quit every so often. (FOR_EACH_TAIL_INTERNAL): New arg CHECK_QUIT. All callers changed.
This commit is contained in:
parent
14dd9101ec
commit
b491322ed0
52
src/lisp.h
52
src/lisp.h
@ -4580,44 +4580,56 @@ enum
|
||||
Lisp_String)) \
|
||||
: make_unibyte_string (str, len))
|
||||
|
||||
/* Loop over tails of LIST, checking for dotted lists and cycles.
|
||||
/* Loop over tails of LIST, checking for dotted lists and cycles,
|
||||
and possibly quitting after each loop iteration.
|
||||
In the loop body, ‘li.tail’ is the current cons; the name ‘li’ is
|
||||
short for “list iterator”. The expression LIST may be evaluated
|
||||
more than once, and so should not have side effects. The loop body
|
||||
should not modify the list’s top level structure other than by
|
||||
perhaps deleting the current cons.
|
||||
|
||||
Use Brent’s teleporting tortoise-hare algorithm. See:
|
||||
Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190
|
||||
http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */
|
||||
perhaps deleting the current cons. */
|
||||
|
||||
#define FOR_EACH_TAIL(list) \
|
||||
FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \
|
||||
circular_list (list))
|
||||
circular_list (list), true)
|
||||
|
||||
/* Like FOR_EACH_TAIL (LIST), except check only for cycles. */
|
||||
/* Like FOR_EACH_TAIL (LIST), except do not check for dotted lists. */
|
||||
|
||||
#define FOR_EACH_TAIL_CONS(list) \
|
||||
FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list))
|
||||
#define FOR_EACH_TAIL_CONS(list) \
|
||||
FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list), true)
|
||||
|
||||
/* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists
|
||||
nor cycles. */
|
||||
nor cycles, and do not quit. */
|
||||
|
||||
#define FOR_EACH_TAIL_SAFE(list) \
|
||||
FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil))
|
||||
FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil), false)
|
||||
|
||||
/* Like FOR_EACH_TAIL (LIST), except evaluate DOTTED or CYCLE,
|
||||
respectively, if a dotted list or cycle is found. This is an
|
||||
internal macro intended for use only by the above macros. */
|
||||
respectively, if a dotted list or cycle is found, and check for
|
||||
quit if CHECK_QUIT. This is an internal macro intended for use
|
||||
only by the above macros.
|
||||
|
||||
#define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle) \
|
||||
for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \
|
||||
= { list, list, 2, 2 }; \
|
||||
Use Brent’s teleporting tortoise-hare algorithm. See:
|
||||
Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190
|
||||
http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf
|
||||
|
||||
This macro uses maybe_quit because of an excess of caution. The
|
||||
call to maybe_quit should not be needed in practice, as a very long
|
||||
list, whether circular or not, will cause Emacs to be so slow in
|
||||
other noninterruptible areas (e.g., garbage collection) that there
|
||||
is little point to calling maybe_quit here. */
|
||||
|
||||
#define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle, check_quit) \
|
||||
for (struct { Lisp_Object tail, tortoise; intptr_t max, n; \
|
||||
unsigned short int q; \
|
||||
} li = { list, list, 2, 0, 2 }; \
|
||||
CONSP (li.tail) || (dotted, false); \
|
||||
(li.tail = XCDR (li.tail), \
|
||||
(li.n-- == 0 \
|
||||
? (void) (li.n = li.max <<= 1, li.tortoise = li.tail) \
|
||||
: EQ (li.tail, li.tortoise) ? (cycle) : (void) 0)))
|
||||
((--li.q != 0 \
|
||||
|| ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \
|
||||
|| (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \
|
||||
li.tortoise = li.tail, false)) \
|
||||
&& EQ (li.tail, li.tortoise)) \
|
||||
? (cycle) : (void) 0))
|
||||
|
||||
/* Do a `for' loop over alist values. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user