From c80adde1d95b1da45039e6ec39fa7dd12aab2a33 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Mattias=20Engdeg=C3=A5rd?= Date: Tue, 19 Jul 2022 11:59:37 +0200 Subject: [PATCH] Speed up `butlast` * lisp/subr.el (butlast): Don't duplicate the removed part. * test/lisp/subr-tests.el (subr-tests--butlast-ref, subr-butlast): Add test. --- lisp/subr.el | 11 +++++++---- test/lisp/subr-tests.el | 17 +++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lisp/subr.el b/lisp/subr.el index ca4d52535a0..ef6cc41f3b9 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -707,11 +707,14 @@ If N is bigger than the length of LIST, return LIST." (defun butlast (list &optional n) "Return a copy of LIST with the last N elements removed. -If N is omitted or nil, the last element is removed from the -copy." +If N is omitted or nil, return a copy of LIST without its last element. +If N is zero or negative, return LIST." (declare (side-effect-free t)) - (if (and n (<= n 0)) list - (nbutlast (copy-sequence list) n))) + (unless n + (setq n 1)) + (if (<= n 0) + list + (take (- (length list) n) list))) (defun nbutlast (list &optional n) "Modify LIST to remove the last N elements. diff --git a/test/lisp/subr-tests.el b/test/lisp/subr-tests.el index ced2bc5c4e5..f5c1c40263e 100644 --- a/test/lisp/subr-tests.el +++ b/test/lisp/subr-tests.el @@ -1090,5 +1090,22 @@ final or penultimate step during initialization.")) (should-not (plistp '(1 2 3))) (should-not (plistp '(1 2 3 . 4)))) +(defun subr-tests--butlast-ref (list &optional n) + "Reference implementation of `butlast'." + (let ((m (or n 1)) + (len (length list))) + (let ((r nil)) + (while (and list (> len m)) + (push (car list) r) + (setq list (cdr list)) + (setq len (1- len))) + (nreverse r)))) + +(ert-deftest subr-butlast () + (dolist (l '(nil '(a) '(a b) '(a b c) '(a b c d))) + (dolist (n (cons nil (number-sequence -2 6))) + (should (equal (butlast l n) + (subr-tests--butlast-ref l n)))))) + (provide 'subr-tests) ;;; subr-tests.el ends here -- 2.39.5