]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix glitches introduced by nthcdr changes
authorPaul Eggert <eggert@Penguin.CS.UCLA.EDU>
Tue, 21 Aug 2018 09:05:07 +0000 (02:05 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Tue, 21 Aug 2018 09:05:31 +0000 (02:05 -0700)
* src/fns.c (Fnthcdr): Fix recently-introduced bug when
nthcdr is supposed to yield a non-nil non-cons.
Reported by Glenn Morris and by Pip Cet here:
https://lists.gnu.org/r/emacs-devel/2018-08/msg00699.html
https://lists.gnu.org/r/emacs-devel/2018-08/msg00708.html
Speed up nthcdr for small N, as suggested by Pip Cet here:
https://lists.gnu.org/r/emacs-devel/2018-08/msg00707.html
* test/src/fns-tests.el (test-nthcdr-simple): New test.

src/fns.c
test/src/fns-tests.el

index 8cff6b1b6cac213c2793240fc6ea2fc37df7ea2b..9d681017c14af57bee68ded448474f59c5fc417c 100644 (file)
--- a/src/fns.c
+++ b/src/fns.c
@@ -1402,6 +1402,8 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
        doc: /* Take cdr N times on LIST, return the result.  */)
   (Lisp_Object n, Lisp_Object list)
 {
+  Lisp_Object tail = list;
+
   CHECK_INTEGER (n);
 
   /* A huge but in-range EMACS_INT that can be substituted for a
@@ -1412,24 +1414,41 @@ DEFUN ("nthcdr", Fnthcdr, Snthcdr, 2, 2, 0,
 
   EMACS_INT num;
   if (FIXNUMP (n))
-    num = XFIXNUM (n);
+    {
+      num = XFIXNUM (n);
+
+      /* Speed up small lists by omitting circularity and quit checking.  */
+      if (num < 128)
+       {
+         for (; 0 < num; num--, tail = XCDR (tail))
+           if (! CONSP (tail))
+             {
+               CHECK_LIST_END (tail, list);
+               return Qnil;
+             }
+         return tail;
+       }
+    }
   else
     {
-      num = mpz_sgn (XBIGNUM (n)->value);
-      if (0 < num)
-       num = large_num;
+      if (mpz_sgn (XBIGNUM (n)->value) < 0)
+       return tail;
+      num = large_num;
     }
 
   EMACS_INT tortoise_num = num;
-  Lisp_Object tail = list, saved_tail = tail;
+  Lisp_Object saved_tail = tail;
   FOR_EACH_TAIL_SAFE (tail)
     {
-      if (num <= 0)
-       return tail;
-      if (tail == li.tortoise)
+      /* If the tortoise just jumped (which is rare),
+        update TORTOISE_NUM accordingly.  */
+      if (EQ (tail, li.tortoise))
        tortoise_num = num;
+
       saved_tail = XCDR (tail);
       num--;
+      if (num == 0)
+       return saved_tail;
       rarely_quit (num);
     }
 
index 92dc18fa0346bfc054c12a8928702f3f1d60d7b6..b180f30f285e2888ba2f118c04c87ddc48171e7e 100644 (file)
         (should (eq (gethash b2 hash)
                     (funcall test b1 b2)))))))
 
+(ert-deftest test-nthcdr-simple ()
+  (should (eq (nthcdr 0 'x) 'x))
+  (should (eq (nthcdr 1 '(x . y)) 'y))
+  (should (eq (nthcdr 2 '(x y . z)) 'z)))
+
 (ert-deftest test-nthcdr-circular ()
   (dolist (len '(1 2 5 37 120 997 1024))
     (let ((cycle (make-list len nil)))