Speed up vector extension in VECTOR-PUSH-EXTEND.
[sbcl.git] / src / code / coerce.lisp
blobc72a8ea5a4a4570b74a9ed6b3ca9f8866a144e20
1 ;;;; COERCE and related code
3 ;;;; This software is part of the SBCL system. See the README file for
4 ;;;; more information.
5 ;;;;
6 ;;;; This software is derived from the CMU CL system, which was
7 ;;;; written at Carnegie Mellon University and released into the
8 ;;;; public domain. The software is in the public domain and is
9 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
10 ;;;; files for more information.
12 (in-package "SB!IMPL")
14 (macrolet ((def (name constructor access src-type &optional explicit-check)
15 `(defun ,name (object type)
16 (declare (type ,src-type object))
17 ,@(when explicit-check `((declare (explicit-check))))
18 (do* ((index 0 (1+ index))
19 (length (length object))
20 (result ,constructor)
21 (in-object object))
22 ((>= index length) result)
23 (declare (fixnum length index))
24 (declare (type vector result))
25 (setf (,access result index)
26 ,(ecase src-type
27 (list '(pop in-object))
28 (vector '(aref in-object index))
29 (sequence '(elt in-object index))))))))
31 (def list-to-vector* (make-sequence type length) aref list t)
33 (def vector-to-vector* (make-sequence type length) aref vector t)
35 (def sequence-to-vector* (make-sequence type length) aref sequence))
37 (defun vector-to-list* (object)
38 (declare (type vector object))
39 (dx-let ((result (list nil)))
40 (let ((splice result))
41 (do-vector-data (elt object (cdr result))
42 (let ((cell (list elt)))
43 (setf (cdr splice) cell splice cell))))))
45 (defun sequence-to-list (sequence)
46 (declare (type sequence sequence))
47 (dx-let ((result (list nil)))
48 (let ((splice result))
49 (sb!sequence:dosequence (elt sequence (cdr result))
50 (let ((cell (list elt)))
51 (setf (cdr splice) cell splice cell))))))
53 ;;; These are used both by the full DEFUN function and by various
54 ;;; optimization transforms in the constant-OUTPUT-TYPE-SPEC case.
55 ;;;
56 ;;; Most of them are INLINE so that they can be optimized when the
57 ;;; argument type is known. It might be better to do this with
58 ;;; DEFTRANSFORMs, though.
59 (declaim (inline coerce-to-list))
60 (declaim (inline coerce-to-vector))
62 (defun coerce-symbol-to-fun (symbol)
63 ;; FIXME? I would think to use SYMBOL-FUNCTION here which does not strip off
64 ;; encapsulations. But Stas wrote FDEFINITION so ...
65 ;; [Also note, we won't encapsulate a macro or special-form, so this
66 ;; introspective technique to decide what kind something is works either way]
67 (let ((def (fdefinition symbol)))
68 (if (macro/special-guard-fun-p def)
69 (error (ecase (car (%fun-name def))
70 (:macro "~S names a macro.")
71 (:special "~S names a special operator."))
72 symbol)
73 def)))
75 (defun coerce-to-fun (object)
76 ;; (Unlike the other COERCE-TO-FOOs, this one isn't inline, because
77 ;; it's so big and because optimizing away the outer ETYPECASE
78 ;; doesn't seem to buy us that much anyway.)
79 (etypecase object
80 (function object)
81 (symbol
82 (coerce-symbol-to-fun object))
83 (list
84 (case (first object)
85 (setf
86 (fdefinition object))
87 (lambda
88 (eval object))
90 (error 'simple-type-error
91 :datum object
92 :expected-type '(or symbol
93 ;; KLUDGE: ANSI wants us to
94 ;; return a TYPE-ERROR here, and
95 ;; a TYPE-ERROR is supposed to
96 ;; describe the expected type,
97 ;; but it's not obvious how to
98 ;; describe the coerceable cons
99 ;; types, so we punt and just say
100 ;; CONS. -- WHN 20000503
101 cons)
102 :format-control "~S can't be coerced to a function."
103 :format-arguments (list object)))))))
105 (defun coerce-to-list (object)
106 (seq-dispatch object
107 object
108 (vector-to-list* object)
109 (sequence-to-list object)))
111 (defun coerce-to-vector (object output-type-spec)
112 (etypecase object
113 (list (list-to-vector* object output-type-spec))
114 (vector (vector-to-vector* object output-type-spec))))
116 ;;; old working version
117 (defun coerce (object output-type-spec)
118 #!+sb-doc
119 "Coerce the Object to an object of type Output-Type-Spec."
120 (declare (explicit-check))
121 (flet ((coerce-error ()
122 (error 'simple-type-error
123 :format-control "~S can't be converted to type ~S."
124 :format-arguments (list object output-type-spec)
125 :datum object
126 :expected-type output-type-spec)))
127 (let ((type (specifier-type output-type-spec)))
128 (cond
129 ((%%typep object type)
130 object)
131 ((eq type *empty-type*)
132 (coerce-error))
133 ((type= type (specifier-type 'character))
134 (character object))
135 ((numberp object)
136 (cond
137 ((csubtypep type (specifier-type 'single-float))
138 (let ((res (%single-float object)))
139 (unless (typep res output-type-spec)
140 (coerce-error))
141 res))
142 ((csubtypep type (specifier-type 'double-float))
143 (let ((res (%double-float object)))
144 (unless (typep res output-type-spec)
145 (coerce-error))
146 res))
147 #!+long-float
148 ((csubtypep type (specifier-type 'long-float))
149 (let ((res (%long-float object)))
150 (unless (typep res output-type-spec)
151 (coerce-error))
152 res))
153 ((csubtypep type (specifier-type 'float))
154 (let ((res (%single-float object)))
155 (unless (typep res output-type-spec)
156 (coerce-error))
157 res))
159 (let ((res
160 (cond
161 ((csubtypep type (specifier-type '(complex single-float)))
162 (complex (%single-float (realpart object))
163 (%single-float (imagpart object))))
164 ((csubtypep type (specifier-type '(complex double-float)))
165 (complex (%double-float (realpart object))
166 (%double-float (imagpart object))))
167 #!+long-float
168 ((csubtypep type (specifier-type '(complex long-float)))
169 (complex (%long-float (realpart object))
170 (%long-float (imagpart object))))
171 ((csubtypep type (specifier-type '(complex float)))
172 (complex (%single-float (realpart object))
173 (%single-float (imagpart object))))
174 ((and (typep object 'rational) ; TODO jmoringe unreachable?
175 (csubtypep type (specifier-type '(complex float))))
176 ;; Perhaps somewhat surprisingly, ANSI specifies
177 ;; that (COERCE FOO 'FLOAT) is a SINGLE-FLOAT,
178 ;; not dispatching on
179 ;; *READ-DEFAULT-FLOAT-FORMAT*. By analogy, we
180 ;; do the same for complex numbers. -- CSR,
181 ;; 2002-08-06
182 (complex (%single-float object)))
183 ((csubtypep type (specifier-type 'complex))
184 (complex object))
186 (coerce-error)))))
187 ;; If RES has the wrong type, that means that rule of
188 ;; canonical representation for complex rationals was
189 ;; invoked. According to the Hyperspec, (coerce 7/2
190 ;; 'complex) returns 7/2. Thus, if the object was a
191 ;; rational, there is no error here.
192 (unless (or (typep res output-type-spec)
193 (rationalp object))
194 (coerce-error))
195 res))))
196 ((csubtypep type (specifier-type 'list))
197 (if (vectorp object)
198 (cond
199 ((type= type (specifier-type 'list))
200 (vector-to-list* object))
201 ((type= type (specifier-type 'null))
202 (if (= (length object) 0)
203 'nil
204 (sequence-type-length-mismatch-error type
205 (length object))))
206 ((cons-type-p type)
207 (multiple-value-bind (min exactp)
208 (sb!kernel::cons-type-length-info type)
209 (let ((length (length object)))
210 (if exactp
211 (unless (= length min)
212 (sequence-type-length-mismatch-error type length))
213 (unless (>= length min)
214 (sequence-type-length-mismatch-error type length)))
215 (vector-to-list* object))))
216 (t (sequence-type-too-hairy (type-specifier type))))
217 (if (sequencep object)
218 (cond
219 ((type= type (specifier-type 'list))
220 (sb!sequence:make-sequence-like
221 nil (length object) :initial-contents object))
222 ((type= type (specifier-type 'null))
223 (if (= (length object) 0)
224 'nil
225 (sequence-type-length-mismatch-error type
226 (length object))))
227 ((cons-type-p type)
228 (multiple-value-bind (min exactp)
229 (sb!kernel::cons-type-length-info type)
230 (let ((length (length object)))
231 (if exactp
232 (unless (= length min)
233 (sequence-type-length-mismatch-error type length))
234 (unless (>= length min)
235 (sequence-type-length-mismatch-error type length)))
236 (sb!sequence:make-sequence-like
237 nil length :initial-contents object))))
238 (t (sequence-type-too-hairy (type-specifier type))))
239 (coerce-error))))
240 ((csubtypep type (specifier-type 'vector))
241 (typecase object
242 ;; FOO-TO-VECTOR* go through MAKE-SEQUENCE, so length
243 ;; errors are caught there. -- CSR, 2002-10-18
244 (list (list-to-vector* object output-type-spec))
245 (vector (vector-to-vector* object output-type-spec))
246 (sequence (sequence-to-vector* object output-type-spec))
248 (coerce-error))))
249 ((and (csubtypep type (specifier-type 'sequence))
250 (find-class output-type-spec nil))
251 (let ((prototype (sb!mop:class-prototype
252 (sb!pcl:ensure-class-finalized
253 (find-class output-type-spec)))))
254 (sb!sequence:make-sequence-like
255 prototype (length object) :initial-contents object)))
256 ((csubtypep type (specifier-type 'function))
257 (coerce-to-fun object))
259 (coerce-error))))))
261 ;;; new version, which seems as though it should be better, but which
262 ;;; does not yet work
263 #+nil
264 (defun coerce (object output-type-spec)
265 #!+sb-doc
266 "Coerces the Object to an object of type Output-Type-Spec."
267 (flet ((coerce-error ()
268 (error 'simple-type-error
269 :format-control "~S can't be converted to type ~S."
270 :format-arguments (list object output-type-spec)))
271 (check-result (result)
272 #!+high-security (aver (typep result output-type-spec))
273 result))
274 (let ((type (specifier-type output-type-spec)))
275 (cond
276 ((%%typep object type)
277 object)
278 ((eq type *empty-type*)
279 (coerce-error))
280 ((csubtypep type (specifier-type 'character))
281 (character object))
282 ((csubtypep type (specifier-type 'function))
283 (coerce-to-fun object))
284 ((numberp object)
285 (let ((res
286 (cond
287 ((csubtypep type (specifier-type 'single-float))
288 (%single-float object))
289 ((csubtypep type (specifier-type 'double-float))
290 (%double-float object))
291 #!+long-float
292 ((csubtypep type (specifier-type 'long-float))
293 (%long-float object))
294 ((csubtypep type (specifier-type 'float))
295 (%single-float object))
296 ((csubtypep type (specifier-type '(complex single-float)))
297 (complex (%single-float (realpart object))
298 (%single-float (imagpart object))))
299 ((csubtypep type (specifier-type '(complex double-float)))
300 (complex (%double-float (realpart object))
301 (%double-float (imagpart object))))
302 #!+long-float
303 ((csubtypep type (specifier-type '(complex long-float)))
304 (complex (%long-float (realpart object))
305 (%long-float (imagpart object))))
306 ((csubtypep type (specifier-type 'complex))
307 (complex object))
309 (coerce-error)))))
310 ;; If RES has the wrong type, that means that rule of
311 ;; canonical representation for complex rationals was
312 ;; invoked. According to the ANSI spec, (COERCE 7/2
313 ;; 'COMPLEX) returns 7/2. Thus, if the object was a
314 ;; rational, there is no error here.
315 (unless (or (typep res output-type-spec) (rationalp object))
316 (coerce-error))
317 res))
318 ((csubtypep type (specifier-type 'list))
319 (coerce-to-list object))
320 ((csubtypep type (specifier-type 'string))
321 (check-result (coerce-to-simple-string object)))
322 ((csubtypep type (specifier-type 'bit-vector))
323 (check-result (coerce-to-bit-vector object)))
324 ((csubtypep type (specifier-type 'vector))
325 (check-result (coerce-to-vector object output-type-spec)))
327 (coerce-error))))))