Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
;;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: SYSTEM -*-
;;;;
;;;; Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
;;;; Copyright (c) 1990, Giuseppe Attardi.
;;;; Copyright (c) 2012, Jean-Claude Beaudoin.
;;;;
;;;; This program is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public
;;;; License as published by the Free Software Foundation; either
;;;; version 3 of the License, or (at your option) any later version.
;;;;
;;;; See file '../../Copyright' for full details.
;;;; sequence routines
(in-package "SYSTEM")
(defun error-sequence-type (type)
(error 'simple-type-error
:datum (vector) ;; Any sequence object will do, because it does not belong to TYPE
:expected-type type
:format-control "~S does not specify a sequence type"
:format-arguments (list type)))
(defun error-sequence-length (object type size)
(error 'simple-type-error
:format-control "Cannot create a sequence of size ~S which matches type ~S."
:format-arguments (list size type)
:expected-type type
:datum object))
(defun closest-sequence-type (type)
(let (elt-type length name args)
(cond ((consp type)
(setq name (first type) args (cdr type)))
((si::instancep type)
(setf name (class-name (the class type)) args nil))
(t
(setq name type args nil)))
(case name
((LIST)
;; This is the only descriptor that does not match a real
;; array type.
(setq elt-type 'LIST length '*))
((VECTOR)
(setq elt-type (if (endp args) 'T (first args))
length (if (endp (rest args)) '* (second args))))
((SIMPLE-VECTOR)
(setq elt-type 'T
length (if (endp args) '* (first args))))
#-unicode
((STRING SIMPLE-STRING)
(setq elt-type 'BASE-CHAR
length (if (endp args) '* (first args))))
#+unicode
((BASE-STRING BASE-SIMPLE-STRING)
(setq elt-type 'BASE-CHAR
length (if (endp args) '* (first args))))
#+unicode
((STRING SIMPLE-STRING)
(setq elt-type 'CHARACTER
length (if (endp args) '* (first args))))
((BIT-VECTOR SIMPLE-BIT-VECTOR)
(setq elt-type 'BIT
length (if (endp args) '* (first args))))
((ARRAY SIMPLE-ARRAY)
(when (or (endp (rest args))
(atom (setq length (second args)))
(endp length)
(not (endp (rest length))))
(error-sequence-type type))
(setq elt-type (upgraded-array-element-type (first args))
length (first (second args))))
(t
;; We arrive here when the sequence type is not easy to parse.
;; We give up trying to guess the length of the sequence.
;; Furthermore, we also give up trying to find if the element
;; type is *. Instead we just compare with some specialized
;; types and otherwise fail.
(dolist (i '(
(NIL . NIL)
(LIST . LIST)
#-unicode
(SIMPLE-STRING . BASE-CHAR)
#-unicode
(STRING . BASE-CHAR)
#+unicode
(SIMPLE-BASE-STRING . BASE-CHAR)
#+unicode
(BASE-STRING . BASE-CHAR)
#+unicode
(SIMPLE-STRING . CHARACTER)
#+unicode
(STRING . CHARACTER)
(BIT-VECTOR . BIT)
((VECTOR MKCL:NATURAL8) . MKCL:NATURAL8)
((VECTOR MKCL:INTEGER8) . MKCL:INTEGER8)
((VECTOR MKCL:CL-INDEX) . MKCL:CL-INDEX)
((VECTOR FIXNUM) . FIXNUM)
((VECTOR SHORT-FLOAT) . SHORT-FLOAT)
((VECTOR LONG-FLOAT) . LONG-FLOAT)
((VECTOR T) . T))
(if (subtypep type 'vector)
;; Does this have to be a type-error?
;; 17.3 for MAKE-SEQUENCE says it should be an error,
;; but does not specialize what kind.
(error "Cannot find the element type in vector type ~S" type)
(error-sequence-type type)))
(when (subtypep type (car i))
(setq elt-type (cdr i) length '*)
;; The (NIL . NIL) case above
(unless elt-type
(error-sequence-type type))
(return)))))
(values elt-type length)))
;; This implementation of make-sequence is severely non-conformant with the specification.
;; It fails miserably at its analysis of the result-type and will produce
;; results that are explicitly prohibited by the specification.
;; FIXME ASAP. JCB
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
(defun make-sequence (type size &key (initial-element nil iesp) &aux sequence)
"Args: (type length &key initial-element)
Creates and returns a sequence of the given TYPE and LENGTH. If INITIAL-
ELEMENT is given, then it becomes the elements of the created sequence. The
default value of INITIAL-ELEMENT depends on TYPE."
(multiple-value-bind (element-type length)
(closest-sequence-type type)
(cond ((eq element-type 'LIST)
(setq sequence (make-list size :initial-element initial-element))
(unless (subtypep 'LIST type)
(when (or (and (subtypep type 'NULL) (plusp size))
(and (subtypep type 'CONS) (zerop size)))
(error-sequence-length (make-list size :initial-element initial-element) type 0))))
(t
(setq sequence (sys:make-vector (if (eq element-type '*) T element-type)
size nil nil nil nil))
(when iesp
(do ((i 0 (1+ i))
(size size))
((>= i size))
(declare (fixnum i size))
(setf (elt sequence i) initial-element)))
(unless (or (eql length '*) (eql length size))
(error-sequence-length sequence type size))))
sequence))
(defun make-seq-iterator (sequence &optional (start 0))
(cond ((null start)
(setf start 0))
((not (integerp start))
(error "Value ~A is not a valid index into sequence ~A" start sequence)))
(cond ((consp sequence)
(nthcdr start sequence))
((>= start (length sequence))
nil)
(t
start)))
(defun seq-iterator-ref (sequence iterator)
(if (si::fixnump iterator)
(elt sequence iterator)
(first iterator)))
(defun seq-iterator-set (sequence iterator value)
(if (si::fixnump iterator)
(setf (elt sequence iterator) value)
(setf (first iterator) value)))
(defun seq-iterator-next (sequence iterator)
;; returns nil on end of sequence (otherwise it's either a cons or a fixnum).
(if (fixnump iterator)
(and (< (incf iterator) (length sequence))
iterator)
(rest iterator)))
#|
;; The only purpose in life of coerce-to-list and coerce-to-vector is
;; to support the expand-coerce mis-optimization in cmpopt.lsp. JCB
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
(defun coerce-to-list (object)
(if (listp object)
object
(do ((it (make-seq-iterator object) (seq-iterator-next object it))
(output nil))
((null it) (nreverse output))
(push (seq-iterator-ref object it) output))))
(defun coerce-to-vector (object elt-type length)
(let ((output object))
(unless (and (vectorp object)
(eq (array-element-type object) elt-type))
(let* ((final-length (if (eq length '*) (length object) length)))
(setf output (make-vector elt-type final-length nil nil nil 0))
(do ((i (make-seq-iterator object) (seq-iterator-next output i))
(j 0 (1+ j)))
((= j final-length)
(setf object output))
(declare (index j))
(setf (aref output j) (seq-iterator-ref object i)))))
(unless (eq length '*)
(unless (= length (length output))
(let ((type `(vector ,elt-type (,length))))
;;(check-type output type "coerced object") ;; check-type does not eval its second argument
;; so this here above could not work.
;; Here is below the manual expansion of check-type fixed for our need.
(unless (typep output type)
(setf output (si::do-check-type output type '"coerced object" 'output)))
)))
output))
|#
#-(and) (defvar *trace-concatenate* nil)
;; This implementation of concatenate relies heavily on make-sequence.
;; Please read comment just above make-sequence.
(defun concatenate (result-type &rest sequences)
"Args: (type &rest sequences)
Returns a new sequence of the specified type, consisting of all elements of
SEQUENCEs."
#-(and)
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
(when *trace-concatenate*
(format t "~&In concatenate for: ~S ~S." result-type sequences))
(do* ((length-list (mapcar #'length sequences) (rest length-list))
(output (make-sequence result-type (apply #'+ length-list)))
(sequences sequences (rest sequences))
(i (make-seq-iterator output)))
((null sequences) output)
(do* ((s (first sequences))
(j (make-seq-iterator s) (seq-iterator-next s j)))
((null j))
(seq-iterator-set output i (seq-iterator-ref s j))
(setq i (seq-iterator-next output i)))))
(defun map (result-type function sequence &rest more-sequences)
"Args: (type function sequence &rest more-sequences)
Creates and returns a sequence of TYPE with K elements, with the N-th element
being the value of applying FUNCTION to the N-th elements of the given
SEQUENCEs, where K is the minimum length of the given SEQUENCEs."
(setq more-sequences (cons sequence more-sequences))
(do* ((l (apply #'min (mapcar #'length more-sequences)))
(it (mapcar #'make-seq-iterator more-sequences))
(val (make-sequence 'list (length more-sequences)))
(x (unless (null result-type) (make-sequence result-type l)))
(ix (unless (null result-type) (make-seq-iterator x))))
(nil)
(do ((i it (cdr i))
(v val (cdr v))
(s more-sequences (cdr s)))
((null i))
(unless (car i) (return-from map x))
(rplaca v (seq-iterator-ref (car s) (car i)))
(rplaca i (seq-iterator-next (car s) (car i))))
(let ((that-value (apply function val)))
(unless (null result-type)
(seq-iterator-set x ix that-value)
(setq ix (seq-iterator-next x ix))))))
(eval-when (eval compile)
(defmacro def-seq-bool-parser (name doc test end-value)
`(defun ,name (predicate sequence &rest more-sequences)
,doc
(setq more-sequences (cons sequence more-sequences))
(do ((it (mapcar #'make-seq-iterator more-sequences))
(val (make-sequence 'list (length more-sequences))))
(nil)
;;(declare (optimize (safety 0)))
(do ((i it (cdr i))
(v val (cdr v))
(s more-sequences (cdr s)))
((null i))
(unless (car i) (return-from ,name ,end-value))
(rplaca v (seq-iterator-ref (car s) (car i)))
(rplaca i (seq-iterator-next (car s) (car i))))
(let ((that-value
(apply predicate val)))
,test)))))
(def-seq-bool-parser some
"Args: (predicate sequence &rest more-sequences)
Returns T if at least one of the elements in SEQUENCEs satisfies PREDICATE;
NIL otherwise."
(when that-value (return that-value))
nil)
(def-seq-bool-parser every
"Args: (predicate sequence &rest more-sequences)
Returns T if every elements of SEQUENCEs satisfy PREDICATE; NIL otherwise."
(unless that-value (return nil))
t)
(defun every* (predicate &rest sequences)
"Args: (predicate sequence &rest more-sequences)
Returns T if every elements of SEQUENCEs satisfy PREDICATE and all sequences
have the same length; NIL otherwise."
(and (apply #'= (mapcar #'length sequences))
(apply #'every predicate sequences)))
(defun notany (predicate sequence &rest more-sequences)
"Args: (predicate sequence &rest more-sequences)
Returns T if none of the elements in SEQUENCEs satisfies PREDICATE; NIL
otherwise."
(not (apply #'some predicate sequence more-sequences)))
(defun notevery (predicate sequence &rest more-sequences)
"Args: (predicate sequence &rest more-sequences)
Returns T if at least one of the elements in SEQUENCEs does not satisfy
PREDICATE; NIL otherwise."
(not (apply #'every predicate sequence more-sequences)))
(defun map-into (result-sequence function &rest sequences)
"Fills the output sequence with the values returned by applying FUNCTION to the
elements of the given sequences. The i-th element of RESULT-SEQUENCE is the output
of applying FUNCTION to the i-th element of each of the sequences. The map routine
stops when it reaches the end of one of the given sequences."
(let ((nel (apply #'min (if (vectorp result-sequence)
(array-dimension result-sequence 0)
(length result-sequence))
(mapcar #'length sequences))))
(declare (fixnum nel))
;; Set the fill pointer to the number of iterations
(when (and (vectorp result-sequence)
(array-has-fill-pointer-p result-sequence))
(setf (fill-pointer result-sequence) nel))
;; Perform mapping
(do ((ir (make-seq-iterator result-sequence) (seq-iterator-next result-sequence ir))
(it (mapcar #'make-seq-iterator sequences))
(val (make-sequence 'list (length sequences))))
((null ir) result-sequence)
(do ((i it (cdr i))
(v val (cdr v))
(s sequences (cdr s)))
((null i))
(unless (car i) (return-from map-into result-sequence))
(rplaca v (seq-iterator-ref (car s) (car i)))
(rplaca i (seq-iterator-next (car s) (car i))))
(seq-iterator-set result-sequence ir (apply function val)))))
;;;;;;;;;;;;;
(defun mkcl::str+ (&rest strings)
(declare (dynamic-extent strings))
(apply #'concatenate 'string strings))
(define-compiler-macro mkcl::str+ (&whole form &rest strings)
`(concatenate 'string ,@strings))
(defun mkcl::bstr+ (&rest strings)
(declare (dynamic-extent strings))
(apply #'concatenate 'base-string strings))
(define-compiler-macro mkcl::bstr+ (&whole form &rest strings)
`(concatenate 'base-string ,@strings))
(defun mkcl::split-string (str delim)
(let ((start 0) (end 0) out)
(declare (fixnum start end))
(dotimes (i (length str) (setq end i))
(declare (fixnum i))
(when (char= delim (char str i))
(setq end i)
(when (> (- end start) 0)
(push (subseq str start end) out))
(setq start (1+ end))
)
)
(when (> (- end start) 0)
(push (subseq str start end) out))
(nreverse out)
)
)
(export '(mkcl::str+ mkcl::bstr+ mkcl::split-string) :mkcl)