aboutsummaryrefslogtreecommitdiffstats
path: root/src/fns.c
diff options
context:
space:
mode:
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. */)
99 return lispy_val; 99 return lispy_val;
100} 100}
101 101
102/* Heuristic on how many iterations of a tight loop can be safely done
103 before it's time to do a QUIT. This must be a power of 2. */
104enum { QUIT_COUNT_HEURISTIC = 1 << 16 };
105
102/* Random data-structure functions */ 106/* Random data-structure functions */
103 107
104DEFUN ("length", Flength, Slength, 1, 1, 0, 108DEFUN ("length", Flength, Slength, 1, 1, 0,
@@ -128,7 +132,7 @@ To get the number of bytes, use `string-bytes'. */)
128 do 132 do
129 { 133 {
130 ++i; 134 ++i;
131 if ((i & ((1 << 10) - 1)) == 0) 135 if ((i & (QUIT_COUNT_HEURISTIC - 1)) == 0)
132 { 136 {
133 if (MOST_POSITIVE_FIXNUM < i) 137 if (MOST_POSITIVE_FIXNUM < i)
134 error ("List too long"); 138 error ("List too long");
@@ -159,22 +163,38 @@ it returns 0. If LIST is circular, it returns a finite value
159which is at least the number of distinct elements. */) 163which is at least the number of distinct elements. */)
160 (Lisp_Object list) 164 (Lisp_Object list)
161{ 165{
162 Lisp_Object tail, halftail, length; 166 Lisp_Object tail, halftail;
163 int len = 0; 167 double hilen = 0;
168 uintmax_t lolen = 1;
169
170 if (! CONSP (list))
171 return 0;
164 172
165 /* halftail is used to detect circular lists. */ 173 /* halftail is used to detect circular lists. */
166 halftail = list; 174 for (tail = halftail = list; ; )
167 for (tail = list; CONSP (tail); tail = XCDR (tail))
168 { 175 {
169 if (EQ (tail, halftail) && len != 0) 176 tail = XCDR (tail);
177 if (! CONSP (tail))
170 break; 178 break;
171 len++; 179 if (EQ (tail, halftail))
172 if ((len & 1) == 0) 180 break;
173 halftail = XCDR (halftail); 181 lolen++;
182 if ((lolen & 1) == 0)
183 {
184 halftail = XCDR (halftail);
185 if ((lolen & (QUIT_COUNT_HEURISTIC - 1)) == 0)
186 {
187 QUIT;
188 if (lolen == 0)
189 hilen += UINTMAX_MAX + 1.0;
190 }
191 }
174 } 192 }
175 193
176 XSETINT (length, len); 194 /* If the length does not fit into a fixnum, return a float.
177 return length; 195 On all known practical machines this returns an upper bound on
196 the true length. */
197 return hilen ? make_float (hilen + lolen) : make_fixnum_or_float (lolen);
178} 198}
179 199
180DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0, 200DEFUN ("string-bytes", Fstring_bytes, Sstring_bytes, 1, 1, 0,