1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-17 10:06:13 +00:00

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.
This commit is contained in:
Paul Eggert 2018-08-21 02:05:07 -07:00 committed by Paul Eggert
parent eb83344fc7
commit 77fc272598
2 changed files with 32 additions and 8 deletions

View File

@ -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);
/* 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)
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);
}

View File

@ -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)))