emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Emacs-diffs] master 77fc272: Fix glitches introduced by nthcdr changes


From: Paul Eggert
Subject: [Emacs-diffs] master 77fc272: Fix glitches introduced by nthcdr changes
Date: Tue, 21 Aug 2018 05:05:37 -0400 (EDT)

branch: master
commit 77fc2725985b4e5ef977ae6930835c7f0771c61c
Author: Paul Eggert <address@hidden>
Commit: Paul Eggert <address@hidden>

    Fix glitches introduced by nthcdr changes
    
    * 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             | 35 +++++++++++++++++++++++++++--------
 test/src/fns-tests.el |  5 +++++
 2 files changed, 32 insertions(+), 8 deletions(-)

diff --git a/src/fns.c b/src/fns.c
index 8cff6b1..9d68101 100644
--- 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);
     }
 
diff --git a/test/src/fns-tests.el b/test/src/fns-tests.el
index 92dc18f..b180f30 100644
--- a/test/src/fns-tests.el
+++ b/test/src/fns-tests.el
@@ -624,6 +624,11 @@
         (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)))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]