summaryrefslogtreecommitdiff
path: root/src/fns.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2022-09-14 18:46:40 +0200
committerMattias EngdegÄrd <mattiase@acm.org>2022-09-15 09:40:08 +0200
commitf941cc76df7476a055350b3b1b7e9e61d1ddb246 (patch)
treeb1d38295911eaa0eeb189e2e0ed44ca65f2d1587 /src/fns.c
parent429e61b130232e69531f7d44b2bc610d43c8217d (diff)
downloademacs-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.c28
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)