diff options
| author | Tino Calancha | 2017-02-27 16:32:10 +0900 |
|---|---|---|
| committer | Tino Calancha | 2017-02-27 16:32:10 +0900 |
| commit | 4daca38d5c673c5b6862e10cfade9559852cce12 (patch) | |
| tree | f50e54581adcb9d69f5d927dec55ba2e13ed63bc | |
| parent | 841e3e377c97142cfe76b9d91467f439198f5e39 (diff) | |
| download | emacs-4daca38d5c673c5b6862e10cfade9559852cce12.tar.gz emacs-4daca38d5c673c5b6862e10cfade9559852cce12.zip | |
Prevent for consing in cl-mapc and cl-mapl
* lisp/emacs-lisp/cl-extra.el (cl--mapcar-many): Add optional arg ACC;
If non-nil, accumulate values in the result (Bug#25826).
(cl-mapc): Do computations inside function instead of call cl-map.
(cl-mapl): Do computations inside function instead of call cl-maplist.
* lisp/emacs-lisp/cl-lib.el (mapcar): Add autoload cookie.
Call cl--mapcar-many with non-nil 3rd argument.
* test/lisp/emacs-lisp/cl-extra-tests.el (cl-extra-test-map)
(cl-extra-test-mapc, cl-extra-test-mapcar, cl-extra-test-mapl)
(cl-extra-test-maplist): New tests.
| -rw-r--r-- | lisp/emacs-lisp/cl-extra.el | 38 | ||||
| -rw-r--r-- | lisp/emacs-lisp/cl-lib.el | 5 | ||||
| -rw-r--r-- | test/lisp/emacs-lisp/cl-extra-tests.el | 59 |
3 files changed, 88 insertions, 14 deletions
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el index edd14b816f0..8cba9137105 100644 --- a/lisp/emacs-lisp/cl-extra.el +++ b/lisp/emacs-lisp/cl-extra.el | |||
| @@ -89,7 +89,7 @@ strings case-insensitively." | |||
| 89 | ;;; Control structures. | 89 | ;;; Control structures. |
| 90 | 90 | ||
| 91 | ;;;###autoload | 91 | ;;;###autoload |
| 92 | (defun cl--mapcar-many (cl-func cl-seqs) | 92 | (defun cl--mapcar-many (cl-func cl-seqs &optional acc) |
| 93 | (if (cdr (cdr cl-seqs)) | 93 | (if (cdr (cdr cl-seqs)) |
| 94 | (let* ((cl-res nil) | 94 | (let* ((cl-res nil) |
| 95 | (cl-n (apply 'min (mapcar 'length cl-seqs))) | 95 | (cl-n (apply 'min (mapcar 'length cl-seqs))) |
| @@ -106,20 +106,23 @@ strings case-insensitively." | |||
| 106 | (setcar cl-p1 (cdr (car cl-p1)))) | 106 | (setcar cl-p1 (cdr (car cl-p1)))) |
| 107 | (aref (car cl-p1) cl-i))) | 107 | (aref (car cl-p1) cl-i))) |
| 108 | (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2))) | 108 | (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2))) |
| 109 | (push (apply cl-func cl-args) cl-res) | 109 | (if acc |
| 110 | (push (apply cl-func cl-args) cl-res) | ||
| 111 | (apply cl-func cl-args)) | ||
| 110 | (setq cl-i (1+ cl-i))) | 112 | (setq cl-i (1+ cl-i))) |
| 111 | (nreverse cl-res)) | 113 | (and acc (nreverse cl-res))) |
| 112 | (let ((cl-res nil) | 114 | (let ((cl-res nil) |
| 113 | (cl-x (car cl-seqs)) | 115 | (cl-x (car cl-seqs)) |
| 114 | (cl-y (nth 1 cl-seqs))) | 116 | (cl-y (nth 1 cl-seqs))) |
| 115 | (let ((cl-n (min (length cl-x) (length cl-y))) | 117 | (let ((cl-n (min (length cl-x) (length cl-y))) |
| 116 | (cl-i -1)) | 118 | (cl-i -1)) |
| 117 | (while (< (setq cl-i (1+ cl-i)) cl-n) | 119 | (while (< (setq cl-i (1+ cl-i)) cl-n) |
| 118 | (push (funcall cl-func | 120 | (let ((val (funcall cl-func |
| 119 | (if (consp cl-x) (pop cl-x) (aref cl-x cl-i)) | 121 | (if (consp cl-x) (pop cl-x) (aref cl-x cl-i)) |
| 120 | (if (consp cl-y) (pop cl-y) (aref cl-y cl-i))) | 122 | (if (consp cl-y) (pop cl-y) (aref cl-y cl-i))))) |
| 121 | cl-res))) | 123 | (when acc |
| 122 | (nreverse cl-res)))) | 124 | (push val cl-res))))) |
| 125 | (and acc (nreverse cl-res))))) | ||
| 123 | 126 | ||
| 124 | ;;;###autoload | 127 | ;;;###autoload |
| 125 | (defun cl-map (cl-type cl-func cl-seq &rest cl-rest) | 128 | (defun cl-map (cl-type cl-func cl-seq &rest cl-rest) |
| @@ -142,7 +145,7 @@ the elements themselves. | |||
| 142 | (while (not (memq nil cl-args)) | 145 | (while (not (memq nil cl-args)) |
| 143 | (push (apply cl-func cl-args) cl-res) | 146 | (push (apply cl-func cl-args) cl-res) |
| 144 | (setq cl-p cl-args) | 147 | (setq cl-p cl-args) |
| 145 | (while cl-p (setcar cl-p (cdr (pop cl-p)) ))) | 148 | (while cl-p (setcar cl-p (cdr (pop cl-p))))) |
| 146 | (nreverse cl-res)) | 149 | (nreverse cl-res)) |
| 147 | (let ((cl-res nil)) | 150 | (let ((cl-res nil)) |
| 148 | (while cl-list | 151 | (while cl-list |
| @@ -155,8 +158,14 @@ the elements themselves. | |||
| 155 | "Like `cl-mapcar', but does not accumulate values returned by the function. | 158 | "Like `cl-mapcar', but does not accumulate values returned by the function. |
| 156 | \n(fn FUNCTION SEQUENCE...)" | 159 | \n(fn FUNCTION SEQUENCE...)" |
| 157 | (if cl-rest | 160 | (if cl-rest |
| 158 | (progn (apply 'cl-map nil cl-func cl-seq cl-rest) | 161 | (if (or (cdr cl-rest) (nlistp cl-seq) (nlistp (car cl-rest))) |
| 159 | cl-seq) | 162 | (progn |
| 163 | (cl--mapcar-many cl-func (cons cl-seq cl-rest)) | ||
| 164 | cl-seq) | ||
| 165 | (let ((cl-x cl-seq) (cl-y (car cl-rest))) | ||
| 166 | (while (and cl-x cl-y) | ||
| 167 | (funcall cl-func (pop cl-x) (pop cl-y))) | ||
| 168 | cl-seq)) | ||
| 160 | (mapc cl-func cl-seq))) | 169 | (mapc cl-func cl-seq))) |
| 161 | 170 | ||
| 162 | ;;;###autoload | 171 | ;;;###autoload |
| @@ -164,7 +173,12 @@ the elements themselves. | |||
| 164 | "Like `cl-maplist', but does not accumulate values returned by the function. | 173 | "Like `cl-maplist', but does not accumulate values returned by the function. |
| 165 | \n(fn FUNCTION LIST...)" | 174 | \n(fn FUNCTION LIST...)" |
| 166 | (if cl-rest | 175 | (if cl-rest |
| 167 | (apply 'cl-maplist cl-func cl-list cl-rest) | 176 | (let ((cl-args (cons cl-list (copy-sequence cl-rest))) |
| 177 | cl-p) | ||
| 178 | (while (not (memq nil cl-args)) | ||
| 179 | (apply cl-func cl-args) | ||
| 180 | (setq cl-p cl-args) | ||
| 181 | (while cl-p (setcar cl-p (cdr (pop cl-p)))))) | ||
| 168 | (let ((cl-p cl-list)) | 182 | (let ((cl-p cl-list)) |
| 169 | (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p))))) | 183 | (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p))))) |
| 170 | cl-list) | 184 | cl-list) |
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el index 5aa8f1bf652..8c4455a3dad 100644 --- a/lisp/emacs-lisp/cl-lib.el +++ b/lisp/emacs-lisp/cl-lib.el | |||
| @@ -347,8 +347,9 @@ Call `cl-float-limits' to set this.") | |||
| 347 | 347 | ||
| 348 | (cl--defalias 'cl-copy-seq 'copy-sequence) | 348 | (cl--defalias 'cl-copy-seq 'copy-sequence) |
| 349 | 349 | ||
| 350 | (declare-function cl--mapcar-many "cl-extra" (cl-func cl-seqs)) | 350 | (declare-function cl--mapcar-many "cl-extra" (cl-func cl-seqs &optional acc)) |
| 351 | 351 | ||
| 352 | ;;;###autoload | ||
| 352 | (defun cl-mapcar (cl-func cl-x &rest cl-rest) | 353 | (defun cl-mapcar (cl-func cl-x &rest cl-rest) |
| 353 | "Apply FUNCTION to each element of SEQ, and make a list of the results. | 354 | "Apply FUNCTION to each element of SEQ, and make a list of the results. |
| 354 | If there are several SEQs, FUNCTION is called with that many arguments, | 355 | If there are several SEQs, FUNCTION is called with that many arguments, |
| @@ -358,7 +359,7 @@ SEQ, this is like `mapcar'. With several, it is like the Common Lisp | |||
| 358 | \n(fn FUNCTION SEQ...)" | 359 | \n(fn FUNCTION SEQ...)" |
| 359 | (if cl-rest | 360 | (if cl-rest |
| 360 | (if (or (cdr cl-rest) (nlistp cl-x) (nlistp (car cl-rest))) | 361 | (if (or (cdr cl-rest) (nlistp cl-x) (nlistp (car cl-rest))) |
| 361 | (cl--mapcar-many cl-func (cons cl-x cl-rest)) | 362 | (cl--mapcar-many cl-func (cons cl-x cl-rest) 'accumulate) |
| 362 | (let ((cl-res nil) (cl-y (car cl-rest))) | 363 | (let ((cl-res nil) (cl-y (car cl-rest))) |
| 363 | (while (and cl-x cl-y) | 364 | (while (and cl-x cl-y) |
| 364 | (push (funcall cl-func (pop cl-x) (pop cl-y)) cl-res)) | 365 | (push (funcall cl-func (pop cl-x) (pop cl-y)) cl-res)) |
diff --git a/test/lisp/emacs-lisp/cl-extra-tests.el b/test/lisp/emacs-lisp/cl-extra-tests.el index 3e2388acc6f..5b2371e7b95 100644 --- a/test/lisp/emacs-lisp/cl-extra-tests.el +++ b/test/lisp/emacs-lisp/cl-extra-tests.el | |||
| @@ -35,4 +35,63 @@ | |||
| 35 | (should (eq (cl-getf plist 'y :none) nil)) | 35 | (should (eq (cl-getf plist 'y :none) nil)) |
| 36 | (should (eq (cl-getf plist 'z :none) :none)))) | 36 | (should (eq (cl-getf plist 'z :none) :none)))) |
| 37 | 37 | ||
| 38 | (ert-deftest cl-extra-test-mapc () | ||
| 39 | (let ((lst '(a b c)) | ||
| 40 | (lst2 '(d e f)) | ||
| 41 | (lst3 '(1 2 3)) | ||
| 42 | (fn1 (lambda (_x) nil)) | ||
| 43 | (fn2 (lambda (_x _y) nil)) | ||
| 44 | (fn3 (lambda (_x _y _z) nil))) | ||
| 45 | (should (equal lst (cl-mapc fn1 lst))) | ||
| 46 | (should (equal lst (cl-mapc fn2 lst lst2))) | ||
| 47 | (should (equal lst (cl-mapc fn3 lst lst2 lst3))))) | ||
| 48 | |||
| 49 | (ert-deftest cl-extra-test-mapl () | ||
| 50 | (let ((lst '(a b c)) | ||
| 51 | (lst2 '(d e f)) | ||
| 52 | (lst3 '(1 2 3)) | ||
| 53 | (fn1 (lambda (x) (should (consp x)))) | ||
| 54 | (fn2 (lambda (x y) (should (and (consp x) (consp y))))) | ||
| 55 | (fn3 (lambda (x y z) (should (and (consp x) (consp y) (consp z)))))) | ||
| 56 | (should (equal lst (cl-mapl fn1 lst))) | ||
| 57 | (should (equal lst (cl-mapl fn2 lst lst2))) | ||
| 58 | (should (equal lst (cl-mapl fn3 lst lst2 lst3))))) | ||
| 59 | |||
| 60 | (ert-deftest cl-extra-test-mapcar () | ||
| 61 | (let ((lst '(a b c)) | ||
| 62 | (lst2 '(d e f)) | ||
| 63 | (lst3 '(1 2 3)) | ||
| 64 | (fn1 (lambda (x) x)) | ||
| 65 | (fn2 (lambda (_x y) y)) | ||
| 66 | (fn3 (lambda (_x _y z) z))) | ||
| 67 | (should (equal lst (cl-mapcar fn1 lst))) | ||
| 68 | (should (equal lst2 (cl-mapcar fn2 lst lst2))) | ||
| 69 | (should (equal lst3 (cl-mapcar fn3 lst lst2 lst3))))) | ||
| 70 | |||
| 71 | (ert-deftest cl-extra-test-map () | ||
| 72 | (let ((lst '(a b c)) | ||
| 73 | (lst2 '(d e f)) | ||
| 74 | (lst3 '(1 2 3)) | ||
| 75 | (fn1 (lambda (x) x)) | ||
| 76 | (fn2 (lambda (_x y) y)) | ||
| 77 | (fn3 (lambda (x _y _z) (string-to-char (format "%S" x))))) | ||
| 78 | (should (equal lst (cl-map 'list fn1 lst))) | ||
| 79 | (should (equal (vconcat lst2) (cl-map 'vector fn2 lst lst2))) | ||
| 80 | (should (equal (mapconcat (lambda (x) (format "%S" x)) lst "") | ||
| 81 | (cl-map 'string fn3 lst lst2 lst3))))) | ||
| 82 | |||
| 83 | (ert-deftest cl-extra-test-maplist () | ||
| 84 | (let ((lst '(a b c)) | ||
| 85 | (lst2 '(d e f)) | ||
| 86 | (lst3 '(1 2 3)) | ||
| 87 | (fn1 (lambda (x) (should (consp x)) x)) | ||
| 88 | (fn2 (lambda (x y) (should (and (consp x) (consp y))) y)) | ||
| 89 | (fn3 (lambda (x y z) (should (and (consp x) (consp y) (consp z))) z))) | ||
| 90 | (should (equal (list lst (cdr lst) (cddr lst)) | ||
| 91 | (cl-maplist fn1 lst))) | ||
| 92 | (should (equal (list lst2 (cdr lst2) (cddr lst2)) | ||
| 93 | (cl-maplist fn2 lst lst2))) | ||
| 94 | (should (equal (list lst3 (cdr lst3) (cddr lst3)) | ||
| 95 | (cl-maplist fn3 lst lst2 lst3))))) | ||
| 96 | |||
| 38 | ;;; cl-extra-tests.el ends here | 97 | ;;; cl-extra-tests.el ends here |