1 ;; Common Lisp bindings for GTK+ 2.x
2 ;; Copyright 1999-2006 Espen S. Johnsen <espen@users.sf.net>
4 ;; Permission is hereby granted, free of charge, to any person obtaining
5 ;; a copy of this software and associated documentation files (the
6 ;; "Software"), to deal in the Software without restriction, including
7 ;; without limitation the rights to use, copy, modify, merge, publish,
8 ;; distribute, sublicense, and/or sell copies of the Software, and to
9 ;; permit persons to whom the Software is furnished to do so, subject to
10 ;; the following conditions:
12 ;; The above copyright notice and this permission notice shall be
13 ;; included in all copies or substantial portions of the Software.
15 ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 ;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 ;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 ;; $Id: vectors.lisp,v 1.1 2006-04-25 20:40:57 espen Exp $
30 (defun make-c-vector (type length &key content location temp)
31 (let* ((element-size (size-of type))
32 (location (or location (allocate-memory (* element-size length))))
33 (writer (writer-function type :temp temp)))
37 for element across content
39 for offset by element-size
40 do (funcall writer element location offset)))
43 for element in content
45 for offset by element-size
46 do (funcall writer element location offset))))
50 (defun map-c-vector (seqtype function location element-type length
51 &optional (ref :read))
52 (let ((reader (reader-function element-type :ref ref))
53 (element-size (size-of element-type)))
58 for offset by element-size
59 do (funcall function (funcall reader location offset))))
63 for offset by element-size
64 collect (funcall function (funcall reader location offset))))
67 with sequence = (make-sequence seqtype length)
69 for offset by element-size
72 (funcall function (funcall reader location offset)))
73 finally (return sequence))))))
76 (defun unset-c-vector (location element-type length &optional temp-p)
78 with destroy = (destroy-function element-type :temp temp-p)
79 with element-size = (size-of element-type)
81 for offset by element-size
82 do (funcall destroy location offset)))
85 (defun destroy-c-vector (location element-type length &optional temp-p)
86 (unset-c-vector location element-type length temp-p)
87 (deallocate-memory location))
90 (defmacro with-c-vector (var type content &body body)
91 (let ((length (make-symbol "LENGTH")))
92 `(let ((,length (length ,content)))
93 (with-memory (,var (* ,(size-of type) ,length))
94 (make-c-vector ',type ,length :content ,content :location ,var :temp t)
97 (unset-c-vector ,var ',type ,length t))))))
100 (define-type-method alien-type ((type vector))
101 (declare (ignore type))
102 (alien-type 'pointer))
104 (define-type-method size-of ((type vector) &key inlined)
106 (destructuring-bind (element-type &optional (length '*))
107 (rest (type-expand-to 'vector type))
109 (error "Can't inline vector with variable size: ~A" type)
110 (* (size-of element-type) length)))
113 (define-type-method alien-arg-wrapper ((type vector) var vector style form &optional copy-in-p)
114 (destructuring-bind (element-type &optional (length '*))
115 (rest (type-expand-to 'vector type))
116 (when (and (eq length '*) (out-arg-p style))
117 (error "Can't use vector with variable size as return type"))
119 ((and (in-arg-p style) copy-in-p)
120 `(with-pointer (,var `(make-c-vector ',element-type
121 ,(if (eq length '*) `(length ,vector) length)
124 ((and (in-arg-p style) (not (out-arg-p style)))
125 `(with-memory (,var ,(if (eq length '*)
126 `(* ,(size-of element-type)
128 `(* ,(size-of element-type) ,length)))
129 (make-c-vector ',element-type
130 ,(if (eq length '*) `(length ,vector) length)
131 :content ,vector :location ,var :temp t)
134 (unset-c-vector ,var ',element-type
135 ,(if (eq length '*) `(length ,vector) length) t))))
136 ((and (in-arg-p style) (out-arg-p style))
137 (let ((c-vector (make-symbol "C-VECTOR")))
138 `(with-memory (,c-vector (* ,(size-of element-type) length))
139 (make-c-vector ',element-type ,length
140 :content ,vector :location ,c-vector :temp t)
141 (with-pointer (,var ,c-vector)
144 (unset-c-vector ,c-vector ',element-type ,length t))))))
145 ((and (out-arg-p style) (not (in-arg-p style)))
146 `(with-pointer (,var)
149 ;; This will enable us specify vectors with variable length in C callbacks
150 (define-type-method callback-wrapper ((type vector) var vector form)
151 (funcall (find-applicable-type-method 'callback-wrapper t) type var vector form))
153 (define-type-method to-alien-form ((type vector) vector &optional copy-p)
154 (declare (ignore copy-p))
155 (destructuring-bind (element-type &optional (length '*))
156 (rest (type-expand-to 'vector type))
157 `(make-c-vector ',element-type
158 ,(if (eq length '*) `(length ,vector) length) :content ,vector)))
161 (define-type-method from-alien-form ((type vector) form &key (ref :free))
162 (destructuring-bind (element-type &optional (length '*))
163 (rest (type-expand-to 'vector type))
165 (error "Can't use vector of variable size as return type")
166 `(let ((c-vector ,form))
168 (map-c-vector 'vector #'identity c-vector ',element-type ,length
169 ,(ecase ref (:free :get) ((:static :temp) :peek) (:copy :read)))
170 ,(when (eq ref :free)
171 `(deallocate-memory c-vector)))))))
174 (define-type-method writer-function ((type vector) &key temp inlined)
175 (destructuring-bind (element-type &optional (length '*))
176 (rest (type-expand-to 'vector type))
179 (error "Can't inline vector with variable size: ~A" type)
180 #'(lambda (vector location &optional (offset 0))
181 (make-c-vector element-type length
182 :location (pointer+ location offset)
183 :content vector :temp temp)))
184 #'(lambda (vector location &optional (offset 0))
186 (ref-pointer location offset)
187 (make-c-vector element-type length :content vector :temp temp))))))
189 (define-type-method reader-function ((type vector) &key (ref :read) inlined)
190 (destructuring-bind (element-type &optional (length '*))
191 (rest (type-expand-to 'vector type))
194 (error "Can't create reader function for vector with variable size"))
196 #'(lambda (location &optional (offset 0))
197 (map-c-vector 'vector #'identity (pointer+ location offset)
198 element-type length ref)))
202 #'(lambda (location &optional (offset 0))
203 (unless (null-pointer-p (ref-pointer location offset))
204 (map-c-vector 'vector #'identity (ref-pointer location offset)
205 element-type length ref))))
207 #'(lambda (location &optional (offset 0))
208 (unless (null-pointer-p (ref-pointer location offset))
210 (map-c-vector 'vector #'identity
211 (ref-pointer location offset) element-type length :get)
212 (deallocate-memory (ref-pointer location offset))
213 (setf (ref-pointer location offset) (make-pointer 0)))))))))))
215 (define-type-method destroy-function ((type vector) &key temp inlined)
216 (destructuring-bind (element-type &optional (length '*))
217 (rest (type-expand-to 'vector type))
220 (error "Can't create destroy function for vector with variable size"))
222 #'(lambda (location &optional (offset 0))
223 (unset-c-vector (pointer+ location offset)
224 element-type length temp)))
226 #'(lambda (location &optional (offset 0))
227 (unless (null-pointer-p (ref-pointer location offset))
228 (destroy-c-vector (ref-pointer location offset)
229 element-type length temp)
230 (setf (ref-pointer location offset) (make-pointer 0))))))))
232 (define-type-method copy-function ((type vector) &key inlined)
233 (destructuring-bind (element-type &optional (length '*))
234 (rest (type-expand-to 'vector type))
236 ((eq length '*) (error "Can't copy vector with variable size: ~A" type))
238 (let ((copy-element (copy-function element-type))
239 (element-size (size-of element-type)))
240 #'(lambda (from to &optional (offset 0))
243 for element from offset by element-size
244 do (funcall copy-element from to element)))))
246 (let ((size (* length (size-of element-type)))
247 (copy-content (copy-function type :inlined t)))
248 #'(lambda (from to &optional (offset 0))
249 (unless (null-pointer-p (ref-pointer from offset))
250 (let ((vector (allocate-memory size)))
251 (setf (ref-pointer to offset) vector)
252 (funcall copy-content (ref-pointer from offset) vector)))))))))
255 ;;;; Null terminated vector
257 (defun make-0-vector (type &key content location temp)
258 (let* ((element-size (size-of type))
259 (length (length content))
260 (location (or location (allocate-memory (* element-size (1+ length))))))
261 (make-c-vector type length :content content :location location :temp temp)))
264 (defun map-0-vector (seqtype function location element-type &optional (ref :read))
265 (let ((reader (reader-function element-type :ref ref))
266 (element-size (size-of element-type)))
270 for offset by element-size
271 until (memory-clear-p (pointer+ location offset) element-size)
272 do (funcall function (funcall reader location offset))))
275 for offset by element-size
276 until (memory-clear-p (pointer+ location offset) element-size)
277 collect (funcall function (funcall reader location offset))))
281 for offset by element-size
282 until (memory-clear-p (pointer+ location offset) element-size)
283 collect (funcall function (funcall reader location offset)))
287 (defun unset-0-vector (location element-type &optional temp-p)
289 with destroy = (destroy-function element-type temp-p)
290 with element-size = (size-of element-type)
291 for offset by element-size
292 until (memory-clear-p (pointer+ location offset) element-size)
293 do (funcall destroy location offset)))
295 (defun destroy-0-vector (location element-type &optional temp-p)
296 (unset-0-vector location element-type temp-p)
297 (deallocate-memory location))
300 (deftype vector0 (element-type) `(vector ,element-type))
301 (deftype null-terminated-vector (element-type) `(vector0 ,element-type))
303 (define-type-method alien-type ((type vector0))
304 (declare (ignore type))
305 (alien-type 'pointer))
307 (define-type-method size-of ((type vector0) &key inlined)
308 (assert-not-inlined type inlined)
311 (define-type-method alien-arg-wrapper ((type vector0) var vector style form &optional copy-in-p)
312 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
314 ((and (in-arg-p style) copy-in-p)
315 `(with-pointer (,var (make-0-vector ',element-type :content ,vector))
317 ((and (in-arg-p style) (not (out-arg-p style)))
318 `(with-memory (,var (* ,(size-of element-type) (1+ (length ,vector))))
319 (make-0-vector ',element-type :content ,vector :location ,var :temp t)
322 (unset-0-vector ,var ',element-type t))))
323 ((and (in-arg-p style) (out-arg-p style))
324 (let ((c-vector (make-symbol "C-VECTOR")))
325 `(with-memory (,c-vector (* ,(size-of element-type) (1+ (length ,vector))))
326 (make-0-vector ',element-type :content ,vector :location ,c-vector :temp t)
327 (with-pointer (,var ,c-vector)
330 (unset-0-vector ,c-vector ',element-type t))))))
331 ((and (out-arg-p style) (not (in-arg-p style)))
332 `(with-pointer (,var)
336 (define-type-method to-alien-form ((type vector0) vector &optional copy-p)
337 (declare (ignore copy-p))
338 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
339 `(make-0-vector ',element-type :content ,vector)))
341 (define-type-method from-alien-form ((type vector0) form &key (ref :free))
342 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
343 `(let ((c-vector ,form))
345 (map-0-vector 'vector #'identity c-vector ',element-type
346 ,(ecase ref (:free :get) ((:static :temp) :peek) (:copy :read)))
347 ,(when (eq ref :free)
348 `(deallocate-memory c-vector))))))
351 (define-type-method writer-function ((type vector0) &key temp inlined)
352 (assert-not-inlined type inlined)
353 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
354 #'(lambda (vector location &optional (offset 0))
356 (ref-pointer location offset)
357 (make-0-vector element-type :content vector :temp temp)))))
359 (define-type-method reader-function ((type vector0) &key (ref :read) inlined)
360 (assert-not-inlined type inlined)
361 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
364 #'(lambda (location &optional (offset 0))
365 (unless (null-pointer-p (ref-pointer location offset))
366 (map-0-vector 'vector #'identity (ref-pointer location offset)
369 #'(lambda (location &optional (offset 0))
370 (unless (null-pointer-p (ref-pointer location offset))
372 (map-0-vector 'vector #'identity (ref-pointer location offset)
374 (deallocate-memory (ref-pointer location offset))
375 (setf (ref-pointer location offset) (make-pointer 0)))))))))
378 (define-type-method destroy-function ((type vector0) &key temp inlined)
379 (assert-not-inlined type inlined)
380 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
381 #'(lambda (location &optional (offset 0))
382 (unless (null-pointer-p (ref-pointer location offset))
384 (ref-pointer location offset) element-type temp)
385 (setf (ref-pointer location offset) (make-pointer 0))))))
387 (define-type-method copy-function ((type vector0) &key inlined)
388 (assert-not-inlined type inlined)
389 (destructuring-bind (element-type) (rest (type-expand-to 'vector0 type))
390 (let ((copy-element (copy-function element-type))
391 (element-size (size-of element-type)))
392 #'(lambda (from to &optional (offset 0))
393 (unless (null-pointer-p (ref-pointer from offset))
394 (let* ((from-vector (ref-pointer from offset))
398 for element by element-size
399 until (memory-clear-p from-vector element-size element)
400 finally (return length)))
402 (ref-pointer to offset)
403 (allocate-memory (* length element-size)))))
406 for element by element-size
407 do (funcall copy-element from-vector to-vector element))))))))
409 (define-type-method unbound-value ((type vector0))
410 (declare (ignore type))
417 (defun make-counted-vector (type &key content location (counter-type 'unsigned-int) temp)
418 (let* ((element-size (size-of type))
419 (length (length content))
423 (+ (size-of counter-type) (* element-size length))))))
424 (funcall (writer-function counter-type :temp temp) length location)
425 (make-c-vector type length :content content :location (pointer+ location (size-of counter-type)))
428 (defun map-counted-vector (seqtype function location element-type &optional (counter-type 'unsigned-int) (ref :read))
429 (let ((length (funcall (reader-function counter-type) location :ref ref)))
431 seqtype function (pointer+ location (size-of counter-type))
432 element-type length)))
434 (defun unset-counted-vector (location element-type &optional (counter-type 'unsigned-int) temp-p)
435 (let ((length (funcall (reader-function counter-type) location)))
437 (pointer+ location (size-of counter-type)) element-type length temp-p)))
439 (defun destroy-counted-vector (location element-type &optional (counter-type 'unsigned-int) temp-p)
440 (unset-counted-vector location element-type counter-type temp-p)
441 (deallocate-memory location))
444 (deftype counted-vector (element-type &optional counter-type)
445 (declare (ignore counter-type))
446 `(vector ,element-type))
448 (define-type-method alien-type ((type counted-vector))
449 (declare (ignore type))
450 (alien-type 'pointer))
452 (define-type-method size-of ((type counted-vector) &key inlined)
453 (assert-not-inlined type inlined)
456 (define-type-method alien-arg-wrapper ((type counted-vector) var vector style form &optional copy-in-p)
457 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
458 (rest (type-expand-to 'counted-vector type))
460 ((and (in-arg-p style) copy-in-p)
461 `(with-pointer (,var (make-counted-vector ',element-type
462 :content ,vector :counter-type ',counter-type))
464 ((and (in-arg-p style) (not (out-arg-p style)))
465 `(with-memory (,var (+ (* ,(size-of element-type) (length ,vector)) ,(size-of counter-type)))
466 (make-counted-vector ',element-type :content ,vector
467 :location ,var :counter-type ',counter-type :temp t)
470 (unset-counted-vector ,var ',element-type ',counter-type t))))
471 ((and (in-arg-p style) (out-arg-p style))
472 (let ((c-vector (make-symbol "C-VECTOR")))
473 `(with-memory (,c-vector (+ (* ,(size-of element-type) (length ,vector)) ,(size-of counter-type)))
474 (make-counted-vector ',element-type :content ,vector ,c-vector
475 :counter-type ',counter-type :temp t)
476 (with-pointer (,var ,c-vector)
479 (unset-counted-vector ,c-vector ',element-type ',counter-type t))))))
480 ((and (out-arg-p style) (not (in-arg-p style)))
481 `(with-pointer (,var)
485 (define-type-method to-alien-form ((type counted-vector) vector &optional copy-p)
486 (declare (ignore copy-p))
487 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
488 (rest (type-expand-to 'counted-vector type))
489 `(make-counted-vector ',element-type
490 :content ,vector :counter-type ',counter-type)))
492 (define-type-method from-alien-form ((type counted-vector) form &key (ref :free))
493 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
494 (rest (type-expand-to 'counted-vector type))
495 `(let ((c-vector ,form))
497 (map-counted-vector 'vector #'identity c-vector ',element-type ',counter-type
498 ,(ecase ref (:free :get) ((:static :temp) :peek) (:copy :read)))
499 ,(when (eq ref :free)
500 `(deallocate c-vector))))))
502 (define-type-method writer-function ((type counted-vector) &key temp inlined)
503 (assert-not-inlined type inlined)
504 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
505 (rest (type-expand-to 'counted-vector type))
506 #'(lambda (vector location &optional (offset 0))
508 (ref-pointer location offset)
509 (make-counted-vector element-type :content vector
510 :counter-type counter-type :temp temp)))))
512 (define-type-method reader-function ((type counted-vector) &key (ref :read) inlined)
513 (assert-not-inlined type inlined)
514 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
515 (rest (type-expand-to 'counted-vector type))
518 #'(lambda (location &optional (offset 0))
519 (unless (null-pointer-p (ref-pointer location offset))
520 (map-counted-vector 'vector #'identity
521 (ref-pointer location offset) element-type counter-type ref))))
523 #'(lambda (location &optional (offset 0))
524 (unless (null-pointer-p (ref-pointer location offset))
526 (map-counted-vector 'vector #'identity
527 (ref-pointer location offset) element-type counter-type :get)
528 (deallocate-memory (ref-pointer location offset))
529 (setf (ref-pointer location offset) (make-pointer 0)))))))))
531 (define-type-method destroy-function ((type counted-vector) &key temp inlined)
532 (assert-not-inlined type inlined)
533 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
534 (rest (type-expand-to 'counted-vector type))
535 #'(lambda (location &optional (offset 0))
536 (unless (null-pointer-p (ref-pointer location offset))
537 (destroy-counted-vector (ref-pointer location offset)
538 element-type counter-type temp)
539 (setf (ref-pointer location offset) (make-pointer 0))))))
541 (define-type-method copy-function ((type counted-vector) &key inlined)
542 (assert-not-inlined type inlined)
543 (destructuring-bind (element-type &optional (counter-type 'unsigned-int))
544 (rest (type-expand-to 'counted-vector type))
545 (let ((vector-length (reader-function counter-type))
546 (counter-size (size-of counter-type))
547 (copy-element (copy-function element-type))
548 (element-size (size-of element-type)))
549 #'(lambda (from to &optional (offset 0))
550 (unless (null-pointer-p (ref-pointer from offset))
551 (let* ((from-vector (ref-pointer from offset))
552 (length (funcall vector-length from-vector))
554 (ref-pointer to offset)
555 (allocate-memory (+ counter-size (* length element-size))))))
556 (copy-memory from-vector counter-size to-vector)
559 for element from counter-size by element-size
560 do (funcall copy-element from-vector to-vector element))))))))