diff options
| author | Paul Eggert | 2017-02-05 13:25:37 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-02-05 13:30:29 -0800 |
| commit | b491322ed0fcf039669183880a342bbb2326e787 (patch) | |
| tree | d72d9396783d63214a8ab1069f972bb3029921f0 /src | |
| parent | 14dd9101ec4838f75addf25bf6b06ef33f8a7e97 (diff) | |
| download | emacs-b491322ed0fcf039669183880a342bbb2326e787.tar.gz emacs-b491322ed0fcf039669183880a342bbb2326e787.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lisp.h | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/src/lisp.h b/src/lisp.h index 13fca0b29e0..edbd15170f8 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4580,44 +4580,56 @@ enum | |||
| 4580 | Lisp_String)) \ | 4580 | Lisp_String)) \ |
| 4581 | : make_unibyte_string (str, len)) | 4581 | : make_unibyte_string (str, len)) |
| 4582 | 4582 | ||
| 4583 | /* Loop over tails of LIST, checking for dotted lists and cycles. | 4583 | /* Loop over tails of LIST, checking for dotted lists and cycles, |
| 4584 | and possibly quitting after each loop iteration. | ||
| 4584 | In the loop body, ‘li.tail’ is the current cons; the name ‘li’ is | 4585 | In the loop body, ‘li.tail’ is the current cons; the name ‘li’ is |
| 4585 | short for “list iterator”. The expression LIST may be evaluated | 4586 | short for “list iterator”. The expression LIST may be evaluated |
| 4586 | more than once, and so should not have side effects. The loop body | 4587 | more than once, and so should not have side effects. The loop body |
| 4587 | should not modify the list’s top level structure other than by | 4588 | should not modify the list’s top level structure other than by |
| 4588 | perhaps deleting the current cons. | 4589 | perhaps deleting the current cons. */ |
| 4589 | |||
| 4590 | Use Brent’s teleporting tortoise-hare algorithm. See: | ||
| 4591 | Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190 | ||
| 4592 | http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */ | ||
| 4593 | 4590 | ||
| 4594 | #define FOR_EACH_TAIL(list) \ | 4591 | #define FOR_EACH_TAIL(list) \ |
| 4595 | FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \ | 4592 | FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \ |
| 4596 | circular_list (list)) | 4593 | circular_list (list), true) |
| 4597 | 4594 | ||
| 4598 | /* Like FOR_EACH_TAIL (LIST), except check only for cycles. */ | 4595 | /* Like FOR_EACH_TAIL (LIST), except do not check for dotted lists. */ |
| 4599 | 4596 | ||
| 4600 | #define FOR_EACH_TAIL_CONS(list) \ | 4597 | #define FOR_EACH_TAIL_CONS(list) \ |
| 4601 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list)) | 4598 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list), true) |
| 4602 | 4599 | ||
| 4603 | /* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists | 4600 | /* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists |
| 4604 | nor cycles. */ | 4601 | nor cycles, and do not quit. */ |
| 4605 | 4602 | ||
| 4606 | #define FOR_EACH_TAIL_SAFE(list) \ | 4603 | #define FOR_EACH_TAIL_SAFE(list) \ |
| 4607 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil)) | 4604 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil), false) |
| 4608 | 4605 | ||
| 4609 | /* Like FOR_EACH_TAIL (LIST), except evaluate DOTTED or CYCLE, | 4606 | /* Like FOR_EACH_TAIL (LIST), except evaluate DOTTED or CYCLE, |
| 4610 | respectively, if a dotted list or cycle is found. This is an | 4607 | respectively, if a dotted list or cycle is found, and check for |
| 4611 | internal macro intended for use only by the above macros. */ | 4608 | quit if CHECK_QUIT. This is an internal macro intended for use |
| 4609 | only by the above macros. | ||
| 4612 | 4610 | ||
| 4613 | #define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle) \ | 4611 | Use Brent’s teleporting tortoise-hare algorithm. See: |
| 4614 | for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \ | 4612 | Brent RP. BIT. 1980;20(2):176-84. doi:10.1007/BF01933190 |
| 4615 | = { list, list, 2, 2 }; \ | 4613 | http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf |
| 4614 | |||
| 4615 | This macro uses maybe_quit because of an excess of caution. The | ||
| 4616 | call to maybe_quit should not be needed in practice, as a very long | ||
| 4617 | list, whether circular or not, will cause Emacs to be so slow in | ||
| 4618 | other noninterruptible areas (e.g., garbage collection) that there | ||
| 4619 | is little point to calling maybe_quit here. */ | ||
| 4620 | |||
| 4621 | #define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle, check_quit) \ | ||
| 4622 | for (struct { Lisp_Object tail, tortoise; intptr_t max, n; \ | ||
| 4623 | unsigned short int q; \ | ||
| 4624 | } li = { list, list, 2, 0, 2 }; \ | ||
| 4616 | CONSP (li.tail) || (dotted, false); \ | 4625 | CONSP (li.tail) || (dotted, false); \ |
| 4617 | (li.tail = XCDR (li.tail), \ | 4626 | (li.tail = XCDR (li.tail), \ |
| 4618 | (li.n-- == 0 \ | 4627 | ((--li.q != 0 \ |
| 4619 | ? (void) (li.n = li.max <<= 1, li.tortoise = li.tail) \ | 4628 | || ((check_quit) ? maybe_quit () : (void) 0, 0 < --li.n) \ |
| 4620 | : EQ (li.tail, li.tortoise) ? (cycle) : (void) 0))) | 4629 | || (li.q = li.n = li.max <<= 1, li.n >>= USHRT_WIDTH, \ |
| 4630 | li.tortoise = li.tail, false)) \ | ||
| 4631 | && EQ (li.tail, li.tortoise)) \ | ||
| 4632 | ? (cycle) : (void) 0)) | ||
| 4621 | 4633 | ||
| 4622 | /* Do a `for' loop over alist values. */ | 4634 | /* Do a `for' loop over alist values. */ |
| 4623 | 4635 | ||