(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.
(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