diff options
| author | Paul Eggert | 2017-02-05 13:25:37 -0800 |
|---|---|---|
| committer | Paul Eggert | 2017-02-05 13:30:29 -0800 |
| commit | 14dd9101ec4838f75addf25bf6b06ef33f8a7e97 (patch) | |
| tree | 500eb382ab23735af5b722b5ad7882c05bdfa965 /src/lisp.h | |
| parent | b7fa6b1f1cee9d1b71553fa665843774d2e5cf3d (diff) | |
| download | emacs-14dd9101ec4838f75addf25bf6b06ef33f8a7e97.tar.gz emacs-14dd9101ec4838f75addf25bf6b06ef33f8a7e97.zip | |
Signal list cycles in ‘length’ etc.
Use macros like FOR_EACH_TAIL instead of maybe_quit to
catch list cycles automatically instead of relying on the
user becoming impatient and typing C-g (Bug#25606).
* src/fns.c (Flength, Fmember, Fmemq, Fmemql, Fassq, Fassoc, Frassq)
(Frassoc, Fdelete, Freverse):
Use FOR_EACH_TAIL instead of maybe_quit.
(Fnreverse): Use simple EQ to check for circular list instead
of rarely_quit, as this suffices in this unusual case.
(Fplist_put, Flax_plist_put, Flax_plist_put):
Use FOR_EACH_TAIL_CONS instead of maybe_quit.
(internal_equal): Use FOR_EACH_TAIL_CONS to check lists, instead
of by-hand tail recursion that did not catch cycles.
* src/fns.c (Fsafe_length, Fplist_get):
* src/xdisp.c (display_mode_element):
Use FOR_EACH_TAIL_SAFE instead of by-hand Floyd’s algorithm.
* src/lisp.h (QUIT_COUNT_HEURISTIC): Remove; no longer needed.
(rarely_quit): Simply count toward USHRT_MAX + 1, since the
fancier versions are no longer needed.
(FOR_EACH_TAIL_CONS, FOR_EACH_TAIL_SAFE)
(FOR_EACH_TAIL_INTERNAL): New macros, the last with definiens
mostly taken from FOR_EACH_TAIL.
(FOR_EACH_TAIL): Rewrite in terms of FOR_EACH_TAIL_INTERNAL.
Diffstat (limited to 'src/lisp.h')
| -rw-r--r-- | src/lisp.h | 35 |
1 files changed, 24 insertions, 11 deletions
diff --git a/src/lisp.h b/src/lisp.h index 102e8bd70ef..13fca0b29e0 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -3129,20 +3129,14 @@ extern void maybe_quit (void); | |||
| 3129 | 3129 | ||
| 3130 | #define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) | 3130 | #define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit)) |
| 3131 | 3131 | ||
| 3132 | /* Heuristic on how many iterations of a tight loop can be safely done | ||
| 3133 | before it's time to do a quit. This must be a power of 2. It | ||
| 3134 | is nice but not necessary for it to equal USHRT_MAX + 1. */ | ||
| 3135 | |||
| 3136 | enum { QUIT_COUNT_HEURISTIC = 1 << 16 }; | ||
| 3137 | |||
| 3138 | /* Process a quit rarely, based on a counter COUNT, for efficiency. | 3132 | /* Process a quit rarely, based on a counter COUNT, for efficiency. |
| 3139 | "Rarely" means once per QUIT_COUNT_HEURISTIC or per USHRT_MAX + 1 | 3133 | "Rarely" means once per USHRT_MAX + 1 times; this is somewhat |
| 3140 | times, whichever is smaller (somewhat arbitrary, but often faster). */ | 3134 | arbitrary, but efficient. */ |
| 3141 | 3135 | ||
| 3142 | INLINE void | 3136 | INLINE void |
| 3143 | rarely_quit (unsigned short int count) | 3137 | rarely_quit (unsigned short int count) |
| 3144 | { | 3138 | { |
| 3145 | if (! (count & (QUIT_COUNT_HEURISTIC - 1))) | 3139 | if (! count) |
| 3146 | maybe_quit (); | 3140 | maybe_quit (); |
| 3147 | } | 3141 | } |
| 3148 | 3142 | ||
| @@ -4598,13 +4592,32 @@ enum | |||
| 4598 | http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */ | 4592 | http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */ |
| 4599 | 4593 | ||
| 4600 | #define FOR_EACH_TAIL(list) \ | 4594 | #define FOR_EACH_TAIL(list) \ |
| 4595 | FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \ | ||
| 4596 | circular_list (list)) | ||
| 4597 | |||
| 4598 | /* Like FOR_EACH_TAIL (LIST), except check only for cycles. */ | ||
| 4599 | |||
| 4600 | #define FOR_EACH_TAIL_CONS(list) \ | ||
| 4601 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list)) | ||
| 4602 | |||
| 4603 | /* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists | ||
| 4604 | nor cycles. */ | ||
| 4605 | |||
| 4606 | #define FOR_EACH_TAIL_SAFE(list) \ | ||
| 4607 | FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil)) | ||
| 4608 | |||
| 4609 | /* Like FOR_EACH_TAIL (LIST), except evaluate DOTTED or CYCLE, | ||
| 4610 | respectively, if a dotted list or cycle is found. This is an | ||
| 4611 | internal macro intended for use only by the above macros. */ | ||
| 4612 | |||
| 4613 | #define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle) \ | ||
| 4601 | for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \ | 4614 | for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \ |
| 4602 | = { list, list, 2, 2 }; \ | 4615 | = { list, list, 2, 2 }; \ |
| 4603 | CONSP (li.tail) || (CHECK_LIST_END (li.tail, list), false); \ | 4616 | CONSP (li.tail) || (dotted, false); \ |
| 4604 | (li.tail = XCDR (li.tail), \ | 4617 | (li.tail = XCDR (li.tail), \ |
| 4605 | (li.n-- == 0 \ | 4618 | (li.n-- == 0 \ |
| 4606 | ? (void) (li.n = li.max <<= 1, li.tortoise = li.tail) \ | 4619 | ? (void) (li.n = li.max <<= 1, li.tortoise = li.tail) \ |
| 4607 | : EQ (li.tail, li.tortoise) ? circular_list (list) : (void) 0))) | 4620 | : EQ (li.tail, li.tortoise) ? (cycle) : (void) 0))) |
| 4608 | 4621 | ||
| 4609 | /* Do a `for' loop over alist values. */ | 4622 | /* Do a `for' loop over alist values. */ |
| 4610 | 4623 | ||