all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* bug#68863: Add support for using setf with seq-subseq
@ 2024-02-01  3:31 Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-04 18:33 ` bug#68863: [PATCH] " Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
  2024-02-08 11:39 ` bug#68863: " Eli Zaretskii
  0 siblings, 2 replies; 13+ messages in thread
From: Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2024-02-01  3:31 UTC (permalink / raw)
  To: 68863

[-- Attachment #1: Type: text/plain, Size: 881 bytes --]

Hello,

This patch adds support for using `seq-subseq` with `setf`, as in

     ;; => [0 1 2 10 11]
     (let ((seq (vector 0 1 2 3 4)))
       (setf (seq-subseq seq -2) (list 10 11 12 13 14))
       seq)

The patch adds a generic version which uses the existing `setf` support 
of `seq-elt` and a specialized version for modifying lists.  Both 
versions use `seq-do` to map a function over the values that should 
replace the values in the modified sequence.

To avoid modifying more values than specified, that modifying function 
uses a `when` condition. I'm not sure of a good way to stop `seq-do` 
early when we know that it can stop calling the modifying function. 
Normally, I would use `cl-block` and `cl-return`. Is it OK to use those 
features in `seq.el`? If not, is it worth adding something like a 
`seq-map-while` or a `seq-do-while`?

Thank you.

[-- Attachment #2: 0001-Add-setf-support-for-seq-subseq.patch --]
[-- Type: text/x-patch, Size: 5338 bytes --]

From 0a5fac443cdcbeb9312d7ee68bafdd22e0905828 Mon Sep 17 00:00:00 2001
From: Earl Hyatt <okamsn@protonmail.com>
Date: Sun, 28 Jan 2024 22:48:13 -0500
Subject: [PATCH] Add setf support for seq-subseq

* lisp/emacs-lisp/seq.el (seq-subseq): Add a generic version of
calling setf on seq-subseq and add a specialized version for when the
modified sequence is a list.
* test/lisp/emacs-lisp/seq-tests.el (test-setf-seq-subseq)
(test-setf-seq-subseq-combinations): Add tests for the feature.
---
 lisp/emacs-lisp/seq.el            | 43 +++++++++++++++++
 test/lisp/emacs-lisp/seq-tests.el | 76 +++++++++++++++++++++++++++++++
 2 files changed, 119 insertions(+)

diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 4c6553972c2..fd971806d87 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -193,6 +193,49 @@ seq-subseq
         (copy-sequence sequence))))
    (t (error "Unsupported sequence: %s" sequence))))
 
+(cl-defgeneric (setf seq-subseq) (store sequence start &optional end)
+  "Modify the elements of SEQUENCE from START to END to be those of STORE.
+
+SEQUENCE is neither lengthened nor shortened."
+  (let* ((len (seq-length sequence))
+         (idx (if (< start 0)
+                  (+ start len)
+                start))
+         (end (cond
+               ((null end) len)
+               ((< end 0)
+                (+ end len))
+               (t (min len end)))))
+    (when (< idx end)
+      (seq-do (lambda (v)
+                (when (< idx end)
+                  (setf (seq-elt sequence idx) v
+                        idx (1+ idx))))
+              store)))
+  store)
+
+(cl-defmethod (setf seq-subseq) (store (sequence list) start &optional end)
+  "Modify the elements of SEQUENCE from START to END to be those of STORE.
+
+SEQUENCE is neither lengthened nor shortened."
+  (let* ((len (seq-length sequence))
+         (idx (if (< start 0)
+                  (+ start len)
+                start))
+         (end (cond
+               ((null end) len)
+               ((< end 0)  (+ end len))
+               (t          (min len end)))))
+    (when (< idx end)
+      (seq-do (let ((replaced (nthcdr idx sequence)))
+                (lambda (v)
+                  (when (< idx end)
+                    (setf (car replaced) v
+                          replaced (cdr replaced)
+                          idx (1+ idx)))))
+              store)))
+  store)
+
 \f
 (cl-defgeneric seq-map (function sequence)
   "Return the result of applying FUNCTION to each element of SEQUENCE."
diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el
index c06ceb00bdb..6b8789688d3 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -312,6 +312,82 @@ test-seq-subseq
                   (:success
                    (should (equal (seq-subseq list start end) res))))))))))))
 
+(cl-defmacro test-setf-seq-subseq-combinations (&key result range init-vals
+                                                     sub-vals)
+  "Produce substitutions tests for `seq-subseq' using `setf'.
+
+- INIT-VALS is a list holding the initial elements.
+- RESULT is what the final value should be after substitution.
+- SUB-VALS is a list holding the elements to be substituted in.
+- RANGE is a list of the `start' and `end' arguments of `seq-subseq'."
+  (let ((tests))
+    (dolist (type1 '(list vector string))
+      (dolist (type2 '(list vector string))
+        (push  `(should (equal (,type1 ,@result)
+                               (let ((seq (,type1 ,@init-vals)))
+                                 (setf (seq-subseq seq ,@range)
+                                       (,type2 ,@sub-vals))
+                                 seq)))
+               tests)))
+    `(progn ,@tests)))
+
+(ert-deftest test-setf-seq-subseq ()
+  "Test using `seq-subseq' with `setf'.
+Any combination of sequences should work."
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2)
+   :sub-vals (10 11 12)
+   :range (0)
+   :result (10 11 12))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1)
+   :sub-vals (10 11 12)
+   :range (0)
+   :result (10 11))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1)
+   :sub-vals (10 11 12)
+   :range (0 100)
+   :result (10 11))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4)
+   :sub-vals (12 13 14 15)
+   :range (2 100)
+   :result (0 1 12 13 14))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4)
+   :sub-vals (12 13 14 15)
+   :range (2 3)
+   :result (0 1 12 3 4))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4)
+   :sub-vals (12 13 14 15)
+   :range (2 2)
+   :result (0 1 2 3 4))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4 5 6 7 8 9)
+   :sub-vals (10 11 12 13 14)
+   :range (-2)
+   :result (0 1 2 10 11))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4 5 6 7 8 9)
+   :sub-vals (10 11 12 13 14)
+   :range (-6 -3)
+   :result (0 1 2 3 10 11 12 7 8 9))
+
+  (test-setf-seq-subseq-combinations
+   :init-vals (0 1 2 3 4 5 6 7 8 9)
+   :sub-vals (10 11 12 13 14)
+   :range (-6 -10)
+   :result (0 1 2 3 4 5 6 7 8 9)))
+
 (ert-deftest test-seq-concatenate ()
   (with-test-sequences (seq '(2 4 6))
     (should (equal (seq-concatenate 'string seq [8]) (string 2 4 6 8)))
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-05-14 15:52 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-02-01  3:31 bug#68863: Add support for using setf with seq-subseq Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-04 18:33 ` bug#68863: [PATCH] " Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-08 11:39 ` bug#68863: " Eli Zaretskii
2024-02-08 14:25   ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-09  3:54     ` Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-02-14  2:50       ` Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-04-18  2:54         ` Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-07  1:45           ` Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-08 21:01             ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-09 12:16             ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-09 13:55               ` Stefan Monnier via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-14 12:47               ` Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors
2024-05-14 15:52                 ` Michael Heerdegen via Bug reports for GNU Emacs, the Swiss army knife of text editors

Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.