]> git.eshelyaron.com Git - emacs.git/commitdiff
Don't mutate strings in cl-substitute
authorMattias EngdegÄrd <mattiase@acm.org>
Wed, 8 May 2024 10:13:48 +0000 (12:13 +0200)
committerEshel Yaron <me@eshelyaron.com>
Wed, 8 May 2024 16:53:14 +0000 (18:53 +0200)
This fixes cl-substitute, cl-substitute-if, cl-substitute-if-not,
cl-nsubstitute, cl-nsubstitute-if and cl-nsubstitute-if-not,
when called with a string sequence argument.

* lisp/emacs-lisp/cl-seq.el (cl-nsubstitute):
Avoid running in O(n^2) time and make future-safe.

(cherry picked from commit de5a89254cb8645143e9f4e51a1727a7237109e8)

lisp/emacs-lisp/cl-seq.el

index e46955fd968725ed94f3de0ada73c35552710c44..42f54603899c57c4556fc629257e10280e90e563 100644 (file)
@@ -452,14 +452,15 @@ to avoid corrupting the original SEQ.
   (apply 'cl-substitute cl-new nil cl-list :if-not cl-pred cl-keys))
 
 ;;;###autoload
-(defun cl-nsubstitute (cl-new cl-old cl-seq &rest cl-keys)
+(defun cl-nsubstitute (cl-new cl-old seq &rest cl-keys)
   "Substitute NEW for OLD in SEQ.
 This is a destructive function; it reuses the storage of SEQ whenever possible.
 \nKeywords supported:  :test :test-not :key :count :start :end :from-end
 \n(fn NEW OLD SEQ [KEYWORD VALUE]...)"
   (cl--parsing-keywords (:test :test-not :key :if :if-not :count
                        (:start 0) :end :from-end) ()
-    (let ((len (length cl-seq)))
+    (let* ((cl-seq (if (stringp seq) (string-to-vector seq) seq))
+           (len (length cl-seq)))
       (or (eq cl-old cl-new) (<= (or cl-count (setq cl-count len)) 0)
          (if (and (listp cl-seq) (or (not cl-from-end) (> cl-count (/ len 2))))
            (let ((cl-p (nthcdr cl-start cl-seq)))
@@ -483,8 +484,8 @@ This is a destructive function; it reuses the storage of SEQ whenever possible.
                  (progn
                    (aset cl-seq cl-start cl-new)
                    (setq cl-count (1- cl-count))))
-             (setq cl-start (1+ cl-start)))))))
-    cl-seq))
+             (setq cl-start (1+ cl-start))))))
+      (if (stringp seq) (concat cl-seq) cl-seq))))
 
 ;;;###autoload
 (defun cl-nsubstitute-if (cl-new cl-pred cl-list &rest cl-keys)