]> git.eshelyaron.com Git - emacs.git/commitdiff
Speed up `butlast`
authorMattias Engdegård <mattiase@acm.org>
Tue, 19 Jul 2022 09:59:37 +0000 (11:59 +0200)
committerMattias Engdegård <mattiase@acm.org>
Tue, 19 Jul 2022 10:09:33 +0000 (12:09 +0200)
* 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
test/lisp/subr-tests.el

index ca4d52535a0f9783e55f626d58252274875af569..ef6cc41f3b9c6ccfaedb3c39e83f8f5b87e27972 100644 (file)
@@ -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.
index ced2bc5c4e5ba1a24d3327423c01139b2a2a832f..f5c1c40263e7ac12ee1ba3e3959f754befceee41 100644 (file)
@@ -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