aboutsummaryrefslogtreecommitdiffstats
path: root/src/lisp.h
diff options
context:
space:
mode:
authorPaul Eggert2017-02-05 13:25:37 -0800
committerPaul Eggert2017-02-05 13:30:29 -0800
commit14dd9101ec4838f75addf25bf6b06ef33f8a7e97 (patch)
tree500eb382ab23735af5b722b5ad7882c05bdfa965 /src/lisp.h
parentb7fa6b1f1cee9d1b71553fa665843774d2e5cf3d (diff)
downloademacs-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.h35
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
3136enum { 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
3142INLINE void 3136INLINE void
3143rarely_quit (unsigned short int count) 3137rarely_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