emacs-diffs
[Top][All Lists]
Advanced

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

[Emacs-diffs] master 4daca38: Prevent for consing in cl-mapc and cl-mapl


From: Tino Calancha
Subject: [Emacs-diffs] master 4daca38: Prevent for consing in cl-mapc and cl-mapl
Date: Mon, 27 Feb 2017 02:32:45 -0500 (EST)

branch: master
commit 4daca38d5c673c5b6862e10cfade9559852cce12
Author: Tino Calancha <address@hidden>
Commit: Tino Calancha <address@hidden>

    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.
---
 lisp/emacs-lisp/cl-extra.el            | 38 +++++++++++++++-------
 lisp/emacs-lisp/cl-lib.el              |  5 +--
 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 edd14b8..8cba913 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -89,7 +89,7 @@ strings case-insensitively."
 ;;; Control structures.
 
 ;;;###autoload
-(defun cl--mapcar-many (cl-func cl-seqs)
+(defun cl--mapcar-many (cl-func cl-seqs &optional acc)
   (if (cdr (cdr cl-seqs))
       (let* ((cl-res nil)
             (cl-n (apply 'min (mapcar 'length cl-seqs)))
@@ -106,20 +106,23 @@ strings case-insensitively."
                          (setcar cl-p1 (cdr (car cl-p1))))
                      (aref (car cl-p1) cl-i)))
            (setq cl-p1 (cdr cl-p1) cl-p2 (cdr cl-p2)))
-         (push (apply cl-func cl-args) cl-res)
+         (if acc
+             (push (apply cl-func cl-args) cl-res)
+           (apply cl-func cl-args))
          (setq cl-i (1+ cl-i)))
-       (nreverse cl-res))
+       (and acc (nreverse cl-res)))
     (let ((cl-res nil)
          (cl-x (car cl-seqs))
          (cl-y (nth 1 cl-seqs)))
       (let ((cl-n (min (length cl-x) (length cl-y)))
            (cl-i -1))
        (while (< (setq cl-i (1+ cl-i)) cl-n)
-         (push (funcall cl-func
-                         (if (consp cl-x) (pop cl-x) (aref cl-x cl-i))
-                         (if (consp cl-y) (pop cl-y) (aref cl-y cl-i)))
-                cl-res)))
-      (nreverse cl-res))))
+         (let ((val (funcall cl-func
+                             (if (consp cl-x) (pop cl-x) (aref cl-x cl-i))
+                             (if (consp cl-y) (pop cl-y) (aref cl-y cl-i)))))
+           (when acc
+             (push val cl-res)))))
+       (and acc (nreverse cl-res)))))
 
 ;;;###autoload
 (defun cl-map (cl-type cl-func cl-seq &rest cl-rest)
@@ -142,7 +145,7 @@ the elements themselves.
        (while (not (memq nil cl-args))
          (push (apply cl-func cl-args) cl-res)
          (setq cl-p cl-args)
-         (while cl-p (setcar cl-p (cdr (pop cl-p)) )))
+         (while cl-p (setcar cl-p (cdr (pop cl-p)))))
        (nreverse cl-res))
     (let ((cl-res nil))
       (while cl-list
@@ -155,8 +158,14 @@ the elements themselves.
   "Like `cl-mapcar', but does not accumulate values returned by the function.
 \n(fn FUNCTION SEQUENCE...)"
   (if cl-rest
-      (progn (apply 'cl-map nil cl-func cl-seq cl-rest)
-            cl-seq)
+      (if (or (cdr cl-rest) (nlistp cl-seq) (nlistp (car cl-rest)))
+          (progn
+            (cl--mapcar-many cl-func (cons cl-seq cl-rest))
+            cl-seq)
+        (let ((cl-x cl-seq) (cl-y (car cl-rest)))
+          (while (and cl-x cl-y)
+            (funcall cl-func (pop cl-x) (pop cl-y)))
+          cl-seq))
     (mapc cl-func cl-seq)))
 
 ;;;###autoload
@@ -164,7 +173,12 @@ the elements themselves.
   "Like `cl-maplist', but does not accumulate values returned by the function.
 \n(fn FUNCTION LIST...)"
   (if cl-rest
-      (apply 'cl-maplist cl-func cl-list cl-rest)
+      (let ((cl-args (cons cl-list (copy-sequence cl-rest)))
+           cl-p)
+       (while (not (memq nil cl-args))
+          (apply cl-func cl-args)
+         (setq cl-p cl-args)
+         (while cl-p (setcar cl-p (cdr (pop cl-p))))))
     (let ((cl-p cl-list))
       (while cl-p (funcall cl-func cl-p) (setq cl-p (cdr cl-p)))))
   cl-list)
diff --git a/lisp/emacs-lisp/cl-lib.el b/lisp/emacs-lisp/cl-lib.el
index 5aa8f1b..8c4455a 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.")
 
 (cl--defalias 'cl-copy-seq 'copy-sequence)
 
-(declare-function cl--mapcar-many "cl-extra" (cl-func cl-seqs))
+(declare-function cl--mapcar-many "cl-extra" (cl-func cl-seqs &optional acc))
 
+;;;###autoload
 (defun cl-mapcar (cl-func cl-x &rest cl-rest)
   "Apply FUNCTION to each element of SEQ, and make a list of the results.
 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
 \n(fn FUNCTION SEQ...)"
   (if cl-rest
       (if (or (cdr cl-rest) (nlistp cl-x) (nlistp (car cl-rest)))
-         (cl--mapcar-many cl-func (cons cl-x cl-rest))
+         (cl--mapcar-many cl-func (cons cl-x cl-rest) 'accumulate)
        (let ((cl-res nil) (cl-y (car cl-rest)))
          (while (and cl-x cl-y)
            (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 3e2388a..5b2371e 100644
--- a/test/lisp/emacs-lisp/cl-extra-tests.el
+++ b/test/lisp/emacs-lisp/cl-extra-tests.el
@@ -35,4 +35,63 @@
     (should (eq (cl-getf plist 'y :none) nil))
     (should (eq (cl-getf plist 'z :none) :none))))
 
+(ert-deftest cl-extra-test-mapc ()
+  (let ((lst '(a b c))
+        (lst2 '(d e f))
+        (lst3 '(1 2 3))
+        (fn1 (lambda (_x) nil))
+        (fn2 (lambda (_x _y) nil))
+        (fn3 (lambda (_x _y _z) nil)))
+    (should (equal lst (cl-mapc fn1 lst)))
+    (should (equal lst (cl-mapc fn2 lst lst2)))
+    (should (equal lst (cl-mapc fn3 lst lst2 lst3)))))
+
+(ert-deftest cl-extra-test-mapl ()
+  (let ((lst '(a b c))
+        (lst2 '(d e f))
+        (lst3 '(1 2 3))
+        (fn1 (lambda (x) (should (consp x))))
+        (fn2 (lambda (x y) (should (and (consp x) (consp y)))))
+        (fn3 (lambda (x y z) (should (and (consp x) (consp y) (consp z))))))
+    (should (equal lst (cl-mapl fn1 lst)))
+    (should (equal lst (cl-mapl fn2 lst lst2)))
+    (should (equal lst (cl-mapl fn3 lst lst2 lst3)))))
+
+(ert-deftest cl-extra-test-mapcar ()
+  (let ((lst '(a b c))
+        (lst2 '(d e f))
+        (lst3 '(1 2 3))
+        (fn1 (lambda (x) x))
+        (fn2 (lambda (_x y) y))
+        (fn3 (lambda (_x _y z) z)))
+    (should (equal lst (cl-mapcar fn1 lst)))
+    (should (equal lst2 (cl-mapcar fn2 lst lst2)))
+    (should (equal lst3 (cl-mapcar fn3 lst lst2 lst3)))))
+
+(ert-deftest cl-extra-test-map ()
+  (let ((lst '(a b c))
+        (lst2 '(d e f))
+        (lst3 '(1 2 3))
+        (fn1 (lambda (x) x))
+        (fn2 (lambda (_x y) y))
+        (fn3 (lambda (x _y _z) (string-to-char (format "%S" x)))))
+    (should (equal lst (cl-map 'list fn1 lst)))
+    (should (equal (vconcat lst2) (cl-map 'vector fn2 lst lst2)))
+    (should (equal (mapconcat (lambda (x) (format "%S" x)) lst "")
+                   (cl-map 'string fn3 lst lst2 lst3)))))
+
+(ert-deftest cl-extra-test-maplist ()
+  (let ((lst '(a b c))
+        (lst2 '(d e f))
+        (lst3 '(1 2 3))
+        (fn1 (lambda (x) (should (consp x)) x))
+        (fn2 (lambda (x y) (should (and (consp x) (consp y))) y))
+        (fn3 (lambda (x y z) (should (and (consp x) (consp y) (consp z))) z)))
+    (should (equal (list lst (cdr lst) (cddr lst))
+                   (cl-maplist fn1 lst)))
+    (should (equal (list lst2 (cdr lst2) (cddr lst2))
+                   (cl-maplist fn2 lst lst2)))
+    (should (equal (list lst3 (cdr lst3) (cddr lst3))
+                   (cl-maplist fn3 lst lst2 lst3)))))
+
 ;;; cl-extra-tests.el ends here



reply via email to

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