From: Okamsn via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org>
To: 68863@debbugs.gnu.org
Subject: bug#68863: Add support for using setf with seq-subseq
Date: Thu, 01 Feb 2024 03:31:10 +0000 [thread overview]
Message-ID: <050ba625-2372-425f-85c6-988e2ef4cf14@protonmail.com> (raw)
[-- 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
next reply other threads:[~2024-02-01 3:31 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-01 3:31 Okamsn via Bug reports for GNU Emacs, the Swiss army knife of text editors [this message]
2024-02-04 18:33 ` bug#68863: [PATCH] Add support for using setf with seq-subseq 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=050ba625-2372-425f-85c6-988e2ef4cf14@protonmail.com \
--to=bug-gnu-emacs@gnu.org \
--cc=68863@debbugs.gnu.org \
--cc=okamsn@protonmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.