seq-2.20/0000755000175200017530000000000013102713476010662 5ustar elpaelpaseq-2.20/tests/0000755000175200017530000000000013025062140012011 5ustar elpaelpaseq-2.20/tests/seq-tests.el0000644000175200017530000003342013025062140014265 0ustar elpaelpa;;; seq-tests.el --- Tests for sequences.el
;; Copyright (C) 2014-2015 Free Software Foundation, Inc.
;; Author: Nicolas Petton
;; Maintainer: emacs-devel@gnu.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see .
;;; Commentary:
;; Tests for seq.el
;;; Code:
(require 'ert)
(require 'seq)
(defmacro with-test-sequences (spec &rest body)
"Successively bind VAR to a list, vector, and string built from SEQ.
Evaluate BODY for each created sequence.
\(fn (var seq) body)"
(declare (indent 1) (debug ((symbolp form) body)))
(let ((initial-seq (make-symbol "initial-seq")))
`(let ((,initial-seq ,(cadr spec)))
,@(mapcar (lambda (s)
`(let ((,(car spec) (apply (function ,s) ,initial-seq)))
,@body))
'(list vector string)))))
(defun same-contents-p (seq1 seq2)
"Return t if SEQ1 and SEQ2 have the same contents, nil otherwise."
(equal (append seq1 '()) (append seq2 '())))
(defun test-sequences-evenp (integer)
"Return t if INTEGER is even."
(eq (logand integer 1) 0))
(defun test-sequences-oddp (integer)
"Return t if INTEGER is odd."
(not (test-sequences-evenp integer)))
(ert-deftest test-seq-drop ()
(with-test-sequences (seq '(1 2 3 4))
(should (equal (seq-drop seq 0) seq))
(should (equal (seq-drop seq 1) (seq-subseq seq 1)))
(should (equal (seq-drop seq 2) (seq-subseq seq 2)))
(should (seq-empty-p (seq-drop seq 4)))
(should (seq-empty-p (seq-drop seq 10))))
(with-test-sequences (seq '())
(should (seq-empty-p (seq-drop seq 0)))
(should (seq-empty-p (seq-drop seq 1)))))
(ert-deftest test-seq-take ()
(with-test-sequences (seq '(2 3 4 5))
(should (seq-empty-p (seq-take seq 0)))
(should (= (seq-length (seq-take seq 1)) 1))
(should (= (seq-elt (seq-take seq 1) 0) 2))
(should (same-contents-p (seq-take seq 3) '(2 3 4)))
(should (equal (seq-take seq 10) seq))))
(ert-deftest test-seq-drop-while ()
(with-test-sequences (seq '(1 3 2 4))
(should (equal (seq-drop-while #'test-sequences-oddp seq)
(seq-drop seq 2)))
(should (equal (seq-drop-while #'test-sequences-evenp seq)
seq))
(should (seq-empty-p (seq-drop-while #'numberp seq))))
(with-test-sequences (seq '())
(should (seq-empty-p (seq-drop-while #'test-sequences-oddp seq)))))
(ert-deftest test-seq-take-while ()
(with-test-sequences (seq '(1 3 2 4))
(should (equal (seq-take-while #'test-sequences-oddp seq)
(seq-take seq 2)))
(should (seq-empty-p (seq-take-while #'test-sequences-evenp seq)))
(should (equal (seq-take-while #'numberp seq) seq)))
(with-test-sequences (seq '())
(should (seq-empty-p (seq-take-while #'test-sequences-oddp seq)))))
(ert-deftest test-seq-map-indexed ()
(should (equal (seq-map-indexed (lambda (elt i)
(list elt i))
nil)
nil))
(should (equal (seq-map-indexed (lambda (elt i)
(list elt i))
'(a b c d))
'((a 0) (b 1) (c 2) (d 3)))))
(ert-deftest test-seq-filter ()
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-filter #'test-sequences-evenp seq) '(6 8 10)))
(should (equal (seq-filter #'test-sequences-oddp seq) '(7 9)))
(should (equal (seq-filter (lambda (elt) nil) seq) '())))
(with-test-sequences (seq '())
(should (equal (seq-filter #'test-sequences-evenp seq) '()))))
(ert-deftest test-seq-remove ()
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-remove #'test-sequences-evenp seq) '(7 9)))
(should (equal (seq-remove #'test-sequences-oddp seq) '(6 8 10)))
(should (same-contents-p (seq-remove (lambda (elt) nil) seq) seq)))
(with-test-sequences (seq '())
(should (equal (seq-remove #'test-sequences-evenp seq) '()))))
(ert-deftest test-seq-count ()
(with-test-sequences (seq '(6 7 8 9 10))
(should (equal (seq-count #'test-sequences-evenp seq) 3))
(should (equal (seq-count #'test-sequences-oddp seq) 2))
(should (equal (seq-count (lambda (elt) nil) seq) 0)))
(with-test-sequences (seq '())
(should (equal (seq-count #'test-sequences-evenp seq) 0))))
(ert-deftest test-seq-reduce ()
(with-test-sequences (seq '(1 2 3 4))
(should (= (seq-reduce #'+ seq 0) 10))
(should (= (seq-reduce #'+ seq 5) 15)))
(with-test-sequences (seq '())
(should (eq (seq-reduce #'+ seq 0) 0))
(should (eq (seq-reduce #'+ seq 7) 7))))
(ert-deftest test-seq-some ()
(with-test-sequences (seq '(4 3 2 1))
(should (seq-some #'test-sequences-evenp seq))
(should (seq-some #'test-sequences-oddp seq))
(should-not (seq-some (lambda (elt) (> elt 10)) seq)))
(with-test-sequences (seq '())
(should-not (seq-some #'test-sequences-oddp seq)))
(should (seq-some #'null '(1 nil 2))))
(ert-deftest test-seq-find ()
(with-test-sequences (seq '(4 3 2 1))
(should (= 4 (seq-find #'test-sequences-evenp seq)))
(should (= 3 (seq-find #'test-sequences-oddp seq)))
(should-not (seq-find (lambda (elt) (> elt 10)) seq)))
(should-not (seq-find #'null '(1 nil 2)))
(should-not (seq-find #'null '(1 nil 2) t))
(should-not (seq-find #'null '(1 2 3)))
(should (seq-find #'null '(1 2 3) 'sentinel)))
(ert-deftest test-seq-contains ()
(with-test-sequences (seq '(3 4 5 6))
(should (seq-contains seq 3))
(should-not (seq-contains seq 7)))
(with-test-sequences (seq '())
(should-not (seq-contains seq 3))
(should-not (seq-contains seq nil))))
(ert-deftest test-seq-every-p ()
(with-test-sequences (seq '(43 54 22 1))
(should (seq-every-p (lambda (elt) t) seq))
(should-not (seq-every-p #'test-sequences-oddp seq))
(should-not (seq-every-p #'test-sequences-evenp seq)))
(with-test-sequences (seq '(42 54 22 2))
(should (seq-every-p #'test-sequences-evenp seq))
(should-not (seq-every-p #'test-sequences-oddp seq)))
(with-test-sequences (seq '())
(should (seq-every-p #'identity seq))
(should (seq-every-p #'test-sequences-evenp seq))))
(ert-deftest test-seq-empty-p ()
(with-test-sequences (seq '(0))
(should-not (seq-empty-p seq)))
(with-test-sequences (seq '(0 1 2))
(should-not (seq-empty-p seq)))
(with-test-sequences (seq '())
(should (seq-empty-p seq))))
(ert-deftest test-seq-sort ()
(should (equal (seq-sort #'< "cbaf") "abcf"))
(should (equal (seq-sort #'< '(2 1 9 4)) '(1 2 4 9)))
(should (equal (seq-sort #'< [2 1 9 4]) [1 2 4 9]))
(should (equal (seq-sort #'< "") "")))
(ert-deftest test-seq-uniq ()
(with-test-sequences (seq '(2 4 6 8 6 4 3))
(should (equal (seq-uniq seq) '(2 4 6 8 3))))
(with-test-sequences (seq '(3 3 3 3 3))
(should (equal (seq-uniq seq) '(3))))
(with-test-sequences (seq '())
(should (equal (seq-uniq seq) '()))))
(ert-deftest test-seq-subseq ()
(with-test-sequences (seq '(2 3 4 5))
(should (equal (seq-subseq seq 0 4) seq))
(should (same-contents-p (seq-subseq seq 2 4) '(4 5)))
(should (same-contents-p (seq-subseq seq 1 3) '(3 4)))
(should (same-contents-p (seq-subseq seq 1 -1) '(3 4))))
(should (vectorp (seq-subseq [2 3 4 5] 2)))
(should (stringp (seq-subseq "foo" 2 3)))
(should (listp (seq-subseq '(2 3 4 4) 2 3)))
(should-error (seq-subseq '(1 2 3) 4))
(should-not (seq-subseq '(1 2 3) 3))
(should (seq-subseq '(1 2 3) -3))
(should-error (seq-subseq '(1 2 3) 1 4))
(should (seq-subseq '(1 2 3) 1 3)))
(ert-deftest test-seq-concatenate ()
(with-test-sequences (seq '(2 4 6))
(should (equal (seq-concatenate 'string seq [8]) (string 2 4 6 8)))
(should (equal (seq-concatenate 'list seq '(8 10)) '(2 4 6 8 10)))
(should (equal (seq-concatenate 'vector seq '(8 10)) [2 4 6 8 10]))
(should (equal (seq-concatenate 'vector nil '(8 10)) [8 10]))
(should (equal (seq-concatenate 'vector seq nil) [2 4 6]))))
(ert-deftest test-seq-mapcat ()
(should (equal (seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)))
'(1 2 3 4 5 6)))
(should (equal (seq-mapcat #'seq-reverse '[(3 2 1) (6 5 4)])
'(1 2 3 4 5 6)))
(should (equal (seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)) 'vector)
'[1 2 3 4 5 6])))
(ert-deftest test-seq-partition ()
(should (same-contents-p (seq-partition '(0 1 2 3 4 5 6 7) 3)
'((0 1 2) (3 4 5) (6 7))))
(should (same-contents-p (seq-partition '[0 1 2 3 4 5 6 7] 3)
'([0 1 2] [3 4 5] [6 7])))
(should (same-contents-p (seq-partition "Hello world" 2)
'("He" "ll" "o " "wo" "rl" "d")))
(should (equal (seq-partition '() 2) '()))
(should (equal (seq-partition '(1 2 3) -1) '())))
(ert-deftest test-seq-group-by ()
(with-test-sequences (seq '(1 2 3 4))
(should (equal (seq-group-by #'test-sequences-oddp seq)
'((t 1 3) (nil 2 4)))))
(should (equal (seq-group-by #'car '((a 1) (b 3) (c 4) (a 2)))
'((b (b 3)) (c (c 4)) (a (a 1) (a 2))))))
(ert-deftest test-seq-reverse ()
(with-test-sequences (seq '(1 2 3 4))
(should (same-contents-p (seq-reverse seq) '(4 3 2 1)))
(should (equal (type-of (seq-reverse seq))
(type-of seq)))))
(ert-deftest test-seq-into ()
(let* ((vector [1 2 3])
(list (seq-into vector 'list)))
(should (same-contents-p vector list))
(should (listp list)))
(let* ((list '(hello world))
(vector (seq-into list 'vector)))
(should (same-contents-p vector list))
(should (vectorp vector)))
(let* ((string "hello")
(list (seq-into string 'list)))
(should (same-contents-p string list))
(should (stringp string)))
(let* ((string "hello")
(vector (seq-into string 'vector)))
(should (same-contents-p string vector))
(should (stringp string)))
(let* ((list nil)
(vector (seq-into list 'vector)))
(should (same-contents-p list vector))
(should (vectorp vector))))
(ert-deftest test-seq-intersection ()
(let ((v1 [2 3 4 5])
(v2 [1 3 5 6 7]))
(should (same-contents-p (seq-intersection v1 v2)
'(3 5))))
(let ((l1 '(2 3 4 5))
(l2 '(1 3 5 6 7)))
(should (same-contents-p (seq-intersection l1 l2)
'(3 5))))
(let ((v1 [2 4 6])
(v2 [1 3 5]))
(should (seq-empty-p (seq-intersection v1 v2)))))
(ert-deftest test-seq-difference ()
(let ((v1 [2 3 4 5])
(v2 [1 3 5 6 7]))
(should (same-contents-p (seq-difference v1 v2)
'(2 4))))
(let ((l1 '(2 3 4 5))
(l2 '(1 3 5 6 7)))
(should (same-contents-p (seq-difference l1 l2)
'(2 4))))
(let ((v1 [2 4 6])
(v2 [2 4 6]))
(should (seq-empty-p (seq-difference v1 v2)))))
(ert-deftest test-seq-let ()
(with-test-sequences (seq '(1 2 3 4))
(seq-let (a b c d e) seq
(should (= a 1))
(should (= b 2))
(should (= c 3))
(should (= d 4))
(should (null e)))
(seq-let (a b &rest others) seq
(should (= a 1))
(should (= b 2))
(should (same-contents-p others (seq-drop seq 2)))))
(let ((seq '(1 (2 (3 (4))))))
(seq-let (_ (_ (_ (a)))) seq
(should (= a 4))))
(let (seq)
(seq-let (a b c) seq
(should (null a))
(should (null b))
(should (null c)))))
(ert-deftest test-seq-min-max ()
(with-test-sequences (seq '(4 5 3 2 0 4))
(should (= (seq-min seq) 0))
(should (= (seq-max seq) 5))))
(ert-deftest test-seq-position ()
(with-test-sequences (seq '(2 4 6))
(should (null (seq-position seq 1)))
(should (= (seq-position seq 4) 1)))
(let ((seq '(a b c)))
(should (null (seq-position seq 'd #'eq)))
(should (= (seq-position seq 'a #'eq) 0))
(should (null (seq-position seq (make-symbol "a") #'eq)))))
(ert-deftest test-seq-mapn ()
(should-error (seq-mapn #'identity))
(with-test-sequences (seq '(1 2 3 4 5 6 7))
(should (equal (append seq nil)
(seq-mapn #'identity seq)))
(should (equal (seq-mapn #'1+ seq)
(seq-map #'1+ seq)))
(with-test-sequences (seq-2 '(10 20 30 40 50))
(should (equal (seq-mapn #'+ seq seq-2)
'(11 22 33 44 55)))
(should (equal (seq-mapn #'+ seq seq-2 nil) nil)))))
(ert-deftest test-seq-sort-by ()
(let ((seq ["x" "xx" "xxx"]))
(should (equal (seq-sort-by #'seq-length #'> seq)
["xxx" "xx" "x"]))))
(ert-deftest test-seq-random-elt-take-all ()
(let ((seq '(a b c d e))
(elts '()))
(should (= 0 (length elts)))
(dotimes (_ 1000)
(let ((random-elt (seq-random-elt seq)))
(add-to-list 'elts
random-elt)))
(should (= 5 (length elts)))))
(ert-deftest test-seq-random-elt-signal-on-empty ()
(should-error (seq-random-elt nil))
(should-error (seq-random-elt []))
(should-error (seq-random-elt "")))
(ert-deftest test-seq-mapn-circular-lists ()
(let ((l1 '#1=(1 . #1#)))
(should (equal (seq-mapn #'+ '(3 4 5 7) l1)
'(4 5 6 8)))))
(ert-deftest test-seq-into-and-identity ()
(let ((lst '(1 2 3))
(vec [1 2 3])
(str "foo bar"))
(should (eq (seq-into lst 'list) lst))
(should (eq (seq-into vec 'vector) vec))
(should (eq (seq-into str 'string) str))))
(provide 'seq-tests)
;;; seq-tests.el ends here
seq-2.20/ChangeLog0000644000175200017530000001253713102713375012442 0ustar elpaelpa2017-05-04 Nicolas Petton
Update seq.el to 2.20
2016-12-16 Nicolas Petton
Backport the latest changes to seq.el from Emacs master
* packages/seq/seq-24.el:
* packages/seq/seq-25.el (seq-into): Do not convert the sequence if not
needed.
* packages/seq/tests/seq-tests.el: Add a regression test.
2016-12-15 Nicolas Petton
Backport seq-mapn fix from Emacs master
* packages/seq/seq-24.el (seq-mapn):
* packages/seq/seq-25.el (seq-mapn): Fix for circular lists.
* packages/seq/tests/seq-tests.el: Add a regression test.
2016-11-16 Nicolas Petton
Do not use map.el in seq-tests.el
* packages/seq/tests/seq-tests.el: Do not use map.el. map.el was
introduced in Emacs 25.1, but seq.el is also available in GNU ELPA for
Emacs 24.5.
2016-10-25 Nicolas Petton
Fix seq-random-elt docstring
* packages/seq/seq-24.el:
* packages/seq/seq-25.el (seq-random-elt): Fix the docstring.
2016-10-25 Nicolas Petton
Backport seq.el changes from Emacs master
* packages/seq/seq-24.el:
* packages/seq/seq-25.el (seq-random-elt): New function.
* packages/seq/seq.el: Bump version to 2.19.
* packages/seq/tests/seq-tests.el: Add tests for seq-random-elt.
2016-09-02 Clément Pit--Claudel
; Fix documentation of seq-subseq
2016-08-28 Nicolas Petton
* packages/seq/seq-24.el: Rename seq-p to seqp
2016-06-12 Nicolas Petton
Update seq.el to 2.16
* packages/seq/seq-24.el:
* packages/seq/seq-25.el: Better implementation of seq-drop for lists.
* packages/seq/seq.el: Bump version number.
2016-04-22 Stefan Monnier
* seq-24.el (seq-concatenate,seq-into,seq--make-bindings): Use _
rather than t as catch-all for pcase.
2016-03-31 Nicolas Petton
Update seq to version 2.15
* packages/seq/seq-25.el: Require cl-lib.
* packages/seq/seq.el: Bump version number.
2016-03-29 Nicolas Petton
Update seq.el to version 2.14
* packages/seq/seq.el: Bump version number.
* packages/seq/seq-24.el (seq-sort-by): New function.
* packages/seq/seq-25.el (seq-sort-by): New function.
* packages/seq/tests/seq-tests.el: Add a test for seq-sort-by.
2016-03-25 Nicolas Petton
* packages/seq/seq-25.el: Better declarations for seq--when-emacs-25-p
2016-03-25 Nicolas Petton
Split seq.el into separate files for different versions of Emacs
All functions in seq-25.el are wrapped in a `seq--when-emacs-25-p' to
make sure that the byte compiler won't emit warnings or errors when the
file is byte compiled in Emacs < 25.
* packages/seq/seq-24.el:
* packages/seq/seq-25.el: New files.
* packages/seq/seq.el: Load seq-VERSION.el based on the version of
Emacs.
* packages/seq/test/seq.el-test.el: Backport a test from seq.el in Emacs
master.
2015-11-30 Stefan Monnier
* packages/seq: Don't define it as a :core package
Revert the removal of packages/seq/seq.el since it's different from the
one in lisp/emacs-lisp.
* .gitignore: Remove packages/seq.
* externals-list: Remove "seq" entry.
2015-11-29 Stefan Monnier
* externals-list: Add seq and python as :core packages
* .gitignore: Add packages/{seq,python}.
* packages/seq: Remove.
2015-10-20 Nicolas Petton
Update seq.el to version 1.11
* packages/seq/seq.el:
* packages/seq/tests/seq-tests.el: Update.
2015-09-18 Nicolas Petton
Update seq.el to version 1.9
* packages/seq/seq.el: Update to version 1.9.
* packages/seq/tests/seq-tests.el: Update to version 1.9.
2015-07-09 Nicolas Petton
Update seq.el to version 1.8
* packages/seq/seq.el: Update to version 1.8.
* packages/seq/tests/seq-tests.el: Update to version 1.8.
2015-05-15 Nicolas Petton
Update seq.el to version 1.7
* packages/seq/seq.el: Update to version 1.7.
* packages/seq/tests/seq-tests.el: Update to version 1.7.
2015-04-27 Nicolas Petton
* packages/seq/seq.el: Update seq.el to version 1.5.
2015-04-15 Nicolas Petton
seq.el update
* packages/seq/seq.el: Update seq.el to version 1.4
* packages/seq/tests/seq-tests.el: Update seq.el to version 1.4
2015-03-25 Nicolas Petton
Rephrases a comment in seq.el about the order of the arguments
* packages/seq/seq.el: Better comment about the order of the arguments
2015-03-09 Nicolas Petton
Update seq.el to version 1.3
* packages/seq/seq.el: update to version 1.3
* packages/seq/tests/seq-tests.el: update to version 1.3
2015-02-11 Nicolas Petton
Update seq.el to version 1.2
* package/seq/seq.el: Update to version 1.2
* packages/seq/tests/seq-tests.el: Update to version 1.2
2015-02-09 Nicolas Petton
Update seq.el to version 1.1.1
* package/seq/seq.el: Update to version 1.1.1
* packages/seq/tests/seq-tests.el: Update to version 1.1.1
2015-02-06 Nicolas Petton
Update seq.el to version 1.1
* packages/seq/seq.el: Update to version 1.1
* packages/seq/tests/seq-tests.el: Update to version 1.1
2015-01-14 Nicolas Petton
packages/seq: New package
seq-2.20/seq-24.el0000644000175200017530000004410213102713323012207 0ustar elpaelpa;;; seq-24.el --- seq.el implementation for Emacs 24.x -*- lexical-binding: t -*-
;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
;; Author: Nicolas Petton
;; Keywords: sequences
;; Maintainer: emacs-devel@gnu.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see .
;;; Commentary:
;; Sequence-manipulation functions that complement basic functions
;; provided by subr.el.
;;
;; All functions are prefixed with "seq-".
;;
;; All provided functions work on lists, strings and vectors.
;;
;; Functions taking a predicate or iterating over a sequence using a
;; function as argument take the function as their first argument and
;; the sequence as their second argument. All other functions take
;; the sequence as their first argument.
;;; Code:
(defmacro seq-doseq (spec &rest body)
"Loop over a sequence.
Similar to `dolist' but can be applied to lists, strings, and vectors.
Evaluate BODY with VAR bound to each element of SEQ, in turn.
\(fn (VAR SEQ) BODY...)"
(declare (indent 1) (debug ((symbolp form &optional form) body)))
(let ((length (make-symbol "length"))
(seq (make-symbol "seq"))
(index (make-symbol "index")))
`(let* ((,seq ,(cadr spec))
(,length (if (listp ,seq) nil (seq-length ,seq)))
(,index (if ,length 0 ,seq)))
(while (if ,length
(< ,index ,length)
(consp ,index))
(let ((,(car spec) (if ,length
(prog1 (seq-elt ,seq ,index)
(setq ,index (+ ,index 1)))
(pop ,index))))
,@body)))))
;; Implementation of `seq-let' compatible with Emacs<25.1.
(defmacro seq-let (args sequence &rest body)
"Bind the variables in ARGS to the elements of SEQUENCE then evaluate BODY.
ARGS can also include the `&rest' marker followed by a variable
name to be bound to the rest of SEQUENCE."
(declare (indent 2) (debug t))
(let ((seq-var (make-symbol "seq")))
`(let* ((,seq-var ,sequence)
,@(seq--make-bindings args seq-var))
,@body)))
(defun seq-drop (sequence n)
"Return a subsequence of SEQUENCE without its first N elements.
The result is a sequence of the same type as SEQUENCE.
If N is a negative integer or zero, SEQUENCE is returned."
(if (<= n 0)
sequence
(if (listp sequence)
(seq--drop-list sequence n)
(let ((length (seq-length sequence)))
(seq-subseq sequence (min n length) length)))))
(defun seq-take (sequence n)
"Return a subsequence of SEQUENCE with its first N elements.
The result is a sequence of the same type as SEQUENCE.
If N is a negative integer or zero, an empty sequence is
returned."
(if (listp sequence)
(seq--take-list sequence n)
(seq-subseq sequence 0 (min (max n 0) (seq-length sequence)))))
(defun seq-drop-while (predicate sequence)
"Return a sequence from the first element for which (PREDICATE element) is nil in SEQUENCE.
The result is a sequence of the same type as SEQUENCE."
(if (listp sequence)
(seq--drop-while-list predicate sequence)
(seq-drop sequence (seq--count-successive predicate sequence))))
(defun seq-take-while (predicate sequence)
"Return the successive elements for which (PREDICATE element) is non-nil in SEQUENCE.
The result is a sequence of the same type as SEQUENCE."
(if (listp sequence)
(seq--take-while-list predicate sequence)
(seq-take sequence (seq--count-successive predicate sequence))))
(defun seq-filter (predicate sequence)
"Return a list of all the elements for which (PREDICATE element) is non-nil in SEQUENCE."
(let ((exclude (make-symbol "exclude")))
(delq exclude (seq-map (lambda (elt)
(if (funcall predicate elt)
elt
exclude))
sequence))))
(defun seq-map-indexed (function sequence)
"Return the result of applying FUNCTION to each element of SEQUENCE.
Unlike `seq-map', FUNCTION takes two arguments: the element of
the sequence, and its index within the sequence."
(let ((index 0))
(seq-map (lambda (elt)
(prog1
(funcall function elt index)
(setq index (1+ index))))
sequence)))
(defun seq-remove (predicate sequence)
"Return a list of all the elements for which (PREDICATE element) is nil in SEQUENCE."
(seq-filter (lambda (elt) (not (funcall predicate elt)))
sequence))
(defun seq-reduce (function sequence initial-value)
"Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
Return the result of calling FUNCTION with INITIAL-VALUE and the
first element of SEQUENCE, then calling FUNCTION with that result and
the second element of SEQUENCE, then with that result and the third
element of SEQUENCE, etc.
If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called."
(if (seq-empty-p sequence)
initial-value
(let ((acc initial-value))
(seq-doseq (elt sequence)
(setq acc (funcall function acc elt)))
acc)))
(defun seq-some (predicate sequence)
"Return the first value for which if (PREDICATE element) is non-nil for in SEQUENCE."
(catch 'seq--break
(seq-doseq (elt sequence)
(let ((result (funcall predicate elt)))
(when result
(throw 'seq--break result))))
nil))
(defun seq-find (predicate sequence &optional default)
"Return the first element for which (PREDICATE element) is non-nil in SEQUENCE.
If no element is found, return DEFAULT.
Note that `seq-find' has an ambiguity if the found element is
identical to DEFAULT, as it cannot be known if an element was
found or not."
(catch 'seq--break
(seq-doseq (elt sequence)
(when (funcall predicate elt)
(throw 'seq--break elt)))
default))
(defun seq-every-p (predicate sequence)
"Return non-nil if (PREDICATE element) is non-nil for all elements of the sequence SEQUENCE."
(catch 'seq--break
(seq-doseq (elt sequence)
(or (funcall predicate elt)
(throw 'seq--break nil)))
t))
(defun seq-count (predicate sequence)
"Return the number of elements for which (PREDICATE element) is non-nil in SEQUENCE."
(let ((count 0))
(seq-doseq (elt sequence)
(when (funcall predicate elt)
(setq count (+ 1 count))))
count))
(defun seq-empty-p (sequence)
"Return non-nil if the sequence SEQUENCE is empty, nil otherwise."
(if (listp sequence)
(null sequence)
(= 0 (seq-length sequence))))
(defun seq-sort (predicate sequence)
"Return a sorted sequence comparing using PREDICATE the elements of SEQUENCE.
The result is a sequence of the same type as SEQUENCE."
(if (listp sequence)
(sort (seq-copy sequence) predicate)
(let ((result (seq-sort predicate (append sequence nil))))
(seq-into result (type-of sequence)))))
(defun seq-sort-by (function pred sequence)
"Sort SEQUENCE using PRED as a comparison function.
Elements of SEQUENCE are transformed by FUNCTION before being
sorted. FUNCTION must be a function of one argument."
(seq-sort (lambda (a b)
(funcall pred
(funcall function a)
(funcall function b)))
sequence))
(defun seq-contains (sequence elt &optional testfn)
"Return the first element in SEQUENCE that equals to ELT.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-some (lambda (e)
(funcall (or testfn #'equal) elt e))
sequence))
(defun seq-set-equal-p (sequence1 sequence2 &optional testfn)
"Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements, regardless of order.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(and (seq-every-p (lambda (item1) (seq-contains sequence2 item1 testfn)) sequence1)
(seq-every-p (lambda (item2) (seq-contains sequence1 item2 testfn)) sequence2)))
(defun seq-position (sequence elt &optional testfn)
"Return the index of the first element in SEQUENCE that is equal to ELT.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(let ((index 0))
(catch 'seq--break
(seq-doseq (e sequence)
(when (funcall (or testfn #'equal) e elt)
(throw 'seq--break index))
(setq index (1+ index)))
nil)))
(defun seq-uniq (sequence &optional testfn)
"Return a list of the elements of SEQUENCE with duplicates removed.
TESTFN is used to compare elements, or `equal' if TESTFN is nil."
(let ((result '()))
(seq-doseq (elt sequence)
(unless (seq-contains result elt testfn)
(setq result (cons elt result))))
(nreverse result)))
(defun seq-subseq (sequence start &optional end)
"Return the subsequence of SEQUENCE from START to END.
If END is omitted, it defaults to the length of the sequence.
If START or END is negative, it counts from the end."
(cond ((or (stringp sequence) (vectorp sequence)) (substring sequence start end))
((listp sequence)
(let (len (errtext (format "Bad bounding indices: %s, %s" start end)))
(and end (< end 0) (setq end (+ end (setq len (seq-length sequence)))))
(if (< start 0) (setq start (+ start (or len (setq len (seq-length sequence))))))
(when (> start 0)
(setq sequence (nthcdr (1- start) sequence))
(or sequence (error "%s" errtext))
(setq sequence (cdr sequence)))
(if end
(let ((res nil))
(while (and (>= (setq end (1- end)) start) sequence)
(push (pop sequence) res))
(or (= (1+ end) start) (error "%s" errtext))
(nreverse res))
(seq-copy sequence))))
(t (error "Unsupported sequence: %s" sequence))))
(defun seq-concatenate (type &rest seqs)
"Concatenate, into a sequence of type TYPE, the sequences SEQS.
TYPE must be one of following symbols: vector, string or list.
\n(fn TYPE SEQUENCE...)"
(pcase type
(`vector (apply #'vconcat seqs))
(`string (apply #'concat seqs))
(`list (apply #'append (append seqs '(nil))))
(_ (error "Not a sequence type name: %S" type))))
(defun seq-mapcat (function sequence &optional type)
"Concatenate the result of applying FUNCTION to each element of SEQUENCE.
The result is a sequence of type TYPE, or a list if TYPE is nil."
(apply #'seq-concatenate (or type 'list)
(seq-map function sequence)))
(defun seq-mapn (function sequence &rest seqs)
"Like `seq-map' but FUNCTION is mapped over all SEQS.
The arity of FUNCTION must match the number of SEQS, and the
mapping stops on the shortest sequence.
Return a list of the results.
\(fn FUNCTION SEQS...)"
(let ((result nil)
(seqs (seq-map (lambda (s)
(seq-into s 'list))
(cons sequence seqs))))
(while (not (memq nil seqs))
(push (apply function (seq-map #'car seqs)) result)
(setq seqs (seq-map #'cdr seqs)))
(nreverse result)))
(defun seq-partition (sequence n)
"Return a list of the elements of SEQUENCE grouped into sub-sequences of length N.
The last sequence may contain less than N elements. If N is a
negative integer or 0, nil is returned."
(unless (< n 1)
(let ((result '()))
(while (not (seq-empty-p sequence))
(push (seq-take sequence n) result)
(setq sequence (seq-drop sequence n)))
(nreverse result))))
(defun seq-intersection (seq1 seq2 &optional testfn)
"Return a list of the elements that appear in both SEQ1 and SEQ2.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-reduce (lambda (acc elt)
(if (seq-contains seq2 elt testfn)
(cons elt acc)
acc))
(seq-reverse seq1)
'()))
(defun seq-difference (seq1 seq2 &optional testfn)
"Return a list of the elements that appear in SEQ1 but not in SEQ2.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-reduce (lambda (acc elt)
(if (not (seq-contains seq2 elt testfn))
(cons elt acc)
acc))
(seq-reverse seq1)
'()))
(defun seq-group-by (function sequence)
"Apply FUNCTION to each element of SEQUENCE.
Separate the elements of SEQUENCE into an alist using the results as
keys. Keys are compared using `equal'."
(seq-reduce
(lambda (acc elt)
(let* ((key (funcall function elt))
(cell (assoc key acc)))
(if cell
(setcdr cell (push elt (cdr cell)))
(push (list key elt) acc))
acc))
(seq-reverse sequence)
nil))
(defalias 'seq-reverse
(if (ignore-errors (reverse [1 2]))
#'reverse
(lambda (sequence)
"Return the reversed copy of list, vector, or string SEQUENCE.
See also the function `nreverse', which is used more often."
(let ((result '()))
(seq-map (lambda (elt) (push elt result))
sequence)
(if (listp sequence)
result
(seq-into result (type-of sequence)))))))
(defun seq-into (sequence type)
"Convert the sequence SEQUENCE into a sequence of type TYPE.
TYPE can be one of the following symbols: vector, string or list."
(pcase type
(`vector (seq--into-vector sequence))
(`string (seq--into-string sequence))
(`list (seq--into-list sequence))
(_ (error "Not a sequence type name: %S" type))))
(defun seq-min (sequence)
"Return the smallest element of SEQUENCE.
SEQUENCE must be a sequence of numbers or markers."
(apply #'min (seq-into sequence 'list)))
(defun seq-max (sequence)
"Return the largest element of SEQUENCE.
SEQUENCE must be a sequence of numbers or markers."
(apply #'max (seq-into sequence 'list)))
(defun seq-random-elt (sequence)
"Return a random element from SEQUENCE.
Signal an error if SEQUENCE is empty."
(if (seq-empty-p sequence)
(error "Sequence cannot be empty")
(seq-elt sequence (random (seq-length sequence)))))
(defun seq--drop-list (list n)
"Return a list from LIST without its first N elements.
This is an optimization for lists in `seq-drop'."
(nthcdr n list))
(defun seq--take-list (list n)
"Return a list from LIST made of its first N elements.
This is an optimization for lists in `seq-take'."
(let ((result '()))
(while (and list (> n 0))
(setq n (1- n))
(push (pop list) result))
(nreverse result)))
(defun seq--drop-while-list (predicate list)
"Return a list from the first element for which (PREDICATE element) is nil in LIST.
This is an optimization for lists in `seq-drop-while'."
(while (and list (funcall predicate (car list)))
(setq list (cdr list)))
list)
(defun seq--take-while-list (predicate list)
"Return the successive elements for which (PREDICATE element) is non-nil in LIST.
This is an optimization for lists in `seq-take-while'."
(let ((result '()))
(while (and list (funcall predicate (car list)))
(push (pop list) result))
(nreverse result)))
(defun seq--count-successive (predicate sequence)
"Return the number of successive elements for which (PREDICATE element) is non-nil in SEQUENCE."
(let ((n 0)
(len (seq-length sequence)))
(while (and (< n len)
(funcall predicate (seq-elt sequence n)))
(setq n (+ 1 n)))
n))
;; Helper function for the Backward-compatible version of `seq-let'
;; for Emacs<25.1.
(defun seq--make-bindings (args sequence &optional bindings)
"Return a list of bindings of the variables in ARGS to the elements of a sequence.
if BINDINGS is non-nil, append new bindings to it, and return
BINDINGS."
(let ((index 0)
(rest-marker nil))
(seq-doseq (name args)
(unless rest-marker
(pcase name
((pred seqp)
(setq bindings (seq--make-bindings (seq--elt-safe args index)
`(seq--elt-safe ,sequence ,index)
bindings)))
(`&rest
(progn (push `(,(seq--elt-safe args (1+ index))
(seq-drop ,sequence ,index))
bindings)
(setq rest-marker t)))
(_
(push `(,name (seq--elt-safe ,sequence ,index)) bindings))))
(setq index (1+ index)))
bindings))
(defun seq--elt-safe (sequence n)
"Return element of SEQUENCE at the index N.
If no element is found, return nil."
(when (or (listp sequence)
(and (sequencep sequence)
(> (seq-length sequence) n)))
(seq-elt sequence n)))
(defun seq--activate-font-lock-keywords ()
"Activate font-lock keywords for some symbols defined in seq."
(font-lock-add-keywords 'emacs-lisp-mode
'("\\" "\\")))
(defalias 'seq-copy #'copy-sequence)
(defalias 'seq-elt #'elt)
(defalias 'seq-length #'length)
(defalias 'seq-do #'mapc)
(defalias 'seq-each #'seq-do)
(defalias 'seq-map #'mapcar)
(defalias 'seqp #'sequencep)
(defun seq--into-list (sequence)
"Concatenate the elements of SEQUENCE into a list."
(if (listp sequence)
sequence
(append sequence nil)))
(defun seq--into-vector (sequence)
"Concatenate the elements of SEQUENCE into a vector."
(if (vectorp sequence)
sequence
(vconcat sequence)))
(defun seq--into-string (sequence)
"Concatenate the elements of SEQUENCE into a string."
(if (stringp sequence)
sequence
(concat sequence)))
(unless (fboundp 'elisp--font-lock-flush-elisp-buffers)
;; In Emacs≥25, (via elisp--font-lock-flush-elisp-buffers and a few others)
;; we automatically highlight macros.
(add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords))
(provide 'seq-24)
;;; seq-24.el ends here
seq-2.20/seq-pkg.el0000644000175200017530000000027013102713476012552 0ustar elpaelpa;; Generated package description from seq.el
(define-package "seq" "2.20" "Sequence manipulation functions" 'nil :url "http://elpa.gnu.org/packages/seq.html" :keywords '("sequences"))
seq-2.20/seq.el0000644000175200017530000000300413102713323011760 0ustar elpaelpa;;; seq.el --- Sequence manipulation functions -*- lexical-binding: t -*-
;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
;; Author: Nicolas Petton
;; Keywords: sequences
;; Version: 2.20
;; Package: seq
;; Maintainer: emacs-devel@gnu.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see .
;;; Commentary:
;; Sequence-manipulation functions that complement basic functions
;; provided by subr.el.
;;
;; All functions are prefixed with "seq-".
;;
;; All provided functions work on lists, strings and vectors.
;;
;; Functions taking a predicate or iterating over a sequence using a
;; function as argument take the function as their first argument and
;; the sequence as their second argument. All other functions take
;; the sequence as their first argument.
;;; Code:
(if (version< emacs-version "25")
(require 'seq-24)
(require 'seq-25))
(provide 'seq)
;;; seq.el ends here
seq-2.20/seq-25.el0000644000175200017530000004425613102713323012222 0ustar elpaelpa;;; seq-25.el --- seq.el implementation for Emacs 25.x -*- lexical-binding: t -*-
;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
;; Author: Nicolas Petton
;; Keywords: sequences
;; Maintainer: emacs-devel@gnu.org
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see .
;;; Commentary:
;; Sequence-manipulation functions that complement basic functions
;; provided by subr.el.
;;
;; All functions are prefixed with "seq-".
;;
;; All provided functions work on lists, strings and vectors.
;;
;; Functions taking a predicate or iterating over a sequence using a
;; function as argument take the function as their first argument and
;; the sequence as their second argument. All other functions take
;; the sequence as their first argument.
;;
;; seq.el can be extended to support new type of sequences. Here are
;; the generic functions that must be implemented by new seq types:
;; - `seq-elt'
;; - `seq-length'
;; - `seq-do'
;; - `seqp'
;; - `seq-subseq'
;; - `seq-into-sequence'
;; - `seq-copy'
;; - `seq-into'
;;; Code:
;; When loading seq.el in Emacs 24.x, this file gets byte-compiled, even if
;; never used. This takes care of byte-compilation warnings is emitted, by
;; emitting nil in the macro expansion in Emacs 24.x.
(defmacro seq--when-emacs-25-p (&rest body)
"Execute BODY if in Emacs>=25.x."
(declare (indent (lambda (&rest x) 0)) (debug t))
(when (version<= "25" emacs-version)
`(progn ,@body)))
(seq--when-emacs-25-p
(require 'cl-generic)
(require 'cl-lib) ;; for cl-subseq
(defmacro seq-doseq (spec &rest body)
"Loop over a sequence.
Evaluate BODY with VAR bound to each element of SEQUENCE, in turn.
Similar to `dolist' but can be applied to lists, strings, and vectors.
\(fn (VAR SEQUENCE) BODY...)"
(declare (indent 1) (debug ((symbolp form &optional form) body)))
`(seq-do (lambda (,(car spec))
,@body)
,(cadr spec)))
(pcase-defmacro seq (&rest patterns)
"Build a `pcase' pattern that matches elements of SEQUENCE.
The `pcase' pattern will match each element of PATTERNS against the
corresponding element of SEQUENCE.
Extra elements of the sequence are ignored if fewer PATTERNS are
given, and the match does not fail."
`(and (pred seqp)
,@(seq--make-pcase-bindings patterns)))
(defmacro seq-let (args sequence &rest body)
"Bind the variables in ARGS to the elements of SEQUENCE, then evaluate BODY.
ARGS can also include the `&rest' marker followed by a variable
name to be bound to the rest of SEQUENCE."
(declare (indent 2) (debug (sexp form body)))
`(pcase-let ((,(seq--make-pcase-patterns args) ,sequence))
,@body))
;;; Basic seq functions that have to be implemented by new sequence types
(cl-defgeneric seq-elt (sequence n)
"Return Nth element of SEQUENCE."
(elt sequence n))
;; Default gv setters for `seq-elt'.
;; It can be a good idea for new sequence implementations to provide a
;; "gv-setter" for `seq-elt'.
(cl-defmethod (setf seq-elt) (store (sequence array) n)
(aset sequence n store))
(cl-defmethod (setf seq-elt) (store (sequence cons) n)
(setcar (nthcdr n sequence) store))
(cl-defgeneric seq-length (sequence)
"Return the number of elements of SEQUENCE."
(length sequence))
(cl-defgeneric seq-do (function sequence)
"Apply FUNCTION to each element of SEQUENCE, presumably for side effects.
Return SEQUENCE."
(mapc function sequence))
(defalias 'seq-each #'seq-do)
(cl-defgeneric seqp (sequence)
"Return non-nil if SEQUENCE is a sequence, nil otherwise."
(sequencep sequence))
(cl-defgeneric seq-copy (sequence)
"Return a shallow copy of SEQUENCE."
(copy-sequence sequence))
(cl-defgeneric seq-subseq (sequence start &optional end)
"Return the sequence of elements of SEQUENCE from START to END.
END is exclusive.
If END is omitted, it defaults to the length of the sequence. If
START or END is negative, it counts from the end. Signal an
error if START or END are outside of the sequence (i.e too large
if positive or too small if negative)."
(cl-subseq sequence start end))
(cl-defgeneric seq-map (function sequence)
"Return the result of applying FUNCTION to each element of SEQUENCE."
(let (result)
(seq-do (lambda (elt)
(push (funcall function elt) result))
sequence)
(nreverse result)))
(defun seq-map-indexed (function sequence)
"Return the result of applying FUNCTION to each element of SEQUENCE.
Unlike `seq-map', FUNCTION takes two arguments: the element of
the sequence, and its index within the sequence."
(let ((index 0))
(seq-map (lambda (elt)
(prog1
(funcall function elt index)
(setq index (1+ index))))
sequence)))
;; faster implementation for sequences (sequencep)
(cl-defmethod seq-map (function (sequence sequence))
(mapcar function sequence))
(cl-defgeneric seq-mapn (function sequence &rest sequences)
"Like `seq-map' but FUNCTION is mapped over all SEQUENCES.
The arity of FUNCTION must match the number of SEQUENCES, and the
mapping stops on the shortest sequence.
Return a list of the results.
\(fn FUNCTION SEQUENCES...)"
(let ((result nil)
(sequences (seq-map (lambda (s)
(seq-into s 'list))
(cons sequence sequences))))
(while (not (memq nil sequences))
(push (apply function (seq-map #'car sequences)) result)
(setq sequences (seq-map #'cdr sequences)))
(nreverse result)))
(cl-defgeneric seq-drop (sequence n)
"Remove the first N elements of SEQUENCE and return the result.
The result is a sequence of the same type as SEQUENCE.
If N is a negative integer or zero, SEQUENCE is returned."
(if (<= n 0)
sequence
(let ((length (seq-length sequence)))
(seq-subseq sequence (min n length) length))))
(cl-defgeneric seq-take (sequence n)
"Take the first N elements of SEQUENCE and return the result.
The result is a sequence of the same type as SEQUENCE.
If N is a negative integer or zero, an empty sequence is
returned."
(seq-subseq sequence 0 (min (max n 0) (seq-length sequence))))
(cl-defgeneric seq-drop-while (pred sequence)
"Remove the successive elements of SEQUENCE for which PRED returns non-nil.
PRED is a function of one argument. The result is a sequence of
the same type as SEQUENCE."
(seq-drop sequence (seq--count-successive pred sequence)))
(cl-defgeneric seq-take-while (pred sequence)
"Take the successive elements of SEQUENCE for which PRED returns non-nil.
PRED is a function of one argument. The result is a sequence of
the same type as SEQUENCE."
(seq-take sequence (seq--count-successive pred sequence)))
(cl-defgeneric seq-empty-p (sequence)
"Return non-nil if the SEQUENCE is empty, nil otherwise."
(= 0 (seq-length sequence)))
(cl-defgeneric seq-sort (pred sequence)
"Sort SEQUENCE using PRED as comparison function.
The result is a sequence of the same type as SEQUENCE."
(let ((result (seq-sort pred (append sequence nil))))
(seq-into result (type-of sequence))))
(defun seq-sort-by (function pred sequence)
"Sort SEQUENCE using PRED as a comparison function.
Elements of SEQUENCE are transformed by FUNCTION before being
sorted. FUNCTION must be a function of one argument."
(seq-sort (lambda (a b)
(funcall pred
(funcall function a)
(funcall function b)))
sequence))
(cl-defmethod seq-sort (pred (list list))
(sort (seq-copy list) pred))
(cl-defgeneric seq-reverse (sequence)
"Return a sequence with elements of SEQUENCE in reverse order."
(let ((result '()))
(seq-map (lambda (elt)
(push elt result))
sequence)
(seq-into result (type-of sequence))))
;; faster implementation for sequences (sequencep)
(cl-defmethod seq-reverse ((sequence sequence))
(reverse sequence))
(cl-defgeneric seq-concatenate (type &rest sequences)
"Concatenate SEQUENCES into a single sequence of type TYPE.
TYPE must be one of following symbols: vector, string or list.
\n(fn TYPE SEQUENCE...)"
(apply #'cl-concatenate type (seq-map #'seq-into-sequence sequences)))
(cl-defgeneric seq-into-sequence (sequence)
"Convert SEQUENCE into a sequence.
The default implementation is to signal an error if SEQUENCE is not a
sequence, specific functions should be implemented for new types
of sequence."
(unless (sequencep sequence)
(error "Cannot convert %S into a sequence" sequence))
sequence)
(cl-defgeneric seq-into (sequence type)
"Concatenate the elements of SEQUENCE into a sequence of type TYPE.
TYPE can be one of the following symbols: vector, string or
list."
(pcase type
(`vector (seq--into-vector sequence))
(`string (seq--into-string sequence))
(`list (seq--into-list sequence))
(_ (error "Not a sequence type name: %S" type))))
(cl-defgeneric seq-filter (pred sequence)
"Return a list of all the elements for which (PRED element) is non-nil in SEQUENCE."
(let ((exclude (make-symbol "exclude")))
(delq exclude (seq-map (lambda (elt)
(if (funcall pred elt)
elt
exclude))
sequence))))
(cl-defgeneric seq-remove (pred sequence)
"Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
(seq-filter (lambda (elt) (not (funcall pred elt)))
sequence))
(cl-defgeneric seq-reduce (function sequence initial-value)
"Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
Return the result of calling FUNCTION with INITIAL-VALUE and the
first element of SEQUENCE, then calling FUNCTION with that result and
the second element of SEQUENCE, then with that result and the third
element of SEQUENCE, etc.
If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called."
(if (seq-empty-p sequence)
initial-value
(let ((acc initial-value))
(seq-doseq (elt sequence)
(setq acc (funcall function acc elt)))
acc)))
(cl-defgeneric seq-every-p (pred sequence)
"Return non-nil if (PRED element) is non-nil for all elements of SEQUENCE."
(catch 'seq--break
(seq-doseq (elt sequence)
(or (funcall pred elt)
(throw 'seq--break nil)))
t))
(cl-defgeneric seq-some (pred sequence)
"Return the first value for which if (PRED element) is non-nil for in SEQUENCE."
(catch 'seq--break
(seq-doseq (elt sequence)
(let ((result (funcall pred elt)))
(when result
(throw 'seq--break result))))
nil))
(cl-defgeneric seq-find (pred sequence &optional default)
"Return the first element for which (PRED element) is non-nil in SEQUENCE.
If no element is found, return DEFAULT.
Note that `seq-find' has an ambiguity if the found element is
identical to DEFAULT, as it cannot be known if an element was
found or not."
(catch 'seq--break
(seq-doseq (elt sequence)
(when (funcall pred elt)
(throw 'seq--break elt)))
default))
(cl-defgeneric seq-count (pred sequence)
"Return the number of elements for which (PRED element) is non-nil in SEQUENCE."
(let ((count 0))
(seq-doseq (elt sequence)
(when (funcall pred elt)
(setq count (+ 1 count))))
count))
(cl-defgeneric seq-contains (sequence elt &optional testfn)
"Return the first element in SEQUENCE that is equal to ELT.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-some (lambda (e)
(funcall (or testfn #'equal) elt e))
sequence))
(cl-defgeneric seq-set-equal-p (sequence1 sequence2 &optional testfn)
"Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements, regardless of order.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(and (seq-every-p (lambda (item1) (seq-contains sequence2 item1 testfn)) sequence1)
(seq-every-p (lambda (item2) (seq-contains sequence1 item2 testfn)) sequence2)))
(cl-defgeneric seq-position (sequence elt &optional testfn)
"Return the index of the first element in SEQUENCE that is equal to ELT.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(let ((index 0))
(catch 'seq--break
(seq-doseq (e sequence)
(when (funcall (or testfn #'equal) e elt)
(throw 'seq--break index))
(setq index (1+ index)))
nil)))
(cl-defgeneric seq-uniq (sequence &optional testfn)
"Return a list of the elements of SEQUENCE with duplicates removed.
TESTFN is used to compare elements, or `equal' if TESTFN is nil."
(let ((result '()))
(seq-doseq (elt sequence)
(unless (seq-contains result elt testfn)
(setq result (cons elt result))))
(nreverse result)))
(cl-defgeneric seq-mapcat (function sequence &optional type)
"Concatenate the result of applying FUNCTION to each element of SEQUENCE.
The result is a sequence of type TYPE, or a list if TYPE is nil."
(apply #'seq-concatenate (or type 'list)
(seq-map function sequence)))
(cl-defgeneric seq-partition (sequence n)
"Return a list of the elements of SEQUENCE grouped into sub-sequences of length N.
The last sequence may contain less than N elements. If N is a
negative integer or 0, nil is returned."
(unless (< n 1)
(let ((result '()))
(while (not (seq-empty-p sequence))
(push (seq-take sequence n) result)
(setq sequence (seq-drop sequence n)))
(nreverse result))))
(cl-defgeneric seq-intersection (sequence1 sequence2 &optional testfn)
"Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-reduce (lambda (acc elt)
(if (seq-contains sequence2 elt testfn)
(cons elt acc)
acc))
(seq-reverse sequence1)
'()))
(cl-defgeneric seq-difference (sequence1 sequence2 &optional testfn)
"Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2.
Equality is defined by TESTFN if non-nil or by `equal' if nil."
(seq-reduce (lambda (acc elt)
(if (not (seq-contains sequence2 elt testfn))
(cons elt acc)
acc))
(seq-reverse sequence1)
'()))
(cl-defgeneric seq-group-by (function sequence)
"Apply FUNCTION to each element of SEQUENCE.
Separate the elements of SEQUENCE into an alist using the results as
keys. Keys are compared using `equal'."
(seq-reduce
(lambda (acc elt)
(let* ((key (funcall function elt))
(cell (assoc key acc)))
(if cell
(setcdr cell (push elt (cdr cell)))
(push (list key elt) acc))
acc))
(seq-reverse sequence)
nil))
(cl-defgeneric seq-min (sequence)
"Return the smallest element of SEQUENCE.
SEQUENCE must be a sequence of numbers or markers."
(apply #'min (seq-into sequence 'list)))
(cl-defgeneric seq-max (sequence)
"Return the largest element of SEQUENCE.
SEQUENCE must be a sequence of numbers or markers."
(apply #'max (seq-into sequence 'list)))
(defun seq--count-successive (pred sequence)
"Return the number of successive elements for which (PRED element) is non-nil in SEQUENCE."
(let ((n 0)
(len (seq-length sequence)))
(while (and (< n len)
(funcall pred (seq-elt sequence n)))
(setq n (+ 1 n)))
n))
;;; Optimized implementations for lists
(cl-defmethod seq-drop ((list list) n)
"Optimized implementation of `seq-drop' for lists."
(nthcdr n list))
(cl-defmethod seq-take ((list list) n)
"Optimized implementation of `seq-take' for lists."
(let ((result '()))
(while (and list (> n 0))
(setq n (1- n))
(push (pop list) result))
(nreverse result)))
(cl-defmethod seq-drop-while (pred (list list))
"Optimized implementation of `seq-drop-while' for lists."
(while (and list (funcall pred (car list)))
(setq list (cdr list)))
list)
(cl-defmethod seq-empty-p ((list list))
"Optimized implementation of `seq-empty-p' for lists."
(null list))
(defun seq--into-list (sequence)
"Concatenate the elements of SEQUENCE into a list."
(if (listp sequence)
sequence
(append sequence nil)))
(defun seq--into-vector (sequence)
"Concatenate the elements of SEQUENCE into a vector."
(if (vectorp sequence)
sequence
(vconcat sequence)))
(defun seq--into-string (sequence)
"Concatenate the elements of SEQUENCE into a string."
(if (stringp sequence)
sequence
(concat sequence)))
(defun seq--make-pcase-bindings (args)
"Return a list of bindings of the variables in ARGS to the elements of a sequence."
(let ((bindings '())
(index 0)
(rest-marker nil))
(seq-doseq (name args)
(unless rest-marker
(pcase name
(`&rest
(progn (push `(app (pcase--flip seq-drop ,index)
,(seq--elt-safe args (1+ index)))
bindings)
(setq rest-marker t)))
(_
(push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings))))
(setq index (1+ index)))
bindings))
(defun seq--make-pcase-patterns (args)
"Return a list of `(seq ...)' pcase patterns from the argument list ARGS."
(cons 'seq
(seq-map (lambda (elt)
(if (seqp elt)
(seq--make-pcase-patterns elt)
elt))
args)))
;; TODO: make public?
(defun seq--elt-safe (sequence n)
"Return element of SEQUENCE at the index N.
If no element is found, return nil."
(ignore-errors (seq-elt sequence n))))
(cl-defgeneric seq-random-elt (sequence)
"Return a random element from SEQUENCE.
Signal an error if SEQUENCE is empty."
(if (seq-empty-p sequence)
(error "Sequence cannot be empty")
(seq-elt sequence (random (seq-length sequence)))))
(provide 'seq-25)
;;; seq-25.el ends here