final tt updates
[emacs-init.git] / elpa / seq-2.20 / seq-25.el
1 ;;; seq-25.el --- seq.el implementation for Emacs 25.x -*- lexical-binding: t -*-
2
3 ;; Copyright (C) 2014-2016 Free Software Foundation, Inc.
4
5 ;; Author: Nicolas Petton <nicolas@petton.fr>
6 ;; Keywords: sequences
7
8 ;; Maintainer: emacs-devel@gnu.org
9
10 ;; This file is part of GNU Emacs.
11
12 ;; GNU Emacs is free software: you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation, either version 3 of the License, or
15 ;; (at your option) any later version.
16
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ;; GNU General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.
24
25 ;;; Commentary:
26
27 ;; Sequence-manipulation functions that complement basic functions
28 ;; provided by subr.el.
29 ;;
30 ;; All functions are prefixed with "seq-".
31 ;;
32 ;; All provided functions work on lists, strings and vectors.
33 ;;
34 ;; Functions taking a predicate or iterating over a sequence using a
35 ;; function as argument take the function as their first argument and
36 ;; the sequence as their second argument.  All other functions take
37 ;; the sequence as their first argument.
38 ;;
39 ;; seq.el can be extended to support new type of sequences.  Here are
40 ;; the generic functions that must be implemented by new seq types:
41 ;; - `seq-elt'
42 ;; - `seq-length'
43 ;; - `seq-do'
44 ;; - `seqp'
45 ;; - `seq-subseq'
46 ;; - `seq-into-sequence'
47 ;; - `seq-copy'
48 ;; - `seq-into'
49
50 ;;; Code:
51
52 ;; When loading seq.el in Emacs 24.x, this file gets byte-compiled, even if
53 ;; never used.  This takes care of byte-compilation warnings is emitted, by
54 ;; emitting nil in the macro expansion in Emacs 24.x.
55 (defmacro seq--when-emacs-25-p (&rest body)
56   "Execute BODY if in Emacs>=25.x."
57   (declare (indent (lambda (&rest x) 0)) (debug t))
58   (when (version<= "25" emacs-version)
59     `(progn ,@body)))
60
61 (seq--when-emacs-25-p
62
63 (require 'cl-generic)
64 (require 'cl-lib) ;; for cl-subseq
65
66 (defmacro seq-doseq (spec &rest body)
67   "Loop over a sequence.
68 Evaluate BODY with VAR bound to each element of SEQUENCE, in turn.
69
70 Similar to `dolist' but can be applied to lists, strings, and vectors.
71
72 \(fn (VAR SEQUENCE) BODY...)"
73   (declare (indent 1) (debug ((symbolp form &optional form) body)))
74   `(seq-do (lambda (,(car spec))
75              ,@body)
76            ,(cadr spec)))
77
78 (pcase-defmacro seq (&rest patterns)
79   "Build a `pcase' pattern that matches elements of SEQUENCE.
80
81 The `pcase' pattern will match each element of PATTERNS against the
82 corresponding element of SEQUENCE.
83
84 Extra elements of the sequence are ignored if fewer PATTERNS are
85 given, and the match does not fail."
86   `(and (pred seqp)
87         ,@(seq--make-pcase-bindings patterns)))
88
89 (defmacro seq-let (args sequence &rest body)
90   "Bind the variables in ARGS to the elements of SEQUENCE, then evaluate BODY.
91
92 ARGS can also include the `&rest' marker followed by a variable
93 name to be bound to the rest of SEQUENCE."
94   (declare (indent 2) (debug (sexp form body)))
95   `(pcase-let ((,(seq--make-pcase-patterns args) ,sequence))
96      ,@body))
97 \f
98
99 ;;; Basic seq functions that have to be implemented by new sequence types
100 (cl-defgeneric seq-elt (sequence n)
101   "Return Nth element of SEQUENCE."
102   (elt sequence n))
103
104 ;; Default gv setters for `seq-elt'.
105 ;; It can be a good idea for new sequence implementations to provide a
106 ;; "gv-setter" for `seq-elt'.
107 (cl-defmethod (setf seq-elt) (store (sequence array) n)
108   (aset sequence n store))
109
110 (cl-defmethod (setf seq-elt) (store (sequence cons) n)
111   (setcar (nthcdr n sequence) store))
112
113 (cl-defgeneric seq-length (sequence)
114   "Return the number of elements of SEQUENCE."
115   (length sequence))
116
117 (cl-defgeneric seq-do (function sequence)
118   "Apply FUNCTION to each element of SEQUENCE, presumably for side effects.
119 Return SEQUENCE."
120   (mapc function sequence))
121
122 (defalias 'seq-each #'seq-do)
123
124 (cl-defgeneric seqp (sequence)
125   "Return non-nil if SEQUENCE is a sequence, nil otherwise."
126   (sequencep sequence))
127
128 (cl-defgeneric seq-copy (sequence)
129   "Return a shallow copy of SEQUENCE."
130   (copy-sequence sequence))
131
132 (cl-defgeneric seq-subseq (sequence start &optional end)
133   "Return the sequence of elements of SEQUENCE from START to END.
134 END is exclusive.
135
136 If END is omitted, it defaults to the length of the sequence.  If
137 START or END is negative, it counts from the end.  Signal an
138 error if START or END are outside of the sequence (i.e too large
139 if positive or too small if negative)."
140   (cl-subseq sequence start end))
141
142 \f
143 (cl-defgeneric seq-map (function sequence)
144   "Return the result of applying FUNCTION to each element of SEQUENCE."
145   (let (result)
146     (seq-do (lambda (elt)
147               (push (funcall function elt) result))
148             sequence)
149     (nreverse result)))
150
151 (defun seq-map-indexed (function sequence)
152   "Return the result of applying FUNCTION to each element of SEQUENCE.
153 Unlike `seq-map', FUNCTION takes two arguments: the element of
154 the sequence, and its index within the sequence."
155   (let ((index 0))
156     (seq-map (lambda (elt)
157                (prog1
158                    (funcall function elt index)
159                  (setq index (1+ index))))
160              sequence)))
161
162 ;; faster implementation for sequences (sequencep)
163 (cl-defmethod seq-map (function (sequence sequence))
164   (mapcar function sequence))
165
166 (cl-defgeneric seq-mapn (function sequence &rest sequences)
167   "Like `seq-map' but FUNCTION is mapped over all SEQUENCES.
168 The arity of FUNCTION must match the number of SEQUENCES, and the
169 mapping stops on the shortest sequence.
170 Return a list of the results.
171
172 \(fn FUNCTION SEQUENCES...)"
173   (let ((result nil)
174         (sequences (seq-map (lambda (s)
175                               (seq-into s 'list))
176                             (cons sequence sequences))))
177     (while (not (memq nil sequences))
178       (push (apply function (seq-map #'car sequences)) result)
179       (setq sequences (seq-map #'cdr sequences)))
180     (nreverse result)))
181
182 (cl-defgeneric seq-drop (sequence n)
183   "Remove the first N elements of SEQUENCE and return the result.
184 The result is a sequence of the same type as SEQUENCE.
185
186 If N is a negative integer or zero, SEQUENCE is returned."
187   (if (<= n 0)
188       sequence
189     (let ((length (seq-length sequence)))
190       (seq-subseq sequence (min n length) length))))
191
192 (cl-defgeneric seq-take (sequence n)
193   "Take the first N elements of SEQUENCE and return the result.
194 The result is a sequence of the same type as SEQUENCE.
195
196 If N is a negative integer or zero, an empty sequence is
197 returned."
198   (seq-subseq sequence 0 (min (max n 0) (seq-length sequence))))
199
200 (cl-defgeneric seq-drop-while (pred sequence)
201   "Remove the successive elements of SEQUENCE for which PRED returns non-nil.
202 PRED is a function of one argument.  The result is a sequence of
203 the same type as SEQUENCE."
204   (seq-drop sequence (seq--count-successive pred sequence)))
205
206 (cl-defgeneric seq-take-while (pred sequence)
207   "Take the successive elements of SEQUENCE for which PRED returns non-nil.
208 PRED is a function of one argument.  The result is a sequence of
209 the same type as SEQUENCE."
210   (seq-take sequence (seq--count-successive pred sequence)))
211
212 (cl-defgeneric seq-empty-p (sequence)
213   "Return non-nil if the SEQUENCE is empty, nil otherwise."
214   (= 0 (seq-length sequence)))
215
216 (cl-defgeneric seq-sort (pred sequence)
217   "Sort SEQUENCE using PRED as comparison function.
218 The result is a sequence of the same type as SEQUENCE."
219   (let ((result (seq-sort pred (append sequence nil))))
220     (seq-into result (type-of sequence))))
221
222 (defun seq-sort-by (function pred sequence)
223   "Sort SEQUENCE using PRED as a comparison function.
224 Elements of SEQUENCE are transformed by FUNCTION before being
225 sorted.  FUNCTION must be a function of one argument."
226   (seq-sort (lambda (a b)
227               (funcall pred
228                        (funcall function a)
229                        (funcall function b)))
230             sequence))
231
232 (cl-defmethod seq-sort (pred (list list))
233   (sort (seq-copy list) pred))
234
235 (cl-defgeneric seq-reverse (sequence)
236   "Return a sequence with elements of SEQUENCE in reverse order."
237   (let ((result '()))
238     (seq-map (lambda (elt)
239                (push elt result))
240              sequence)
241     (seq-into result (type-of sequence))))
242
243 ;; faster implementation for sequences (sequencep)
244 (cl-defmethod seq-reverse ((sequence sequence))
245   (reverse sequence))
246
247 (cl-defgeneric seq-concatenate (type &rest sequences)
248   "Concatenate SEQUENCES into a single sequence of type TYPE.
249 TYPE must be one of following symbols: vector, string or list.
250
251 \n(fn TYPE SEQUENCE...)"
252   (apply #'cl-concatenate type (seq-map #'seq-into-sequence sequences)))
253
254 (cl-defgeneric seq-into-sequence (sequence)
255   "Convert SEQUENCE into a sequence.
256
257 The default implementation is to signal an error if SEQUENCE is not a
258 sequence, specific functions should be implemented for new types
259 of sequence."
260   (unless (sequencep sequence)
261     (error "Cannot convert %S into a sequence" sequence))
262   sequence)
263
264 (cl-defgeneric seq-into (sequence type)
265   "Concatenate the elements of SEQUENCE into a sequence of type TYPE.
266 TYPE can be one of the following symbols: vector, string or
267 list."
268   (pcase type
269     (`vector (seq--into-vector sequence))
270     (`string (seq--into-string sequence))
271     (`list (seq--into-list sequence))
272     (_ (error "Not a sequence type name: %S" type))))
273
274 (cl-defgeneric seq-filter (pred sequence)
275   "Return a list of all the elements for which (PRED element) is non-nil in SEQUENCE."
276   (let ((exclude (make-symbol "exclude")))
277     (delq exclude (seq-map (lambda (elt)
278                              (if (funcall pred elt)
279                                  elt
280                                exclude))
281                            sequence))))
282
283 (cl-defgeneric seq-remove (pred sequence)
284   "Return a list of all the elements for which (PRED element) is nil in SEQUENCE."
285   (seq-filter (lambda (elt) (not (funcall pred elt)))
286               sequence))
287
288 (cl-defgeneric seq-reduce (function sequence initial-value)
289   "Reduce the function FUNCTION across SEQUENCE, starting with INITIAL-VALUE.
290
291 Return the result of calling FUNCTION with INITIAL-VALUE and the
292 first element of SEQUENCE, then calling FUNCTION with that result and
293 the second element of SEQUENCE, then with that result and the third
294 element of SEQUENCE, etc.
295
296 If SEQUENCE is empty, return INITIAL-VALUE and FUNCTION is not called."
297   (if (seq-empty-p sequence)
298       initial-value
299     (let ((acc initial-value))
300       (seq-doseq (elt sequence)
301         (setq acc (funcall function acc elt)))
302       acc)))
303
304 (cl-defgeneric seq-every-p (pred sequence)
305   "Return non-nil if (PRED element) is non-nil for all elements of SEQUENCE."
306   (catch 'seq--break
307     (seq-doseq (elt sequence)
308       (or (funcall pred elt)
309           (throw 'seq--break nil)))
310     t))
311
312 (cl-defgeneric seq-some (pred sequence)
313   "Return the first value for which if (PRED element) is non-nil for in SEQUENCE."
314   (catch 'seq--break
315     (seq-doseq (elt sequence)
316       (let ((result (funcall pred elt)))
317         (when result
318           (throw 'seq--break result))))
319     nil))
320
321 (cl-defgeneric seq-find (pred sequence &optional default)
322   "Return the first element for which (PRED element) is non-nil in SEQUENCE.
323 If no element is found, return DEFAULT.
324
325 Note that `seq-find' has an ambiguity if the found element is
326 identical to DEFAULT, as it cannot be known if an element was
327 found or not."
328   (catch 'seq--break
329     (seq-doseq (elt sequence)
330       (when (funcall pred elt)
331         (throw 'seq--break elt)))
332     default))
333
334 (cl-defgeneric seq-count (pred sequence)
335   "Return the number of elements for which (PRED element) is non-nil in SEQUENCE."
336   (let ((count 0))
337     (seq-doseq (elt sequence)
338       (when (funcall pred elt)
339         (setq count (+ 1 count))))
340     count))
341
342 (cl-defgeneric seq-contains (sequence elt &optional testfn)
343   "Return the first element in SEQUENCE that is equal to ELT.
344 Equality is defined by TESTFN if non-nil or by `equal' if nil."
345   (seq-some (lambda (e)
346               (funcall (or testfn #'equal) elt e))
347             sequence))
348
349 (cl-defgeneric seq-set-equal-p (sequence1 sequence2 &optional testfn)
350   "Return non-nil if SEQUENCE1 and SEQUENCE2 contain the same elements, regardless of order.
351 Equality is defined by TESTFN if non-nil or by `equal' if nil."
352   (and (seq-every-p (lambda (item1) (seq-contains sequence2 item1 testfn)) sequence1)
353        (seq-every-p (lambda (item2) (seq-contains sequence1 item2 testfn)) sequence2)))
354
355 (cl-defgeneric seq-position (sequence elt &optional testfn)
356   "Return the index of the first element in SEQUENCE that is equal to ELT.
357 Equality is defined by TESTFN if non-nil or by `equal' if nil."
358   (let ((index 0))
359     (catch 'seq--break
360       (seq-doseq (e sequence)
361         (when (funcall (or testfn #'equal) e elt)
362           (throw 'seq--break index))
363         (setq index (1+ index)))
364       nil)))
365
366 (cl-defgeneric seq-uniq (sequence &optional testfn)
367   "Return a list of the elements of SEQUENCE with duplicates removed.
368 TESTFN is used to compare elements, or `equal' if TESTFN is nil."
369   (let ((result '()))
370     (seq-doseq (elt sequence)
371       (unless (seq-contains result elt testfn)
372         (setq result (cons elt result))))
373     (nreverse result)))
374
375 (cl-defgeneric seq-mapcat (function sequence &optional type)
376   "Concatenate the result of applying FUNCTION to each element of SEQUENCE.
377 The result is a sequence of type TYPE, or a list if TYPE is nil."
378   (apply #'seq-concatenate (or type 'list)
379          (seq-map function sequence)))
380
381 (cl-defgeneric seq-partition (sequence n)
382   "Return a list of the elements of SEQUENCE grouped into sub-sequences of length N.
383 The last sequence may contain less than N elements.  If N is a
384 negative integer or 0, nil is returned."
385   (unless (< n 1)
386     (let ((result '()))
387       (while (not (seq-empty-p sequence))
388         (push (seq-take sequence n) result)
389         (setq sequence (seq-drop sequence n)))
390       (nreverse result))))
391
392 (cl-defgeneric seq-intersection (sequence1 sequence2 &optional testfn)
393   "Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
394 Equality is defined by TESTFN if non-nil or by `equal' if nil."
395   (seq-reduce (lambda (acc elt)
396                 (if (seq-contains sequence2 elt testfn)
397                     (cons elt acc)
398                   acc))
399               (seq-reverse sequence1)
400               '()))
401
402 (cl-defgeneric seq-difference (sequence1 sequence2 &optional testfn)
403   "Return a list of the elements that appear in SEQUENCE1 but not in SEQUENCE2.
404 Equality is defined by TESTFN if non-nil or by `equal' if nil."
405   (seq-reduce (lambda (acc elt)
406                 (if (not (seq-contains sequence2 elt testfn))
407                     (cons elt acc)
408                   acc))
409               (seq-reverse sequence1)
410               '()))
411
412 (cl-defgeneric seq-group-by (function sequence)
413   "Apply FUNCTION to each element of SEQUENCE.
414 Separate the elements of SEQUENCE into an alist using the results as
415 keys.  Keys are compared using `equal'."
416   (seq-reduce
417    (lambda (acc elt)
418      (let* ((key (funcall function elt))
419             (cell (assoc key acc)))
420        (if cell
421            (setcdr cell (push elt (cdr cell)))
422          (push (list key elt) acc))
423        acc))
424    (seq-reverse sequence)
425    nil))
426
427 (cl-defgeneric seq-min (sequence)
428   "Return the smallest element of SEQUENCE.
429 SEQUENCE must be a sequence of numbers or markers."
430   (apply #'min (seq-into sequence 'list)))
431
432 (cl-defgeneric seq-max (sequence)
433   "Return the largest element of SEQUENCE.
434 SEQUENCE must be a sequence of numbers or markers."
435   (apply #'max (seq-into sequence 'list)))
436
437 (defun seq--count-successive (pred sequence)
438   "Return the number of successive elements for which (PRED element) is non-nil in SEQUENCE."
439   (let ((n 0)
440         (len (seq-length sequence)))
441     (while (and (< n len)
442                 (funcall pred (seq-elt sequence n)))
443       (setq n (+ 1 n)))
444     n))
445
446 ;;; Optimized implementations for lists
447
448 (cl-defmethod seq-drop ((list list) n)
449   "Optimized implementation of `seq-drop' for lists."
450   (nthcdr n list))
451
452 (cl-defmethod seq-take ((list list) n)
453   "Optimized implementation of `seq-take' for lists."
454   (let ((result '()))
455     (while (and list (> n 0))
456       (setq n (1- n))
457       (push (pop list) result))
458     (nreverse result)))
459
460 (cl-defmethod seq-drop-while (pred (list list))
461   "Optimized implementation of `seq-drop-while' for lists."
462   (while (and list (funcall pred (car list)))
463     (setq list (cdr list)))
464   list)
465
466 (cl-defmethod seq-empty-p ((list list))
467   "Optimized implementation of `seq-empty-p' for lists."
468   (null list))
469
470 \f
471 (defun seq--into-list (sequence)
472   "Concatenate the elements of SEQUENCE into a list."
473   (if (listp sequence)
474       sequence
475     (append sequence nil)))
476
477 (defun seq--into-vector (sequence)
478   "Concatenate the elements of SEQUENCE into a vector."
479   (if (vectorp sequence)
480       sequence
481     (vconcat sequence)))
482
483 (defun seq--into-string (sequence)
484   "Concatenate the elements of SEQUENCE into a string."
485   (if (stringp sequence)
486       sequence
487     (concat sequence)))
488
489 (defun seq--make-pcase-bindings (args)
490   "Return a list of bindings of the variables in ARGS to the elements of a sequence."
491   (let ((bindings '())
492         (index 0)
493         (rest-marker nil))
494     (seq-doseq (name args)
495       (unless rest-marker
496         (pcase name
497           (`&rest
498            (progn (push `(app (pcase--flip seq-drop ,index)
499                               ,(seq--elt-safe args (1+ index)))
500                         bindings)
501                   (setq rest-marker t)))
502           (_
503            (push `(app (pcase--flip seq--elt-safe ,index) ,name) bindings))))
504       (setq index (1+ index)))
505     bindings))
506
507 (defun seq--make-pcase-patterns (args)
508   "Return a list of `(seq ...)' pcase patterns from the argument list ARGS."
509   (cons 'seq
510         (seq-map (lambda (elt)
511                    (if (seqp elt)
512                        (seq--make-pcase-patterns elt)
513                      elt))
514                  args)))
515
516 ;; TODO: make public?
517 (defun seq--elt-safe (sequence n)
518   "Return element of SEQUENCE at the index N.
519 If no element is found, return nil."
520   (ignore-errors (seq-elt sequence n))))
521
522 (cl-defgeneric seq-random-elt (sequence)
523   "Return a random element from SEQUENCE.
524 Signal an error if SEQUENCE is empty."
525   (if (seq-empty-p sequence)
526       (error "Sequence cannot be empty")
527     (seq-elt sequence (random (seq-length sequence)))))
528
529 (provide 'seq-25)
530 ;;; seq-25.el ends here