emacs-diffs
[Top][All Lists]
Advanced

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

master c80adde1d9: Speed up `butlast`


From: Mattias Engdegård
Subject: master c80adde1d9: Speed up `butlast`
Date: Tue, 19 Jul 2022 06:17:25 -0400 (EDT)

branch: master
commit c80adde1d95b1da45039e6ec39fa7dd12aab2a33
Author: Mattias Engdegård <mattiase@acm.org>
Commit: Mattias Engdegård <mattiase@acm.org>

    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 ca4d52535a..ef6cc41f3b 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 ced2bc5c4e..f5c1c40263 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



reply via email to

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