diff options
author | Mattias EngdegÄrd <mattiase@acm.org> | 2022-09-14 18:46:40 +0200 |
---|---|---|
committer | Mattias EngdegÄrd <mattiase@acm.org> | 2022-09-15 09:40:08 +0200 |
commit | f941cc76df7476a055350b3b1b7e9e61d1ddb246 (patch) | |
tree | b1d38295911eaa0eeb189e2e0ed44ca65f2d1587 /src/fns.c | |
parent | 429e61b130232e69531f7d44b2bc610d43c8217d (diff) | |
download | emacs-f941cc76df7476a055350b3b1b7e9e61d1ddb246.tar.gz |
mapconcat fast path with `identity` function argument
This makes (mapconcat #'identity SEQ) slightly faster than
(apply #'concat SEQ), which used to be much faster.
Notably, `string-join` benefits from this change as it uses mapconcat.
* src/fns.c (Fmapconcat): Speed up execution when the function
argument is `identity`.
Diffstat (limited to 'src/fns.c')
-rw-r--r-- | src/fns.c | 28 |
1 files changed, 25 insertions, 3 deletions
diff --git a/src/fns.c b/src/fns.c index 2f4808be3d0..9dd10fe4438 100644 --- a/src/fns.c +++ b/src/fns.c @@ -2930,15 +2930,37 @@ FUNCTION must be a function of one argument, and must return a value return empty_unibyte_string; Lisp_Object *args; SAFE_ALLOCA_LISP (args, args_alloc); + if (EQ (function, Qidentity)) + { + /* Fast path when no function call is necessary. */ + if (CONSP (sequence)) + { + Lisp_Object src = sequence; + Lisp_Object *dst = args; + do + { + *dst++ = XCAR (src); + src = XCDR (src); + } + while (!NILP (src)); + goto concat; + } + else if (VECTORP (sequence)) + { + memcpy (args, XVECTOR (sequence)->contents, leni * sizeof *args); + goto concat; + } + } ptrdiff_t nmapped = mapcar1 (leni, args, function, sequence); - ptrdiff_t nargs = 2 * nmapped - 1; eassert (nmapped == leni); + concat: ; + ptrdiff_t nargs = args_alloc; if (NILP (separator) || (STRINGP (separator) && SCHARS (separator) == 0)) - nargs = nmapped; + nargs = leni; else { - for (ptrdiff_t i = nmapped - 1; i > 0; i--) + for (ptrdiff_t i = leni - 1; i > 0; i--) args[i + i] = args[i]; for (ptrdiff_t i = 1; i < nargs; i += 2) |