git.fiddlerwoaroof.com
Browse code

Prototype of conforming extensible sequences

Ed Langley authored on 28/01/2019 11:04:05
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,758 @@
1
+;;; Extensible sequences, based on the proposal by Christophe Rhodes.
2
+
3
+;;;; This software is part of the SBCL system. See the README file for
4
+;;;; more information.
5
+
6
+;;;; This software is in the public domain and is provided with
7
+;;;; absolutely no warranty. See the COPYING and CREDITS files for
8
+;;;; more information.
9
+(cl:defpackage :sequence
10
+  (:use)
11
+  (:import-from :cl
12
+                #:type-error-datum #:lambda #:&key #:&optional #:&rest
13
+                #:&whole #:&body #:error #:null #:format #:class-of #:zerop
14
+                #:multiple-value-bind #:cons #:cond #:and #:make-array
15
+                #:array-element-type #:defvar #:defparameter
16
+                #:make-list #:unless #:= #:let #:let* #:t #:make-array
17
+                #:nil #:define-condition #:defun #:if #:eql
18
+                #:setf #:defgeneric #:< #:rplacd #:nthcdr #:fill-pointer
19
+                #:adjust-array #:declare #:ignore #:defmethod
20
+                #:type-error #:apply #:array-total-size #:1- #:-
21
+                #:array-has-fill-pointer-p #:>= #:or #:aref #:1+
22
+                #:values #:car #:cdr #:cddr #:last #:not #:<=
23
+                #:loop #:eq #:do* #:typecase #:gensym #:push
24
+                #:mapcar #:defmacro #:fdefinition #:complement
25
+                #:functionp #:flet #:list* #:funcall #:setq #:incf
26
+                #:when #:do #:identity #:return #:floor #:ceiling #:+
27
+                #:return-from #:> #:+ #:dotimes #:labels #:function
28
+                #:ignorable #:prog1 #:minusp #:progn #:type #:the)
29
+  (:export #:protocol-unimplemented #:protocol-unimplemented-operation
30
+           #:merge #:with-sequence-iterator-functions #:make-sequence-like
31
+           #:missing-arg #:emptyp #:length #:elt #:adjust-sequence
32
+           #:make-sequence-iterator #:make-list-iterator #:make-vector-iterator
33
+           #:make-simple-sequence-iterator #:iterator-step #:iterator-endp
34
+           #:iterator-element #:iterator-index #:iterator-copy
35
+           #:with-sequence-iterator #:find-if-not #:position #:position-if-not
36
+           #:position-if #:subseq #:copy-seq #:fill #:nsubstitute
37
+           #:nsubstitute-if #:nsubstitute-if-not #:substitute #:substitute-if
38
+           #:substitute-if-not #:replace #:nreverse #:reverse #:concatenate
39
+           #:reduce #:mismatch #:search #:delete #:delete-if #:delete-if-not
40
+           #:remove #:remove-if #:remove-if-not #:delete-duplicates
41
+           #:remove-duplicates #:sort #:stable-sort))
42
+(uiop:define-package :gen-cl-user
43
+    (:mix :sequence :cl))
44
+
45
+(cl:in-package :sequence)
46
+
47
+(defun missing-arg ()
48
+  (error "A required &KEY or &OPTIONAL argument was not supplied."))
49
+
50
+
51
+;;;; basic protocol
52
+(define-condition protocol-unimplemented (type-error
53
+                                          #+sbcl reference-condition)
54
+  ((operation :initarg :operation
55
+              :reader protocol-unimplemented-operation))
56
+  (:default-initargs
57
+   :operation (missing-arg)
58
+    :references '((:sbcl :node "Extensible Sequences")))
59
+  (:report
60
+   (lambda (condition stream)
61
+     (let ((operation (protocol-unimplemented-operation condition))
62
+           (datum (type-error-datum condition)))
63
+       (format stream "~@<The operation ~
64
+                       ~/sb-ext:print-symbol-with-prefix/ is not ~
65
+                       implemented for ~A which is an instance of the ~
66
+                       ~/sb-ext:print-symbol-with-prefix/ subclass ~
67
+                       ~S.~@:>"
68
+               operation datum 'sequence (class-of datum)))))
69
+  (:documentation
70
+   "This error is signaled if a sequence operation is applied to an
71
+   instance of a sequence class that does not support the
72
+   operation."))
73
+
74
+(defun protocol-unimplemented (operation sequence)
75
+  (error 'protocol-unimplemented
76
+         :datum sequence
77
+         :expected-type '(or list vector)
78
+         :operation operation))
79
+
80
+(defgeneric emptyp (sequence)
81
+  (:method ((s cl:list)) (null s))
82
+  (:method ((s cl:vector)) (zerop (cl:length s)))
83
+  (:method ((s cl:sequence)) (zerop (cl:length s)))
84
+  (:documentation
85
+   "Returns T if SEQUENCE is an empty sequence and NIL
86
+   otherwise. Signals an error if SEQUENCE is not a sequence."))
87
+
88
+(defgeneric length (sequence)
89
+  (:method ((s cl:list)) (cl:length s))
90
+  (:method ((s cl:vector)) (cl:length s))
91
+  (:method ((s cl:sequence))
92
+    (protocol-unimplemented 'length s))
93
+  (:documentation
94
+   "Returns the length of SEQUENCE or signals a PROTOCOL-UNIMPLEMENTED
95
+   error if the sequence protocol is not implemented for the class of
96
+   SEQUENCE."))
97
+
98
+(defgeneric elt (sequence index)
99
+  (:method ((s cl:list) index) (cl:elt s index))
100
+  (:method ((s cl:vector) index) (cl:elt s index))
101
+  (:method ((s cl:sequence) index)
102
+    (cl:declare (cl:ignore index))
103
+    (protocol-unimplemented 'elt s))
104
+  (:documentation
105
+   "Returns the element at position INDEX of SEQUENCE or signals a
106
+   PROTOCOL-UNIMPLEMENTED error if the sequence protocol is not
107
+   implemented for the class of SEQUENCE."))
108
+
109
+(defgeneric (setf elt) (new-value sequence index)
110
+  (:argument-precedence-order sequence new-value index)
111
+  (:method (new-value (s cl:list) index) (setf (cl:elt s index) new-value))
112
+  (:method (new-value (s cl:vector) index) (setf (cl:elt s index) new-value))
113
+  (:method (new-value (s cl:sequence) index)
114
+    (cl:declare (cl:ignore index new-value))
115
+    (protocol-unimplemented '(setf elt) s))
116
+  (:documentation
117
+   "Replaces the element at position INDEX of SEQUENCE with NEW-VALUE
118
+   and returns NEW-VALUE or signals a PROTOCOL-UNIMPLEMENTED error if
119
+   the sequence protocol is not implemented for the class of
120
+   SEQUENCE."))
121
+
122
+(defgeneric make-sequence-like
123
+    (sequence length &key initial-element initial-contents)
124
+  (:method ((s cl:list) length
125
+            &key (initial-element nil iep) (initial-contents nil icp))
126
+    (cond
127
+      ((and icp iep) (error "supplied both ~S and ~S to ~S"
128
+                            :initial-element
129
+                            :initial-contents
130
+                            'make-sequence-like))
131
+      (iep (make-list length :initial-element initial-element))
132
+      (icp (unless (= (length initial-contents) length)
133
+             (error "length mismatch in ~S" 'make-sequence-like))
134
+           (let ((result (make-list length)))
135
+             (replace result initial-contents)
136
+             result))
137
+      (t (make-list length))))
138
+  (:method ((s cl:vector) length
139
+            &key (initial-element nil iep) (initial-contents nil icp))
140
+    (cond
141
+      ((and icp iep) (error "supplied both ~S and ~S to ~S"
142
+                            :initial-element
143
+                            :initial-contents
144
+                            'make-sequence-like))
145
+      (iep (make-array length :element-type (array-element-type s)
146
+                       :initial-element initial-element))
147
+      (icp (make-array length :element-type (array-element-type s)
148
+                       :initial-contents initial-contents))
149
+      (t (make-array length :element-type (array-element-type s)))))
150
+  (:method ((s cl:sequence) length &key initial-element initial-contents)
151
+    (cl:declare (cl:ignore initial-element initial-contents length))
152
+    (protocol-unimplemented 'make-sequence-like s))
153
+  (:documentation
154
+   "Returns a freshly allocated sequence of length LENGTH and of the
155
+   same class as SEQUENCE. Elements of the new sequence are
156
+   initialized to INITIAL-ELEMENT, if supplied, initialized to
157
+   INITIAL-CONTENTS if supplied, or identical to the elements of
158
+   SEQUENCE if neither is supplied. Signals a PROTOCOL-UNIMPLEMENTED
159
+   error if the sequence protocol is not implemented for the class of
160
+   SEQUENCE."))
161
+
162
+(defgeneric adjust-sequence
163
+    (sequence length &key initial-element initial-contents)
164
+  (:method ((s cl:list) length &key initial-element (initial-contents nil icp))
165
+    (if (eql length 0)
166
+        nil
167
+        (let ((olength (length s)))
168
+          (cond
169
+            ((eql length olength) (if icp (replace s initial-contents) s))
170
+            ((< length olength)
171
+             (rplacd (nthcdr (1- length) s) nil)
172
+             (if icp (replace s initial-contents) s))
173
+            ((null s)
174
+             (let ((return (make-list length :initial-element initial-element)))
175
+               (if icp (replace return initial-contents) return)))
176
+            (t (rplacd (nthcdr (1- olength) s)
177
+                       (make-list (- length olength)
178
+                                  :initial-element initial-element))
179
+               (if icp (replace s initial-contents) s))))))
180
+  (:method ((s cl:vector) length
181
+            &rest args &key (initial-contents nil icp) initial-element)
182
+    (declare (ignore initial-element))
183
+    (cond
184
+      ((and (array-has-fill-pointer-p s)
185
+            (>= (array-total-size s) length))
186
+       (setf (fill-pointer s) length)
187
+       (if icp (replace s initial-contents) s))
188
+      ((eql (length s) length)
189
+       (if icp (replace s initial-contents) s))
190
+      (t (apply #'adjust-array s length args))))
191
+  (:method ((s cl:sequence) length &rest args)
192
+    (declare (ignore args length))
193
+    (protocol-unimplemented 'adjust-sequence s))
194
+  (:documentation
195
+   "Return destructively modified SEQUENCE or a freshly allocated
196
+   sequence of the same class as SEQUENCE of length LENGTH. Elements
197
+   of the returned sequence are initialized to INITIAL-ELEMENT, if
198
+   supplied, initialized to INITIAL-CONTENTS if supplied, or identical
199
+   to the elements of SEQUENCE if neither is supplied. Signals a
200
+   PROTOCOL-UNIMPLEMENTED error if the sequence protocol is not
201
+   implemented for the class of SEQUENCE."))
202
+
203
+
204
+;;;; iterator protocol
205
+
206
+;;; The general protocol
207
+
208
+(defgeneric make-sequence-iterator (sequence &key from-end start end)
209
+  (:method ((s cl:vector) &key from-end (start 0) end)
210
+    (make-vector-iterator s from-end start end))
211
+  (:method ((s cl:list) &key from-end (start 0) end)
212
+    (make-list-iterator s from-end start end))
213
+  (:method ((s cl:sequence) &key from-end (start 0) end)
214
+    (multiple-value-bind (iterator limit from-end)
215
+        (make-simple-sequence-iterator
216
+         s :from-end from-end :start start :end end)
217
+      (values iterator limit from-end
218
+              #'iterator-step #'iterator-endp
219
+              #'iterator-element #'(setf iterator-element)
220
+              #'iterator-index #'iterator-copy)))
221
+  (:method ((s t) &key from-end start end)
222
+    (declare (ignore from-end start end))
223
+    (error 'type-error
224
+           :datum s
225
+           :expected-type 'sequence))
226
+  (:documentation
227
+   "Returns a sequence iterator for SEQUENCE or, if START and/or END
228
+   are supplied, the subsequence bounded by START and END as nine
229
+   values:
230
+
231
+   1. iterator state
232
+   2. limit
233
+   3. from-end
234
+   4. step function
235
+   5. endp function
236
+   6. element function
237
+   7. setf element function
238
+   8. index function
239
+   9. copy state function
240
+
241
+   If FROM-END is NIL, the constructed iterator visits the specified
242
+   elements in the order in which they appear in SEQUENCE. Otherwise,
243
+   the elements are visited in the opposite order."))
244
+
245
+;;; magic termination value for list :from-end t
246
+(defvar *exhausted* (cons nil nil))
247
+
248
+(defun make-list-iterator (list from-end start end)
249
+  (multiple-value-bind (iterator limit from-end)
250
+      (if from-end
251
+          (let* ((termination (if (= start 0) *exhausted* (nthcdr (1- start) list)))
252
+                 (init (if (<= (or end (cl:length list)) start)
253
+                           termination
254
+                           (if end
255
+                               (last list (- (cl:length list)
256
+                                             (1- end)))
257
+                               (last list)))))
258
+            (values init termination t))
259
+          (cond
260
+            ((not end) (values (nthcdr start list) nil nil))
261
+            (t (let ((st (nthcdr start list)))
262
+                 (values st (nthcdr (- end start) st) nil)))))
263
+    (values iterator limit from-end
264
+            (if from-end
265
+                (lambda (list iterator from-end)
266
+                  (declare (ignore from-end))
267
+                  (if (eq iterator list)
268
+                      *exhausted*
269
+                      (do* ((cdr list (cdr cdr)))
270
+                           ((eq (cdr cdr) iterator) cdr)))
271
+                  (1+ iterator))
272
+                (lambda (list iterator from-end)
273
+                  (declare (ignore list from-end))
274
+                  (cdr iterator)))
275
+            (lambda (list iterator limit from-end)
276
+              (declare (ignore list from-end))
277
+              (eq iterator limit))
278
+            (lambda (list iterator)
279
+              (declare (ignore list))
280
+              (car iterator))
281
+            (lambda (new-value list iterator)
282
+              (declare (ignore list))
283
+              (setf (car iterator) new-value))
284
+            (lambda (list iterator)
285
+              (loop for cdr on list
286
+                 for i from 0
287
+                 when (eq cdr iterator)
288
+                 return i))
289
+            (lambda (list iterator)
290
+              (declare (ignore list))
291
+              iterator))))
292
+
293
+(defun make-vector-iterator (vector from-end start end)
294
+  (let* ((end (or end (length vector)))
295
+         (iterator (if from-end
296
+                       (1- end)
297
+                       start))
298
+         (limit (if from-end
299
+                    (1- start)
300
+                    end)))
301
+    (values iterator limit from-end
302
+            (if from-end
303
+                (lambda (sequence iterator from-end)
304
+                  (declare (ignore sequence from-end))
305
+                  (1- iterator))
306
+                (lambda (sequence iterator from-end)
307
+                  (declare (ignore sequence from-end))
308
+                  (1+ iterator)))
309
+            (lambda (sequence iterator limit from-end)
310
+              (declare (ignore sequence from-end))
311
+              (= iterator limit))
312
+            (lambda (sequence iterator)
313
+              (aref sequence iterator))
314
+            (lambda (new-value sequence iterator)
315
+              (setf (aref sequence iterator) new-value))
316
+            (lambda (sequence iterator)
317
+              (declare (ignore sequence))
318
+              iterator)
319
+            (lambda (sequence iterator)
320
+              (declare (ignore sequence))
321
+              iterator))))
322
+
323
+;;; the simple protocol: the simple iterator returns three values,
324
+;;; STATE, LIMIT and FROM-END.
325
+(defgeneric make-simple-sequence-iterator
326
+    (sequence &key from-end start end)
327
+  (:method ((s cl:list) &key from-end (start 0) end)
328
+    (if from-end
329
+        (let* ((termination (if (= start 0) *exhausted* (nthcdr (1- start) s)))
330
+               (init (if (<= (or end (length s)) start)
331
+                         termination
332
+                         (if end (last s (- (length s) (1- end))) (last s)))))
333
+          (values init termination t))
334
+        (cond
335
+          ((not end) (values (nthcdr start s) nil nil))
336
+          (t (let ((st (nthcdr start s)))
337
+               (values st (nthcdr (- end start) st) nil))))))
338
+  (:method ((s cl:vector) &key from-end (start 0) end)
339
+    (let ((end (or end (length s))))
340
+      (if from-end
341
+          (values (1- end) (1- start) t)
342
+          (values start end nil))))
343
+  (:method ((s cl:sequence) &key from-end (start 0) end)
344
+    (let ((end (or end (length s))))
345
+      (if from-end
346
+          (values (1- end) (1- start) from-end)
347
+          (values start end nil))))
348
+  (:documentation
349
+   "Returns a sequence iterator for SEQUENCE, START, END and FROM-END
350
+   as three values:
351
+
352
+   1. iterator state
353
+   2. limit
354
+   3. from-end
355
+
356
+   The returned iterator can be used with the generic iterator
357
+   functions ITERATOR-STEP, ITERATOR-ENDP, ITERATOR-ELEMENT, (SETF
358
+   ITERATOR-ELEMENT), ITERATOR-INDEX and ITERATOR-COPY."))
359
+
360
+(defgeneric iterator-step (sequence iterator from-end)
361
+  (:method ((s cl:list) iterator from-end)
362
+    (if from-end
363
+        (if (eq iterator s)
364
+            *exhausted*
365
+            (do* ((xs s (cdr xs)))
366
+                 ((eq (cdr xs) iterator) xs)))
367
+        (cdr iterator)))
368
+  (:method ((s cl:vector) iterator from-end)
369
+    (if from-end
370
+        (1- iterator)
371
+        (1+ iterator)))
372
+  (:method ((s cl:sequence) iterator from-end)
373
+    (if from-end
374
+        (1- iterator)
375
+        (1+ iterator)))
376
+  (:documentation
377
+   "Moves ITERATOR one position forward or backward in SEQUENCE
378
+   depending on the iteration direction encoded in FROM-END."))
379
+
380
+(defgeneric iterator-endp (sequence iterator limit from-end)
381
+  (:method ((s cl:list) iterator limit from-end)
382
+    (declare (ignore from-end))
383
+    (eq iterator limit))
384
+  (:method ((s cl:vector) iterator limit from-end)
385
+    (declare (ignore from-end))
386
+    (= iterator limit))
387
+  (:method ((s cl:sequence) iterator limit from-end)
388
+    (declare (ignore from-end))
389
+    (= iterator limit))
390
+  (:documentation
391
+   "Returns non-NIL when ITERATOR has reached LIMIT (which may
392
+   correspond to the end of SEQUENCE) with respect to the iteration
393
+   direction encoded in FROM-END."))
394
+
395
+(defgeneric iterator-element (sequence iterator)
396
+  (:method ((s cl:list) iterator)
397
+    (car iterator))
398
+  (:method ((s cl:vector) iterator)
399
+    (aref s iterator))
400
+  (:method ((s cl:sequence) iterator)
401
+    (elt s iterator))
402
+  (:documentation
403
+   "Returns the element of SEQUENCE associated to the position of
404
+   ITERATOR."))
405
+
406
+(defgeneric (setf iterator-element) (new-value sequence iterator)
407
+  (:method (o (s cl:list) iterator)
408
+    (setf (car iterator) o))
409
+  (:method (o (s cl:vector) iterator)
410
+    (setf (aref s iterator) o))
411
+  (:method (o (s cl:sequence) iterator)
412
+    (setf (elt s iterator) o))
413
+  (:documentation
414
+   "Destructively modifies SEQUENCE by replacing the sequence element
415
+   associated to position of ITERATOR with NEW-VALUE."))
416
+
417
+(defgeneric iterator-index (sequence iterator)
418
+  (:method ((s cl:list) iterator)
419
+    ;; FIXME: this sucks.  (In my defence, it is the equivalent of the
420
+    ;; Apple implementation in Dylan...)
421
+    (loop for l on s for i from 0 when (eq l iterator) return i))
422
+  (:method ((s cl:vector) iterator) iterator)
423
+  (:method ((s cl:sequence) iterator) iterator)
424
+  (:documentation
425
+   "Returns the position of ITERATOR in SEQUENCE."))
426
+
427
+(defgeneric iterator-copy (sequence iterator)
428
+  (:method ((s cl:list) iterator) iterator)
429
+  (:method ((s cl:vector) iterator) iterator)
430
+  (:method ((s cl:sequence) iterator) iterator)
431
+  (:documentation
432
+   "Returns a copy of ITERATOR which also traverses SEQUENCE but can
433
+   be mutated independently of ITERATOR."))
434
+
435
+(defun %make-sequence-iterator (sequence from-end start end)
436
+  (typecase sequence
437
+    (cl:vector
438
+     (make-vector-iterator sequence from-end start end))
439
+    (cl:list
440
+     (make-list-iterator sequence from-end start end))
441
+    (t
442
+     (make-sequence-iterator sequence
443
+                             :end end
444
+                             :start start
445
+                             :from-end from-end))))
446
+
447
+(defmacro with-sequence-iterator
448
+    ((&whole vars
449
+             &optional iterator limit from-end-p
450
+             step endp element set-element index copy)
451
+               (sequence &key from-end (start 0) end) &body body)
452
+  "Executes BODY with the elements of VARS bound to the iteration
453
+  state returned by MAKE-SEQUENCE-ITERATOR for SEQUENCE and
454
+  ARGS. Elements of VARS may be NIL in which case the corresponding
455
+  value returned by MAKE-SEQUENCE-ITERATOR is ignored."
456
+  (declare (ignore iterator limit from-end-p
457
+                   step endp element set-element index copy))
458
+  (let* ((ignored '())
459
+         (vars (mapcar (lambda (x)
460
+                         (or x (let ((name (gensym)))
461
+                                 (push name ignored)
462
+                                 name)))
463
+                       vars)))
464
+    `(multiple-value-bind (,@vars)
465
+         (%make-sequence-iterator ,sequence ,from-end ,start ,end)
466
+       (declare (cl:type function ,@(nthcdr 3 vars))
467
+                (ignore ,@ignored))
468
+       ,@body)))
469
+
470
+(defmacro with-sequence-iterator-functions
471
+    ((step endp elt setf index copy)
472
+     (sequence &rest args &key from-end start end)
473
+     &body body)
474
+  "Executes BODY with the names STEP, ENDP, ELT, SETF, INDEX and COPY
475
+  bound to local functions which execute the iteration state query and
476
+  mutation functions returned by MAKE-SEQUENCE-ITERATOR for SEQUENCE
477
+  and ARGS. STEP, ENDP, ELT, SETF, INDEX and COPY have dynamic
478
+  extent."
479
+  (declare (ignore from-end start end))
480
+  (let ((nstate (gensym "STATE")) (nlimit (gensym "LIMIT"))
481
+        (nfrom-end (gensym "FROM-END-")) (nstep (gensym "STEP"))
482
+        (nendp (gensym "ENDP")) (nelt (gensym "ELT"))
483
+        (nsetf (gensym "SETF")) (nindex (gensym "INDEX"))
484
+        (ncopy (gensym "COPY")))
485
+    `(with-sequence-iterator
486
+         (,nstate ,nlimit ,nfrom-end ,nstep ,nendp ,nelt ,nsetf ,nindex ,ncopy)
487
+         (,sequence,@args)
488
+       (declare (cl:ignorable ,nstate ,nlimit ,nfrom-end ,nstep ,nendp ,nelt ,nsetf ,nindex ,ncopy))
489
+       (flet ((,step () (setq ,nstate (funcall ,nstep ,sequence,nstate ,nfrom-end)))
490
+              (,endp () (funcall ,nendp ,sequence,nstate ,nlimit ,nfrom-end))
491
+              (,elt () (funcall ,nelt ,sequence,nstate))
492
+              (,setf (new-value) (funcall ,nsetf new-value ,sequence,nstate))
493
+              (,index () (funcall ,nindex ,sequence,nstate))
494
+              (,copy () (funcall ,ncopy ,sequence,nstate)))
495
+         (declare (cl:dynamic-extent #',step #',endp #',elt
496
+                                     #',setf #',index #',copy))
497
+         ,@body))))
498
+
499
+(defmacro define-shadowing-generic (name (&rest args) &body options)
500
+  (let* ((seq-position (cl:position 'sequence args))
501
+         (pre-args (cl:subseq args 0 seq-position))
502
+         (raw-post-args (cl:subseq args (1+ seq-position)))
503
+         (cl-name (cl:intern (cl:symbol-name name) :cl))
504
+         (tail (cl:member #\& raw-post-args
505
+                          :key (lambda (x)
506
+                                 (cl:elt (cl:symbol-name x)
507
+                                         0))))
508
+         (post-args (if (and tail (not (eql (car tail) '&optional)))
509
+                        `(,@(loop for x in raw-post-args
510
+                               for rest on raw-post-args
511
+                               while (not (eq rest tail))
512
+                               collect x)
513
+                            &rest r)
514
+                        raw-post-args)))
515
+    (unless seq-position
516
+      (error "no sequence argument"))
517
+    `(defgeneric ,name ,args
518
+       (:method (,@pre-args (sequence cl:sequence) ,@post-args)
519
+         (declare (cl:inline))
520
+         (apply #',cl-name ,@pre-args sequence
521
+                ,@(cl:remove #\& post-args
522
+                             :key (lambda (x)
523
+                                    (cl:elt (cl:symbol-name x)
524
+                                            0)))))
525
+       ,@options)))
526
+
527
+(define-shadowing-generic find-if-not
528
+    (pred sequence &key from-end start end key)
529
+  (:argument-precedence-order sequence pred))
530
+
531
+(define-shadowing-generic position
532
+    (item sequence &key from-end start end test test-not key)
533
+  (:argument-precedence-order sequence item))
534
+
535
+
536
+(define-shadowing-generic position-if (pred sequence &key from-end start end key)
537
+  (:argument-precedence-order sequence pred))
538
+
539
+
540
+(define-shadowing-generic position-if-not
541
+    (pred sequence &key from-end start end key)
542
+  (:argument-precedence-order sequence pred))
543
+
544
+
545
+(define-shadowing-generic subseq (sequence start &optional end))
546
+
547
+
548
+(define-shadowing-generic copy-seq (sequence))
549
+
550
+
551
+(define-shadowing-generic fill (sequence item &key start end))
552
+
553
+
554
+(define-shadowing-generic nsubstitute
555
+    (new old sequence &key start end from-end test test-not count key)
556
+  (:argument-precedence-order sequence new old))
557
+
558
+
559
+(define-shadowing-generic nsubstitute-if
560
+    (new predicate sequence &key start end from-end count key)
561
+  (:argument-precedence-order sequence new predicate))
562
+
563
+
564
+(define-shadowing-generic nsubstitute-if-not
565
+    (new predicate sequence &key start end from-end count key)
566
+  (:argument-precedence-order sequence new predicate))
567
+
568
+
569
+(define-shadowing-generic substitute
570
+    (new old sequence &key start end from-end test test-not count key)
571
+  (:argument-precedence-order sequence new old))
572
+
573
+
574
+(define-shadowing-generic substitute-if
575
+    (new predicate sequence &key start end from-end count key)
576
+  (:argument-precedence-order sequence new predicate))
577
+
578
+
579
+(define-shadowing-generic substitute-if-not
580
+    (new predicate sequence &key start end from-end count key)
581
+  (:argument-precedence-order sequence new predicate))
582
+
583
+
584
+(defun %sequence-replace (sequence1 sequence2 start1 end1 start2 end2)
585
+  (with-sequence-iterator (state1 limit1 from-end1 step1 endp1 elt1 setelt1)
586
+      (sequence1 :start start1 :end end1)
587
+    (declare (ignore elt1))
588
+    (with-sequence-iterator (state2 limit2 from-end2 step2 endp2 elt2)
589
+        (sequence2 :start start2 :end end2)
590
+      (do ()
591
+          ((or (funcall endp1 sequence1 state1 limit1 from-end1)
592
+               (funcall endp2 sequence2 state2 limit2 from-end2))
593
+           sequence1)
594
+        (funcall setelt1 (funcall elt2 sequence2 state2) sequence1 state1)
595
+        (setq state1 (funcall step1 sequence1 state1 from-end1))
596
+        (setq state2 (funcall step2 sequence2 state2 from-end2))))))
597
+
598
+(defgeneric replace
599
+    (sequence1 sequence2 &key start1 end1 start2 end2)
600
+  (:argument-precedence-order sequence2 sequence1))
601
+
602
+
603
+(define-shadowing-generic nreverse (sequence))
604
+
605
+
606
+(define-shadowing-generic reverse (sequence))
607
+
608
+
609
+(defgeneric concatenate (result-prototype &rest sequences)
610
+  (:documentation
611
+   "Implements CL:CONCATENATE for extended sequences.
612
+
613
+    RESULT-PROTOTYPE corresponds to the RESULT-TYPE of CL:CONCATENATE
614
+    but receives a prototype instance of an extended sequence class
615
+    instead of a type specifier. By dispatching on RESULT-PROTOTYPE,
616
+    methods on this generic function specify how extended sequence
617
+    classes act when they are specified as the result type in a
618
+    CL:CONCATENATE call. RESULT-PROTOTYPE may not be fully initialized
619
+    and thus should only be used for dispatch and to determine its
620
+    class."))
621
+
622
+
623
+
624
+(define-shadowing-generic reduce
625
+    (function sequence &key from-end start end initial-value)
626
+  (:argument-precedence-order sequence function))
627
+
628
+
629
+(defgeneric mismatch (sequence1 sequence2 &key from-end start1 end1
630
+                                            start2 end2 test test-not key))
631
+
632
+
633
+(defgeneric search (sequence1 sequence2 &key from-end start1 end1
634
+                                          start2 end2 test test-not key))
635
+
636
+
637
+(define-shadowing-generic delete
638
+    (item sequence &key from-end test test-not start end count key)
639
+  (:argument-precedence-order sequence item))
640
+
641
+
642
+(define-shadowing-generic delete-if
643
+    (predicate sequence &key from-end start end count key)
644
+  (:argument-precedence-order sequence predicate))
645
+
646
+
647
+(define-shadowing-generic delete-if-not
648
+    (predicate sequence &key from-end start end count key)
649
+  (:argument-precedence-order sequence predicate))
650
+
651
+
652
+(define-shadowing-generic remove
653
+    (item sequence &key from-end test test-not start end count key)
654
+  (:argument-precedence-order sequence item))
655
+
656
+
657
+(define-shadowing-generic remove-if
658
+    (predicate sequence &key from-end start end count key)
659
+  (:argument-precedence-order sequence predicate))
660
+
661
+
662
+(define-shadowing-generic remove-if-not
663
+    (predicate sequence &key from-end start end count key)
664
+  (:argument-precedence-order sequence predicate))
665
+
666
+
667
+(define-shadowing-generic delete-duplicates
668
+    (sequence &key from-end test test-not start end key))
669
+
670
+
671
+(define-shadowing-generic remove-duplicates
672
+    (sequence &key from-end test test-not start end key))
673
+
674
+(define-shadowing-generic sort (sequence predicate &key key))
675
+
676
+
677
+(define-shadowing-generic stable-sort (sequence predicate &key key))
678
+
679
+
680
+(defgeneric merge (result-prototype sequence1 sequence2 predicate &key key)
681
+  (:documentation
682
+   "Implements CL:MERGE for extended sequences.
683
+
684
+    RESULT-PROTOTYPE corresponds to the RESULT-TYPE of CL:MERGE but
685
+    receives a prototype instance of an extended sequence class
686
+    instead of a type specifier. By dispatching on RESULT-PROTOTYPE,
687
+    methods on this generic function specify how extended sequence
688
+    classes act when they are specified as the result type in a
689
+    CL:MERGE call. RESULT-PROTOTYPE may not be fully initialized and
690
+    thus should only be used for dispatch and to determine its class.
691
+
692
+    Another difference to CL:MERGE is that PREDICATE is a function,
693
+    not a function designator."))
694
+
695
+(defun %coerce-callable-to-fun (callable)
696
+  (cl:etypecase callable
697
+    (function callable)
698
+    (cl:symbol (cl:symbol-function callable))))
699
+
700
+(defmethod sequence:merge ((result-prototype cl:sequence) (sequence1 cl:sequence) (sequence2 cl:sequence)
701
+                           (predicate cl:function) &key key)
702
+  (let ((key-function (when key
703
+                        (%coerce-callable-to-fun key)))
704
+        (result (sequence:make-sequence-like
705
+                 result-prototype (+ (length sequence1) (length sequence2))))
706
+        endp1 elt1 key1 endp2 elt2 key2)
707
+    (sequence:with-sequence-iterator-functions
708
+        (step-result endp-result elt-result setelt-result index-result copy-result) (result)
709
+      ;; TODO allow nil and fewer number of elements
710
+      (declare (ignorable #'endp-result #'elt-result #'copy-result))
711
+      (sequence:with-sequence-iterator-functions
712
+          (step1 endp1 elt1 setelt1 index1 copy1) (sequence1)
713
+        (declare (ignorable #'setelt1 #'copy1))
714
+        (sequence:with-sequence-iterator-functions
715
+            (step2 endp2 elt2 setelt2 index2 copy2) (sequence2)
716
+          (declare (ignorable #'setelt2 #'copy2))
717
+          (labels ((pop/no-key1 ()
718
+                     (unless (setf endp1 (endp1))
719
+                       (setf elt1 (elt1))))
720
+                   (pop/no-key2 ()
721
+                     (unless (setf endp2 (endp2))
722
+                       (setf elt2 (elt2))))
723
+                   (pop/key1 ()
724
+                     (unless (setf endp1 (endp1))
725
+                       (setf key1 (funcall (the function key-function)
726
+                                           (setf elt1 (elt1))))))
727
+                   (pop/key2 ()
728
+                     (unless (setf endp2 (endp2))
729
+                       (setf key2 (funcall (the function key-function)
730
+                                           (setf elt2 (elt2))))))
731
+                   (pop-one/no-key ()
732
+                     (if (funcall predicate elt2 elt1) ; see comment in MERGE-LIST*
733
+                         (prog1 elt2 (step2) (pop/no-key2))
734
+                         (prog1 elt1 (step1) (pop/no-key1))))
735
+                   (pop-one/key ()
736
+                     (if (funcall predicate key2 key1)
737
+                         (prog1 elt2 (step2) (pop/key2))
738
+                         (prog1 elt1 (step1) (pop/key1)))))
739
+            (declare (cl:dynamic-extent #'pop/no-key1 #'pop/no-key2
740
+                                        #'pop/key1 #'pop/key2
741
+                                        #'pop-one/no-key #'pop-one/key))
742
+            ;; Populate ENDP{1,2}, ELT{1,2} and maybe KEY{1,2}.
743
+            (cond (key-function (pop/key1) (pop/key2))
744
+                  (t (pop/no-key1) (pop/no-key2)))
745
+            (loop with pop-one = (if key-function #'pop-one/key #'pop-one/no-key) do
746
+                 (cond
747
+                   (endp2 ; batch-replace rest of SEQUENCE1 if SEQUENCE2 exhausted
748
+                    (unless endp1
749
+                      (replace result sequence1 :start1 (index-result) :start2 (index1)))
750
+                    (return))
751
+                   (endp1
752
+                    (unless endp2
753
+                      (replace result sequence2 :start1 (index-result) :start2 (index2)))
754
+                    (return))
755
+                   (t
756
+                    (setelt-result (funcall pop-one))
757
+                    (step-result))))))))
758
+    result))