summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoão Távora <joaotavora@gmail.com>2026-05-24 03:26:19 +0100
committerJoão Távora <joaotavora@gmail.com>2026-05-24 04:23:51 +0100
commit7892ae5eaf4c22a3209a8c44c6267004653c5691 (patch)
tree4740ec244fba688d5b8f2bc3729f28e49eb80a35 /src
parent12eec781ed69c4fc7611e8c9a1953ad33da98a0c (diff)
Fix pathological slowness in flex completion
The 'completion-regexp-list' optimization in completion--flex-all-completions-1, a cheap pre-filter via a trivial regexp, performs very poorly for longer patterns and strings, so drop it. That alone recovers fairly decent performance for the flex completion when compared to the 'hotfuzz' point of reference. We then recover the cheap rejection with an O(N+M) pre-check in the Fcompletion__flex_cost_gotoh C scorer. This kicks in the common case (completion-ignore-case is nil) and pays off especially when the table is already a list and 'all-completions' needn't cons. See: https://lists.gnu.org/archive/html/emacs-devel/2026-04/msg01081.html https://lists.gnu.org/archive/html/emacs-devel/2026-05/msg00519.html * lisp/minibuffer.el (completion--flex-all-completions-1): Remove regexp pre-filter. * src/minibuf.c (Fcompletion__flex_cost_gotoh): Add subsequence pre-check.
Diffstat (limited to 'src')
-rw-r--r--src/minibuf.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/src/minibuf.c b/src/minibuf.c
index c716ac0d811..745a71a63fc 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -2364,6 +2364,22 @@ STR the i-th character of PAT matched. */)
if (patlen == 0 || strlen == 0 || size > FLEX_MAX_MATRIX_SIZE)
return Qnil;
+ /* Also bail if PAT is not a subsequence of STR so bail "cheaply"
+ before the O(N*M) DP algorithm. Walking both strings
+ byte-by-byte for this purpose (and only for case-sensitive common
+ case) should be valid even for multibyte strings. */
+ if (!completion_ignore_case)
+ {
+ const unsigned char *p = SDATA (pat);
+ const unsigned char *s = SDATA (str);
+ int pi = 0;
+ for (int si = 0; si < strlen && pi < patlen; si++)
+ if (s[si] == p[pi])
+ pi++;
+ if (pi < patlen)
+ return Qnil;
+ }
+
/* Initialize M and D with positive infinity... */
for (int j = 0; j < size; j++)
M[j] = D[j] = pos_inf;