XSETFASTINT (val, ASIZE (sequence) & PSEUDOVECTOR_SIZE_MASK);
else if (CONSP (sequence))
{
- EMACS_INT i = 0;
-
- do
- {
- ++i;
- if ((i & (QUIT_COUNT_HEURISTIC - 1)) == 0)
- {
- if (MOST_POSITIVE_FIXNUM < i)
- error ("List too long");
- maybe_quit ();
- }
- sequence = XCDR (sequence);
- }
- while (CONSP (sequence));
-
- CHECK_LIST_END (sequence, sequence);
-
+ intptr_t i = 0;
+ FOR_EACH_TAIL (sequence)
+ i++;
+ if (MOST_POSITIVE_FIXNUM < i)
+ error ("List too long");
val = make_number (i);
}
else if (NILP (sequence))
which is at least the number of distinct elements. */)
(Lisp_Object list)
{
- Lisp_Object tail, halftail;
- double hilen = 0;
- uintmax_t lolen = 1;
-
- if (! CONSP (list))
- return make_number (0);
-
- /* halftail is used to detect circular lists. */
- for (tail = halftail = list; ; )
- {
- tail = XCDR (tail);
- if (! CONSP (tail))
- break;
- if (EQ (tail, halftail))
- break;
- lolen++;
- if ((lolen & 1) == 0)
- {
- halftail = XCDR (halftail);
- if ((lolen & (QUIT_COUNT_HEURISTIC - 1)) == 0)
- {
- maybe_quit ();
- if (lolen == 0)
- hilen += UINTMAX_MAX + 1.0;
- }
- }
- }
-
- /* If the length does not fit into a fixnum, return a float.
- On all known practical machines this returns an upper bound on
- the true length. */
- return hilen ? make_float (hilen + lolen) : make_fixnum_or_float (lolen);
+ intptr_t len = 0;
+ FOR_EACH_TAIL_SAFE (list)
+ len++;
+ return make_fixnum_or_float (len);
}
DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,
The value is actually the tail of LIST whose car is ELT. */)
(Lisp_Object elt, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
- {
- if (! NILP (Fequal (elt, XCAR (tail))))
- return tail;
- rarely_quit (++quit_count);
- }
- CHECK_LIST_END (tail, list);
+ FOR_EACH_TAIL (list)
+ if (! NILP (Fequal (elt, XCAR (li.tail))))
+ return li.tail;
return Qnil;
}
The value is actually the tail of LIST whose car is ELT. */)
(Lisp_Object elt, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
- {
- if (EQ (XCAR (tail), elt))
- return tail;
- rarely_quit (++quit_count);
- }
- CHECK_LIST_END (tail, list);
+ FOR_EACH_TAIL (list)
+ if (EQ (XCAR (li.tail), elt))
+ return li.tail;
return Qnil;
}
if (!FLOATP (elt))
return Fmemq (elt, list);
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_TAIL (list)
{
- Lisp_Object tem = XCAR (tail);
+ Lisp_Object tem = XCAR (li.tail);
if (FLOATP (tem) && internal_equal (elt, tem, 0, 0, Qnil))
- return tail;
- rarely_quit (++quit_count);
+ return li.tail;
}
- CHECK_LIST_END (tail, list);
return Qnil;
}
Elements of LIST that are not conses are ignored. */)
(Lisp_Object key, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
- {
- if (CONSP (XCAR (tail)) && EQ (XCAR (XCAR (tail)), key))
- return XCAR (tail);
- rarely_quit (++quit_count);
- }
- CHECK_LIST_END (tail, list);
+ FOR_EACH_TAIL (list)
+ if (CONSP (XCAR (li.tail)) && EQ (XCAR (XCAR (li.tail)), key))
+ return XCAR (li.tail);
return Qnil;
}
The value is actually the first element of LIST whose car equals KEY. */)
(Lisp_Object key, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_TAIL (list)
{
- Lisp_Object car = XCAR (tail);
+ Lisp_Object car = XCAR (li.tail);
if (CONSP (car)
&& (EQ (XCAR (car), key) || !NILP (Fequal (XCAR (car), key))))
return car;
- rarely_quit (++quit_count);
}
- CHECK_LIST_END (tail, list);
return Qnil;
}
The value is actually the first element of LIST whose cdr is KEY. */)
(Lisp_Object key, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
- {
- if (CONSP (XCAR (tail)) && EQ (XCDR (XCAR (tail)), key))
- return XCAR (tail);
- rarely_quit (++quit_count);
- }
- CHECK_LIST_END (tail, list);
+ FOR_EACH_TAIL (list)
+ if (CONSP (XCAR (li.tail)) && EQ (XCDR (XCAR (li.tail)), key))
+ return XCAR (li.tail);
return Qnil;
}
The value is actually the first element of LIST whose cdr equals KEY. */)
(Lisp_Object key, Lisp_Object list)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_TAIL (list)
{
- Lisp_Object car = XCAR (tail);
+ Lisp_Object car = XCAR (li.tail);
if (CONSP (car)
&& (EQ (XCDR (car), key) || !NILP (Fequal (XCDR (car), key))))
return car;
- rarely_quit (++quit_count);
}
- CHECK_LIST_END (tail, list);
return Qnil;
}
\f
}
else
{
- unsigned short int quit_count = 0;
- Lisp_Object tail, prev;
+ Lisp_Object prev = Qnil;
- for (tail = seq, prev = Qnil; CONSP (tail); tail = XCDR (tail))
+ FOR_EACH_TAIL (seq)
{
- if (!NILP (Fequal (elt, XCAR (tail))))
+ if (!NILP (Fequal (elt, (XCAR (li.tail)))))
{
if (NILP (prev))
- seq = XCDR (tail);
+ seq = XCDR (li.tail);
else
- Fsetcdr (prev, XCDR (tail));
+ Fsetcdr (prev, XCDR (li.tail));
}
else
- prev = tail;
- rarely_quit (++quit_count);
+ prev = li.tail;
}
- CHECK_LIST_END (tail, seq);
}
return seq;
return Freverse (seq);
else if (CONSP (seq))
{
- unsigned short int quit_count = 0;
Lisp_Object prev, tail, next;
for (prev = Qnil, tail = seq; CONSP (tail); tail = next)
{
next = XCDR (tail);
+ /* If SEQ contains a cycle, attempting to reverse it
+ in-place will inevitably come back to SEQ. */
+ if (EQ (next, seq))
+ circular_list (seq);
Fsetcdr (tail, prev);
prev = tail;
- rarely_quit (++quit_count);
}
CHECK_LIST_END (tail, seq);
seq = prev;
return Qnil;
else if (CONSP (seq))
{
- unsigned short int quit_count = 0;
- for (new = Qnil; CONSP (seq); seq = XCDR (seq))
- {
- new = Fcons (XCAR (seq), new);
- rarely_quit (++quit_count);
- }
- CHECK_LIST_END (seq, seq);
+ new = Qnil;
+ FOR_EACH_TAIL (seq)
+ new = Fcons (XCAR (li.tail), new);
}
else if (VECTORP (seq))
{
properties on the list. This function never signals an error. */)
(Lisp_Object plist, Lisp_Object prop)
{
- Lisp_Object tail, halftail;
-
- /* halftail is used to detect circular lists. */
- tail = halftail = plist;
- while (CONSP (tail) && CONSP (XCDR (tail)))
+ FOR_EACH_TAIL_SAFE (plist)
{
- if (EQ (prop, XCAR (tail)))
- return XCAR (XCDR (tail));
-
- tail = XCDR (XCDR (tail));
- halftail = XCDR (halftail);
- if (EQ (tail, halftail))
+ if (! CONSP (XCDR (li.tail)))
+ break;
+ if (EQ (prop, XCAR (li.tail)))
+ return XCAR (XCDR (li.tail));
+ li.tail = XCDR (li.tail);
+ if (EQ (li.tail, li.tortoise))
break;
}
The PLIST is modified by side effects. */)
(Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
{
- unsigned short int quit_count = 0;
Lisp_Object prev = Qnil;
- for (Lisp_Object tail = plist; CONSP (tail) && CONSP (XCDR (tail));
- tail = XCDR (XCDR (tail)))
+ FOR_EACH_TAIL_CONS (plist)
{
- if (EQ (prop, XCAR (tail)))
+ if (! CONSP (XCDR (li.tail)))
+ break;
+
+ if (EQ (prop, XCAR (li.tail)))
{
- Fsetcar (XCDR (tail), val);
+ Fsetcar (XCDR (li.tail), val);
return plist;
}
- prev = tail;
- rarely_quit (++quit_count);
+ prev = li.tail;
+ li.tail = XCDR (li.tail);
+ if (EQ (li.tail, li.tortoise))
+ circular_list (plist);
}
Lisp_Object newcell
= Fcons (prop, Fcons (val, NILP (prev) ? plist : XCDR (XCDR (prev))));
one of the properties on the list. */)
(Lisp_Object plist, Lisp_Object prop)
{
- unsigned short int quit_count = 0;
- Lisp_Object tail;
-
- for (tail = plist;
- CONSP (tail) && CONSP (XCDR (tail));
- tail = XCDR (XCDR (tail)))
+ FOR_EACH_TAIL_CONS (plist)
{
- if (! NILP (Fequal (prop, XCAR (tail))))
- return XCAR (XCDR (tail));
- rarely_quit (++quit_count);
+ if (! CONSP (XCDR (li.tail)))
+ break;
+ if (! NILP (Fequal (prop, XCAR (li.tail))))
+ return XCAR (XCDR (li.tail));
+ li.tail = XCDR (li.tail);
+ if (EQ (li.tail, li.tortoise))
+ circular_list (plist);
}
-
- CHECK_LIST_END (tail, prop);
-
return Qnil;
}
The PLIST is modified by side effects. */)
(Lisp_Object plist, Lisp_Object prop, Lisp_Object val)
{
- unsigned short int quit_count = 0;
Lisp_Object prev = Qnil;
- for (Lisp_Object tail = plist; CONSP (tail) && CONSP (XCDR (tail));
- tail = XCDR (XCDR (tail)))
+ FOR_EACH_TAIL_CONS (plist)
{
- if (! NILP (Fequal (prop, XCAR (tail))))
+ if (! CONSP (XCDR (li.tail)))
+ break;
+
+ if (! NILP (Fequal (prop, XCAR (li.tail))))
{
- Fsetcar (XCDR (tail), val);
+ Fsetcar (XCDR (li.tail), val);
return plist;
}
- prev = tail;
- rarely_quit (++quit_count);
+ prev = li.tail;
+ li.tail = XCDR (li.tail);
+ if (EQ (li.tail, li.tortoise))
+ circular_list (plist);
}
Lisp_Object newcell = list2 (prop, val);
if (NILP (prev))
}
}
- unsigned short int quit_count = 0;
tail_recurse:
- rarely_quit (++quit_count);
if (EQ (o1, o2))
return 1;
if (XTYPE (o1) != XTYPE (o2))
}
case Lisp_Cons:
- if (!internal_equal (XCAR (o1), XCAR (o2), depth + 1, props, ht))
- return 0;
- o1 = XCDR (o1);
- o2 = XCDR (o2);
- /* FIXME: This inf-loops in a circular list! */
- goto tail_recurse;
+ {
+ Lisp_Object tail1 = o1;
+ FOR_EACH_TAIL_CONS (o1)
+ {
+ if (! CONSP (o2))
+ return false;
+ if (! internal_equal (XCAR (li.tail), XCAR (o2), depth + 1,
+ props, ht))
+ return false;
+ tail1 = XCDR (li.tail);
+ o2 = XCDR (o2);
+ if (EQ (tail1, o2))
+ return true;
+ }
+ o1 = tail1;
+ depth++;
+ goto tail_recurse;
+ }
case Lisp_Misc:
if (XMISCTYPE (o1) != XMISCTYPE (o2))
return 0;
o1 = XOVERLAY (o1)->plist;
o2 = XOVERLAY (o2)->plist;
+ depth++;
goto tail_recurse;
}
if (MARKERP (o1))
usage: (nconc &rest LISTS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- unsigned short int quit_count = 0;
Lisp_Object val = Qnil;
for (ptrdiff_t argnum = 0; argnum < nargs; argnum++)
CHECK_CONS (tem);
Lisp_Object tail;
- do
- {
- tail = tem;
- tem = XCDR (tail);
- rarely_quit (++quit_count);
- }
- while (CONSP (tem));
+ FOR_EACH_TAIL_CONS (tem)
+ tail = li.tail;
tem = args[argnum + 1];
Fsetcdr (tail, tem);
The value is actually the tail of PLIST whose car is PROP. */)
(Lisp_Object plist, Lisp_Object prop)
{
- unsigned short int quit_count = 0;
- while (CONSP (plist) && !EQ (XCAR (plist), prop))
+ FOR_EACH_TAIL (plist)
{
- plist = XCDR (plist);
- plist = CDR (plist);
- rarely_quit (++quit_count);
+ if (EQ (XCAR (li.tail), prop))
+ return li.tail;
+ if (!CONSP (XCDR (li.tail)))
+ {
+ CHECK_LIST_END (XCDR (li.tail), plist);
+ return Qnil;
+ }
+ li.tail = XCDR (li.tail);
+ if (EQ (li.tail, li.tortoise))
+ circular_list (plist);
}
- return plist;
+ return Qnil;
}
DEFUN ("widget-put", Fwidget_put, Swidget_put, 3, 3, 0,
#define QUITP (!NILP (Vquit_flag) && NILP (Vinhibit_quit))
-/* Heuristic on how many iterations of a tight loop can be safely done
- before it's time to do a quit. This must be a power of 2. It
- is nice but not necessary for it to equal USHRT_MAX + 1. */
-
-enum { QUIT_COUNT_HEURISTIC = 1 << 16 };
-
/* Process a quit rarely, based on a counter COUNT, for efficiency.
- "Rarely" means once per QUIT_COUNT_HEURISTIC or per USHRT_MAX + 1
- times, whichever is smaller (somewhat arbitrary, but often faster). */
+ "Rarely" means once per USHRT_MAX + 1 times; this is somewhat
+ arbitrary, but efficient. */
INLINE void
rarely_quit (unsigned short int count)
{
- if (! (count & (QUIT_COUNT_HEURISTIC - 1)))
+ if (! count)
maybe_quit ();
}
\f
http://maths-people.anu.edu.au/~brent/pd/rpb051i.pdf */
#define FOR_EACH_TAIL(list) \
+ FOR_EACH_TAIL_INTERNAL (list, CHECK_LIST_END (li.tail, list), \
+ circular_list (list))
+
+/* Like FOR_EACH_TAIL (LIST), except check only for cycles. */
+
+#define FOR_EACH_TAIL_CONS(list) \
+ FOR_EACH_TAIL_INTERNAL (list, (void) 0, circular_list (list))
+
+/* Like FOR_EACH_TAIL (LIST), except check for neither dotted lists
+ nor cycles. */
+
+#define FOR_EACH_TAIL_SAFE(list) \
+ FOR_EACH_TAIL_INTERNAL (list, (void) 0, (void) (li.tail = Qnil))
+
+/* 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. */
+
+#define FOR_EACH_TAIL_INTERNAL(list, dotted, cycle) \
for (struct { Lisp_Object tail, tortoise; intptr_t n, max; } li \
= { list, list, 2, 2 }; \
- CONSP (li.tail) || (CHECK_LIST_END (li.tail, list), false); \
+ 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) ? circular_list (list) : (void) 0)))
+ : EQ (li.tail, li.tortoise) ? (cycle) : (void) 0)))
/* Do a `for' loop over alist values. */