An efficient built-in mapcan

A built-in version of `mapcan' avoids consing up (and GC'ing) the
intermediate list.

* src/fns.c (Fmapcan): New built-in.
(syms_of_fns): Define.

* lisp/emacs-lisp/cl.el (mapcan): Remove defalias.

* lisp/emacs-lisp/cl-extra.el (cl-mapcan): Use built-in `mapcan'
if only one sequence is provided.

* lisp/progmodes/hideif.el (hif-delimit):
* lisp/dired-aux.el (dired-do-find-regexp):
* lisp/woman.el (woman-parse-colon-path): Use `mapcan' instead of
`cl-mapcan'.

* lisp/woman.el (eval-when-compile): Require 'cl-lib only when
compiling.

* lisp/mouse.el (mouse-buffer-menu-map):
* lisp/net/pop3.el (pop3-uidl-dele):
* lisp/progmodes/gud.el (gud-jdb-build-source-files-list):
* lisp/cedet/semantic/db-find.el (semanticdb-fast-strip-find-results):
* lisp/cedet/semantic/symref/grep.el (semantic-symref-derive-find-filepatterns):
* lisp/gnus/nnmail.el (nnmail-split-it):
* lisp/gnus/gnus-sum.el (gnus-articles-in-thread):
* lisp/gnus/gnus-registry.el (gnus-registry-sort-addresses):
* lisp/gnus/gnus-util.el (gnus-mapcar): Use `mapcan'.
This commit is contained in:
Mario Lang 2016-07-10 01:18:47 +02:00
parent c3223dd505
commit 466ee1b3ea
16 changed files with 51 additions and 25 deletions

View file

@ -557,6 +557,9 @@ ABBR is a time zone abbreviation. The affected functions are
*** New basic face 'fixed-pitch-serif', for a fixed-width font with serifs.
The Info-quoted and tex-verbatim faces now default to inheriting from it.
** New built-in function `mapcan' which avoids unnecessary consing (and garbage
collection).
* Changes in Emacs 25.2 on Non-Free Operating Systems

View file

@ -902,7 +902,7 @@ instead."
This makes it appear more like the results of a `semantic-find-' call.
This is like `semanticdb-strip-find-results', except the input list RESULTS
will be changed."
(apply #'nconc (mapcar #'cdr results)))
(mapcan #'cdr results))
(defun semanticdb-find-results-p (resultp)
"Non-nil if RESULTP is in the form of a semanticdb search result.

View file

@ -81,7 +81,7 @@ Optional argument MODE specifies the `major-mode' to test."
(if (null (cdr args))
args
`("(" ,@args
,@(apply #'nconc (mapcar (lambda (s) `("-o" "-name" ,s)) pat))
,@(mapcan (lambda (s) `("-o" "-name" ,s)) pat)
")"))))))
(defvar grepflags)

View file

@ -2762,7 +2762,7 @@ REGEXP should use constructs supported by your local `grep' command."
(lambda (s) (concat s "/"))
grep-find-ignored-directories)
grep-find-ignored-files))
(xrefs (cl-mapcan
(xrefs (mapcan
(lambda (file)
(xref-collect-matches regexp "*" file
(and (file-directory-p file)

View file

@ -173,7 +173,9 @@ the elements themselves.
(defun cl-mapcan (cl-func cl-seq &rest cl-rest)
"Like `cl-mapcar', but nconc's together the values returned by the function.
\n(fn FUNCTION SEQUENCE...)"
(apply 'nconc (apply 'cl-mapcar cl-func cl-seq cl-rest)))
(if cl-rest
(apply 'nconc (apply 'cl-mapcar cl-func cl-seq cl-rest))
(mapcan cl-func cl-seq)))
;;;###autoload
(defun cl-mapcon (cl-func cl-list &rest cl-rest)

View file

@ -154,7 +154,6 @@
every
some
mapcon
mapcan
mapl
maplist
map

View file

@ -826,8 +826,7 @@ Addresses without a name will say \"noname\"."
(defun gnus-registry-sort-addresses (&rest addresses)
"Return a normalized and sorted list of ADDRESSES."
(sort (apply 'nconc (mapcar 'gnus-registry-extract-addresses addresses))
'string-lessp))
(sort (mapcan 'gnus-registry-extract-addresses addresses) 'string-lessp))
(defun gnus-registry-simplify-subject (subject)
(if (stringp subject)

View file

@ -4749,7 +4749,7 @@ If LINE, insert the rebuilt thread starting on line LINE."
(defun gnus-articles-in-thread (thread)
"Return the list of articles in THREAD."
(cons (mail-header-number (car thread))
(apply 'nconc (mapcar 'gnus-articles-in-thread (cdr thread)))))
(mapcan 'gnus-articles-in-thread (cdr thread))))
(defun gnus-remove-thread (id &optional dont-remove)
"Remove the thread that has ID in it."

View file

@ -1599,7 +1599,7 @@ sequence, this is like `mapcar'. With several, it is like the Common Lisp
heads))
nil))
(setq ,result-tail (cdr ,result-tail)
,@(apply 'nconc (mapcar (lambda (h) (list h (list 'cdr h))) heads))))
,@(mapcan (lambda (h) (list h (list 'cdr h))) heads)))
(cdr ,result)))
`(mapcar ,function ,seq1)))

View file

@ -1372,7 +1372,7 @@ See the documentation for the variable `nnmail-split-fancy' for details."
;; Builtin & operation.
((eq (car split) '&)
(apply 'nconc (mapcar 'nnmail-split-it (cdr split))))
(mapcan 'nnmail-split-it (cdr split)))
;; Builtin | operation.
((eq (car split) '|)

View file

@ -1638,8 +1638,8 @@ and selects that window."
(let ((others-list
(mouse-buffer-menu-alist
;; we don't need split-by-major-mode any more,
;; so we can ditch it with nconc.
(apply 'nconc (mapcar 'cddr split-by-major-mode)))))
;; so we can ditch it with nconc (mapcan).
(mapcan 'cddr split-by-major-mode))))
(and others-list
(setq subdivided-menus
(cons (cons "Others" others-list)

View file

@ -402,8 +402,7 @@ Return non-nil if it is necessary to update the local UIDL file."
(push uidl new))
(decf i)))
(pop3-uidl
(setq new (apply 'nconc (mapcar (lambda (elt) (list elt ctime))
pop3-uidl)))))
(setq new (mapcan (lambda (elt) (list elt ctime)) pop3-uidl))))
(when new (setq mod t))
;; List expirable messages and delete them from the data to be saved.
(setq ctime (when (numberp pop3-leave-mail-on-server)

View file

@ -1947,10 +1947,10 @@ the source code display in sync with the debugging session.")
PATH gives the directories in which to search for files with
extension EXTN. Normally EXTN is given as the regular expression
\"\\.java$\" ."
(apply 'nconc (mapcar (lambda (d)
(when (file-directory-p d)
(directory-files d t extn nil)))
path)))
(mapcan (lambda (d)
(when (file-directory-p d)
(directory-files d t extn nil)))
path))
;; Move point past whitespace.
(defun gud-jdb-skip-whitespace ()

View file

@ -1114,8 +1114,8 @@ preprocessing token"
result)))
(defun hif-delimit (lis atom)
(nconc (cl-mapcan (lambda (l) (list l atom))
(butlast lis))
(nconc (mapcan (lambda (l) (list l atom))
(butlast lis))
(last lis)))
;; Perform token replacement:

View file

@ -414,9 +414,8 @@
(substring arg 0 (match-end 1))
arg))))
(require 'cl-lib)
(eval-when-compile ; to avoid compiler warnings
(require 'cl-lib)
(require 'dired)
(require 'apropos))
@ -434,7 +433,7 @@ As a special case, if PATHS is nil then replace it by calling
(mapcar 'woman-Cyg-to-Win (woman-parse-man.conf)))
((string-match-p ";" paths)
;; Assume DOS-style path-list...
(cl-mapcan ; splice list into list
(mapcan ; splice list into list
(lambda (x)
(if x
(list x)
@ -445,14 +444,14 @@ As a special case, if PATHS is nil then replace it by calling
(list paths))
(t
;; Assume UNIX/Cygwin-style path-list...
(cl-mapcan ; splice list into list
(mapcan ; splice list into list
(lambda (x)
(mapcar 'woman-Cyg-to-Win
(if x (list x) (woman-parse-man.conf))))
(let ((path-separator ":"))
(parse-colon-path paths)))))
;; Assume host-default-style path-list...
(cl-mapcan ; splice list into list
(mapcan ; splice list into list
(lambda (x) (if x (list x) (woman-parse-man.conf)))
(parse-colon-path (or paths "")))))

View file

@ -2654,6 +2654,30 @@ SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
return sequence;
}
DEFUN ("mapcan", Fmapcan, Smapcan, 2, 2, 0,
doc: /* Apply FUNCTION to each element of SEQUENCE, and concatenate
the results by altering them (using `nconc').
SEQUENCE may be a list, a vector, a bool-vector, or a string. */)
(Lisp_Object function, Lisp_Object sequence)
{
register EMACS_INT leni;
register Lisp_Object *args;
Lisp_Object ret;
USE_SAFE_ALLOCA;
if (CHAR_TABLE_P (sequence))
wrong_type_argument (Qlistp, sequence);
leni = XFASTINT (Flength (sequence));
SAFE_ALLOCA_LISP (args, leni);
mapcar1 (leni, args, function, sequence);
ret = Fnconc (leni, args);
SAFE_FREE ();
return ret;
}
/* This is how C code calls `yes-or-no-p' and allows the user
to redefine it. */
@ -5203,6 +5227,7 @@ this variable. */);
defsubr (&Snconc);
defsubr (&Smapcar);
defsubr (&Smapc);
defsubr (&Smapcan);
defsubr (&Smapconcat);
defsubr (&Syes_or_no_p);
defsubr (&Sload_average);