Subject: bug#67536: 29.1; Calc mode's math-read-preprocess-string conses unnecessarily

From: Raffael Stocker <[email-masked]>
Date: Fri, 01 Dec 2023 22:10:22 +0100

Eli Zaretskii <[email-masked]> writes:

>> I use cl-flet and (eval-when-compile (require 'cl-lib)).  I hope that is
>> ok.
>
> I'd prefer a simple internal function, or a lambda.

I went with the lambda, it is the more concise choice.

>> +      (buffer-string))))
>
> I think buffer-substring-no-properties would be better than
> buffer-string, as we don't need to copy any text properties, right?

Yes, indeed.  I fixed that too.

Regards,
Raffael

>From 68ae1e20ae5eb66cc4899a1e442dae3bb6a054ad Mon Sep 17 00:00:00 2001
From: Raffael Stocker <[email-masked]>
Date: Fri, 1 Dec 2023 22:08:24 +0100
Subject: [PATCH] * lisp/calc/calc-aent.el (math-read-preprocess-string): cons
 less (bug#67536)

Use a temp buffer instead of working on a string.  This function is
called by calc-eval, which in turn is called repeatedly when
re-calculating org-mode tables.  This function is one of the main
bottlenecks there.
---
 lisp/calc/calc-aent.el | 23 ++++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

diff --git a/lisp/calc/calc-aent.el b/lisp/calc/calc-aent.el
index 66ede3295ae..b79765fbc1f 100644
--- a/lisp/calc/calc-aent.el
+++ b/lisp/calc/calc-aent.el
@@ -550,19 +550,16 @@ math-read-subscripts
 ;;;###autoload
 (defun math-read-preprocess-string (str)
   "Replace some substrings of STR by Calc equivalents."
-  (setq str
-        (replace-regexp-in-string (concat "[" math-read-superscripts "]+")
-                                  "^(\\&)" str))
-  (setq str
-        (replace-regexp-in-string (concat "[" math-read-subscripts "]+")
-                                  "_(\\&)" str))
-  (let ((rep-list math-read-replacement-list))
-    (while rep-list
-      (setq str
-            (replace-regexp-in-string (nth 0 (car rep-list))
-                                      (nth 1 (car rep-list)) str))
-      (setq rep-list (cdr rep-list))))
-  str)
+  (with-temp-buffer
+    (insert str)
+    (mapc (lambda (rep-pair)
+            (goto-char 0)
+            (while (re-search-forward (car rep-pair) nil t)
+              (replace-match (cadr rep-pair))))
+          `((,(concat "[" math-read-superscripts "]+") "^(\\&)")
+            (,(concat "[" math-read-subscripts "]+") "_(\\&)")
+            ,@math-read-replacement-list))
+    (buffer-substring-no-properties (point-min) (point-max))))
 
 ;; The next few variables are local to math-read-exprs (and math-read-expr
 ;; in calc-ext.el), but are set in functions they call.
-- 
2.43.0