]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid resizing mutation in subst-char-in-string
authorMattias EngdegÄrd <mattiase@acm.org>
Fri, 10 May 2024 08:35:39 +0000 (10:35 +0200)
committerEshel Yaron <me@eshelyaron.com>
Sun, 12 May 2024 15:48:25 +0000 (17:48 +0200)
* lisp/subr.el (subst-char-in-string):
Use string-replace to avoid resizing mutation and O(n^2) time.

(cherry picked from commit 184d6e8c02345583264b053bb59ae031bb1c5a00)

lisp/subr.el

index de5d5c7291155b6b0889706a2c2b451191283630..9abcecd7c0470bc14065ad13a26c995651dbaee8 100644 (file)
@@ -5694,13 +5694,19 @@ The SEPARATOR regexp defaults to \"\\s-+\"."
 (defun subst-char-in-string (fromchar tochar string &optional inplace)
   "Replace FROMCHAR with TOCHAR in STRING each time it occurs.
 Unless optional argument INPLACE is non-nil, return a new string."
-  (let ((i (length string))
-       (newstr (if inplace string (copy-sequence string))))
-    (while (> i 0)
-      (setq i (1- i))
-      (if (eq (aref newstr i) fromchar)
-         (aset newstr i tochar)))
-    newstr))
+  (if (and (not inplace)
+           (if (multibyte-string-p string)
+               (> (max fromchar tochar) 127)
+             (> tochar 255)))
+      ;; Avoid quadratic behaviour from resizing replacement.
+      (string-replace (string fromchar) (string tochar) string)
+    (let ((i (length string))
+         (newstr (if inplace string (copy-sequence string))))
+      (while (> i 0)
+        (setq i (1- i))
+        (if (eq (aref newstr i) fromchar)
+           (aset newstr i tochar)))
+      newstr)))
 
 (defun string-replace (from-string to-string in-string)
   "Replace FROM-STRING with TO-STRING in IN-STRING each time it occurs."