2011-06-14 Paul Eggert <eggert@cs.ucla.edu>
- * fns.c (Flength): Don't overflow int when computing a list length.
- Use EMACS_INT, not int, to avoid unwanted truncation on 64-bit hosts.
- Check for QUIT every 1024 entries rather than every other entry;
- that's faster and is responsive enough. Report an error instead of
- overflowing an integer.
+ * fns.c: Don't overflow int when computing a list length.
+ * fns.c (QUIT_COUNT_HEURISTIC): New constant.
+ (Flength, Fsafe_length): Use EMACS_INT, not int, to avoid unwanted
+ truncation on 64-bit hosts. Check for QUIT every
+ QUIT_COUNT_HEURISTIC entries rather than every other entry; that's
+ faster and is responsive enough.
+ (Flength): Report an error instead of overflowing an integer.
+ (Fsafe_length): Return a float if the value is not representable
+ as a fixnum. This shouldn't happen except in contrived situations.
* alloc.c: Check that resized vectors' lengths fit in fixnums.
(header_size, word_size): New constants.
return lispy_val;
}
\f
+/* 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. */
+enum { QUIT_COUNT_HEURISTIC = 1 << 16 };
+
/* Random data-structure functions */
DEFUN ("length", Flength, Slength, 1, 1, 0,
do
{
++i;
- if ((i & ((1 << 10) - 1)) == 0)
+ if ((i & (QUIT_COUNT_HEURISTIC - 1)) == 0)
{
if (MOST_POSITIVE_FIXNUM < i)
error ("List too long");
which is at least the number of distinct elements. */)
(Lisp_Object list)
{
- Lisp_Object tail, halftail, length;
- int len = 0;
+ Lisp_Object tail, halftail;
+ double hilen = 0;
+ uintmax_t lolen = 1;
+
+ if (! CONSP (list))
+ return 0;
/* halftail is used to detect circular lists. */
- halftail = list;
- for (tail = list; CONSP (tail); tail = XCDR (tail))
+ for (tail = halftail = list; ; )
{
- if (EQ (tail, halftail) && len != 0)
+ tail = XCDR (tail);
+ if (! CONSP (tail))
break;
- len++;
- if ((len & 1) == 0)
- halftail = XCDR (halftail);
+ if (EQ (tail, halftail))
+ break;
+ lolen++;
+ if ((lolen & 1) == 0)
+ {
+ halftail = XCDR (halftail);
+ if ((lolen & (QUIT_COUNT_HEURISTIC - 1)) == 0)
+ {
+ QUIT;
+ if (lolen == 0)
+ hilen += UINTMAX_MAX + 1.0;
+ }
+ }
}
- XSETINT (length, len);
- return length;
+ /* 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);
}
DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,