summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2011-06-14 15:32:12 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2011-06-14 15:32:12 -0700
commite6966cd635f324edcc27adecb82cd85c71cbfcad (patch)
tree0412f99ae48f617d75b9ae26b2f27eb7d018d592 /src/fns.c
parent00c604f263874880cc55a000af884c55743d6441 (diff)
downloademacs-e6966cd635f324edcc27adecb82cd85c71cbfcad.tar.gz
emacs-e6966cd635f324edcc27adecb82cd85c71cbfcad.tar.bz2
emacs-e6966cd635f324edcc27adecb82cd85c71cbfcad.zip
* fns.c: Don't overflow int when computing a list length.
(Fsafe_length): Return a float if the value is not representable as a fixnum. This shouldn't happen except in contrived situations. Use same QUIT_COUNT_HEURISTIC as Flength now does.
Diffstat (limited to 'src/fns.c')
-rw-r--r--src/fns.c42
1 files changed, 31 insertions, 11 deletions
diff --git a/src/fns.c b/src/fns.c
index 7d5d1bd5d99..10af162cfc4 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -99,6 +99,10 @@ Other values of LIMIT are ignored. */)
return lispy_val;
}
+/* 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,
@@ -128,7 +132,7 @@ To get the number of bytes, use `string-bytes'. */)
do
{
++i;
- if ((i & ((1 << 10) - 1)) == 0)
+ if ((i & (QUIT_COUNT_HEURISTIC - 1)) == 0)
{
if (MOST_POSITIVE_FIXNUM < i)
error ("List too long");
@@ -159,22 +163,38 @@ it returns 0. If LIST is circular, it returns a finite value
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,