chiark / gitweb /
Added PRINT-OBJECT method for widget class and a small bug fix
[clg] / glib / glib.lisp
CommitLineData
112ac1d3 1;; Common Lisp bindings for GTK+ 2.x
2;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
560af5c5 3;;
112ac1d3 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:
560af5c5 11;;
112ac1d3 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
560af5c5 14;;
112ac1d3 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.
22
b238749d 23;; $Id: glib.lisp,v 1.35 2006-02-19 22:34:28 espen Exp $
560af5c5 24
25
26(in-package "GLIB")
c4e9d221 27
560af5c5 28(use-prefix "g")
29
30
31;;;; Memory management
32
dba0c446 33(defbinding (allocate-memory "g_malloc0") () pointer
560af5c5 34 (size unsigned-long))
35
dba0c446 36(defbinding (reallocate-memory "g_realloc") () pointer
560af5c5 37 (address pointer)
38 (size unsigned-long))
39
3c657c71 40(defbinding (deallocate-memory "g_free") () nil
41 (address pointer))
9adccb27 42;; (defun deallocate-memory (address)
43;; (declare (ignore address)))
560af5c5 44
45(defun copy-memory (from length &optional (to (allocate-memory length)))
4f805161 46 #+cmu(system-area-copy from 0 to 0 (* 8 length))
47 #+sbcl(system-area-ub8-copy from 0 to 0 length)
560af5c5 48 to)
49
b238749d 50(defun clear-memory (from length)
51 #+cmu(system-area-fill 0 0 from 0 (* 8 length))
52 #+sbcl(system-area-ub8-fill 0 from 0 length))
53
7cda9325 54(defmacro with-allocated-memory ((var size) &body body)
9a47e267 55 (if (constantp size)
b238749d 56 (let ((alien (make-symbol "ALIEN"))
57 (size (eval size)))
58 `(with-alien ((,alien (array #+sbcl(sb-alien:unsigned 8) #+cmu(alien:unsigned 8) ,size)))
9a47e267 59 (let ((,var (alien-sap ,alien)))
b238749d 60 (clear-memory ,var ,size)
9a47e267 61 ,@body)))
62 `(let ((,var (allocate-memory ,size)))
63 (unwind-protect
64 (progn ,@body)
65 (deallocate-memory ,var)))))
7cda9325 66
560af5c5 67
c4e9d221 68;;;; User data mechanism
69
70(internal *user-data* *user-data-count*)
71
c4e9d221 72(defvar *user-data* (make-hash-table))
73(defvar *user-data-count* 0)
74
75(defun register-user-data (object &optional destroy-function)
76 (check-type destroy-function (or null symbol function))
77 (incf *user-data-count*)
78 (setf
79 (gethash *user-data-count* *user-data*)
80 (cons object destroy-function))
81 *user-data-count*)
82
83(defun find-user-data (id)
84 (check-type id fixnum)
85 (multiple-value-bind (user-data p) (gethash id *user-data*)
86 (values (car user-data) p)))
87
7e531ed5 88(defun user-data-exists-p (id)
89 (nth-value 1 (find-user-data id)))
90
c9219df2 91(defun update-user-data (id object)
92 (check-type id fixnum)
93 (multiple-value-bind (user-data exists-p) (gethash id *user-data*)
94 (cond
95 ((not exists-p) (error "User data id ~A does not exist" id))
96 (t
97 (when (cdr user-data)
98 (funcall (cdr user-data) (car user-data)))
99 (setf (car user-data) object)))))
100
c4e9d221 101(defun destroy-user-data (id)
102 (check-type id fixnum)
103 (let ((user-data (gethash id *user-data*)))
104 (when (cdr user-data)
105 (funcall (cdr user-data) (car user-data))))
106 (remhash id *user-data*))
107
560af5c5 108
0aef1da8 109;;;; Quarks
110
111(deftype quark () 'unsigned)
112
5cae32e1 113(defbinding %quark-from-string () quark
415444ae 114 (string string))
115
7e531ed5 116(defun quark-intern (object)
117 (etypecase object
118 (quark object)
119 (string (%quark-from-string object))
120 (symbol (%quark-from-string (format nil "clg-~A:~A"
121 (package-name (symbol-package object))
122 object)))))
0aef1da8 123
7e531ed5 124(defbinding quark-to-string () (copy-of string)
125 (quark quark))
0aef1da8 126
127
3846c0b6 128;;;; Linked list (GList)
560af5c5 129
72e5ffec 130(deftype glist (type)
9adccb27 131 `(or (null (cons ,type list))))
560af5c5 132
72e5ffec 133(defbinding (%glist-append "g_list_append") () pointer
3846c0b6 134 (glist pointer)
72e5ffec 135 (nil null))
3846c0b6 136
9adccb27 137(defun make-glist (type list)
72e5ffec 138 (loop
139 with writer = (writer-function type)
140 for element in list
141 as glist = (%glist-append (or glist (make-pointer 0)))
142 do (funcall writer element glist)
143 finally (return glist)))
560af5c5 144
560af5c5 145(defun glist-next (glist)
146 (unless (null-pointer-p glist)
9adccb27 147 (sap-ref-sap glist +size-of-pointer+)))
560af5c5 148
9adccb27 149;; Also used for gslists
150(defun map-glist (seqtype function glist element-type)
151 (let ((reader (reader-function element-type)))
152 (case seqtype
153 ((nil)
154 (loop
155 as tmp = glist then (glist-next tmp)
156 until (null-pointer-p tmp)
157 do (funcall function (funcall reader tmp))))
158 (list
159 (loop
160 as tmp = glist then (glist-next tmp)
161 until (null-pointer-p tmp)
162 collect (funcall function (funcall reader tmp))))
163 (t
164 (coerce
165 (loop
166 as tmp = glist then (glist-next tmp)
167 until (null-pointer-p tmp)
168 collect (funcall function (funcall reader tmp)))
169 seqtype)))))
170
dba0c446 171(defbinding (glist-free "g_list_free") () nil
560af5c5 172 (glist pointer))
173
72e5ffec 174(defun destroy-glist (glist element-type)
175 (loop
176 with destroy = (destroy-function element-type)
177 as tmp = glist then (glist-next tmp)
178 until (null-pointer-p tmp)
179 do (funcall destroy tmp 0))
180 (glist-free glist))
415444ae 181
9adccb27 182(defmethod alien-type ((type (eql 'glist)) &rest args)
183 (declare (ignore type args))
184 (alien-type 'pointer))
185
186(defmethod size-of ((type (eql 'glist)) &rest args)
187 (declare (ignore type args))
415444ae 188 (size-of 'pointer))
560af5c5 189
9adccb27 190(defmethod to-alien-form (list (type (eql 'glist)) &rest args)
191 (declare (ignore type))
192 (destructuring-bind (element-type) args
193 `(make-glist ',element-type ,list)))
194
195(defmethod to-alien-function ((type (eql 'glist)) &rest args)
8755b1a5 196 (declare (ignore type))
9adccb27 197 (destructuring-bind (element-type) args
198 #'(lambda (list)
199 (make-glist element-type list))))
200
201(defmethod from-alien-form (glist (type (eql 'glist)) &rest args)
202 (declare (ignore type))
203 (destructuring-bind (element-type) args
560af5c5 204 `(let ((glist ,glist))
9adccb27 205 (unwind-protect
206 (map-glist 'list #'identity glist ',element-type)
72e5ffec 207 (destroy-glist glist ',element-type)))))
9adccb27 208
209(defmethod from-alien-function ((type (eql 'glist)) &rest args)
210 (declare (ignore type))
211 (destructuring-bind (element-type) args
212 #'(lambda (glist)
213 (unwind-protect
214 (map-glist 'list #'identity glist element-type)
72e5ffec 215 (destroy-glist glist element-type)))))
216
217(defmethod copy-from-alien-form (glist (type (eql 'glist)) &rest args)
218 (declare (ignore type))
219 (destructuring-bind (element-type) args
220 `(map-glist 'list #'identity ,glist ',element-type)))
221
222(defmethod copy-from-alien-function ((type (eql 'glist)) &rest args)
223 (declare (ignore type))
224 (destructuring-bind (element-type) args
225 #'(lambda (glist)
226 (map-glist 'list #'identity glist element-type))))
9adccb27 227
228(defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
72e5ffec 229 (declare (ignore type))
230 (destructuring-bind (element-type) args
231 `(destroy-glist ,glist ',element-type)))
9adccb27 232
233(defmethod cleanup-function ((type (eql 'glist)) &rest args)
e8caa25a 234 (declare (ignore type))
72e5ffec 235 (destructuring-bind (element-type) args
236 #'(lambda (glist)
237 (destroy-glist glist element-type))))
560af5c5 238
e8caa25a 239(defmethod writer-function ((type (eql 'glist)) &rest args)
240 (declare (ignore type))
241 (destructuring-bind (element-type) args
242 #'(lambda (list location &optional (offset 0))
243 (setf
244 (sap-ref-sap location offset)
245 (make-glist element-type list)))))
246
247(defmethod reader-function ((type (eql 'glist)) &rest args)
248 (declare (ignore type))
249 (destructuring-bind (element-type) args
3005806e 250 #'(lambda (location &optional (offset 0) weak-p)
251 (declare (ignore weak-p))
e8caa25a 252 (unless (null-pointer-p (sap-ref-sap location offset))
253 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
254
255(defmethod destroy-function ((type (eql 'glist)) &rest args)
256 (declare (ignore type))
257 (destructuring-bind (element-type) args
258 #'(lambda (location &optional (offset 0))
259 (unless (null-pointer-p (sap-ref-sap location offset))
260 (destroy-glist (sap-ref-sap location offset) element-type)
261 (setf (sap-ref-sap location offset) (make-pointer 0))))))
262
263
560af5c5 264
3846c0b6 265;;;; Single linked list (GSList)
266
267(deftype gslist (type) `(or (null (cons ,type list))))
268
72e5ffec 269(defbinding (%gslist-prepend "g_slist_prepend") () pointer
3846c0b6 270 (gslist pointer)
72e5ffec 271 (nil null))
3846c0b6 272
9adccb27 273(defun make-gslist (type list)
72e5ffec 274 (loop
275 with writer = (writer-function type)
276 for element in (reverse list)
277 as gslist = (%gslist-prepend (or gslist (make-pointer 0)))
278 do (funcall writer element gslist)
279 finally (return gslist)))
9adccb27 280
dba0c446 281(defbinding (gslist-free "g_slist_free") () nil
3846c0b6 282 (gslist pointer))
283
72e5ffec 284(defun destroy-gslist (gslist element-type)
285 (loop
286 with destroy = (destroy-function element-type)
287 as tmp = gslist then (glist-next tmp)
288 until (null-pointer-p tmp)
289 do (funcall destroy tmp 0))
290 (gslist-free gslist))
3846c0b6 291
9adccb27 292(defmethod alien-type ((type (eql 'gslist)) &rest args)
293 (declare (ignore type args))
294 (alien-type 'pointer))
295
296(defmethod size-of ((type (eql 'gslist)) &rest args)
297 (declare (ignore type args))
3846c0b6 298 (size-of 'pointer))
299
9adccb27 300(defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
301 (declare (ignore type))
302 (destructuring-bind (element-type) args
303 `(make-sglist ',element-type ,list)))
304
305(defmethod to-alien-function ((type (eql 'gslist)) &rest args)
8755b1a5 306 (declare (ignore type))
9adccb27 307 (destructuring-bind (element-type) args
308 #'(lambda (list)
309 (make-gslist element-type list))))
310
311(defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
312 (declare (ignore type))
313 (destructuring-bind (element-type) args
3846c0b6 314 `(let ((gslist ,gslist))
9adccb27 315 (unwind-protect
316 (map-glist 'list #'identity gslist ',element-type)
72e5ffec 317 (destroy-gslist gslist ',element-type)))))
3846c0b6 318
9adccb27 319(defmethod from-alien-function ((type (eql 'gslist)) &rest args)
320 (declare (ignore type))
321 (destructuring-bind (element-type) args
322 #'(lambda (gslist)
323 (unwind-protect
324 (map-glist 'list #'identity gslist element-type)
72e5ffec 325 (destroy-gslist gslist element-type)))))
326
327(defmethod copy-from-alien-form (gslist (type (eql 'gslist)) &rest args)
328 (declare (ignore type))
329 (destructuring-bind (element-type) args
330 `(map-glist 'list #'identity ,gslist ',element-type)))
331
73572c12 332(defmethod copy-from-alien-function ((type (eql 'gslist)) &rest args)
72e5ffec 333 (declare (ignore type))
334 (destructuring-bind (element-type) args
335 #'(lambda (gslist)
336 (map-glist 'list #'identity gslist element-type))))
3846c0b6 337
72e5ffec 338(defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
e8caa25a 339 (declare (ignore type))
72e5ffec 340 (destructuring-bind (element-type) args
341 `(destroy-gslist ,gslist ',element-type)))
3846c0b6 342
9adccb27 343(defmethod cleanup-function ((type (eql 'gslist)) &rest args)
e8caa25a 344 (declare (ignore type))
72e5ffec 345 (destructuring-bind (element-type) args
346 #'(lambda (gslist)
347 (destroy-gslist gslist element-type))))
415444ae 348
e8caa25a 349(defmethod writer-function ((type (eql 'gslist)) &rest args)
350 (declare (ignore type))
351 (destructuring-bind (element-type) args
352 #'(lambda (list location &optional (offset 0))
353 (setf
354 (sap-ref-sap location offset)
355 (make-gslist element-type list)))))
356
357(defmethod reader-function ((type (eql 'gslist)) &rest args)
358 (declare (ignore type))
359 (destructuring-bind (element-type) args
3005806e 360 #'(lambda (location &optional (offset 0) weak-p)
361 (declare (ignore weak-p))
e8caa25a 362 (unless (null-pointer-p (sap-ref-sap location offset))
363 (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
364
365(defmethod destroy-function ((type (eql 'gslist)) &rest args)
366 (declare (ignore type))
367 (destructuring-bind (element-type) args
368 #'(lambda (location &optional (offset 0))
369 (unless (null-pointer-p (sap-ref-sap location offset))
370 (destroy-gslist (sap-ref-sap location offset) element-type)
371 (setf (sap-ref-sap location offset) (make-pointer 0))))))
5cae32e1 372
415444ae 373
9adccb27 374;;; Vector
415444ae 375
9adccb27 376(defun make-c-vector (type length &optional content location)
377 (let* ((size-of-type (size-of type))
378 (location (or location (allocate-memory (* size-of-type length))))
379 (writer (writer-function type)))
814ccf77 380 (etypecase content
381 (vector
382 (loop
383 for element across content
384 for i from 0 below length
385 as offset = 0 then (+ offset size-of-type)
386 do (funcall writer element location offset)))
387 (list
388 (loop
389 for element in content
390 for i from 0 below length
391 as offset = 0 then (+ offset size-of-type)
392 do (funcall writer element location offset))))
9adccb27 393 location))
394
395
396(defun map-c-vector (seqtype function location element-type length)
397 (let ((reader (reader-function element-type))
398 (size-of-element (size-of element-type)))
dba0c446 399 (case seqtype
400 ((nil)
9adccb27 401 (loop
402 for i from 0 below length
403 as offset = 0 then (+ offset size-of-element)
404 do (funcall function (funcall reader location offset))))
dba0c446 405 (list
9adccb27 406 (loop
407 for i from 0 below length
408 as offset = 0 then (+ offset size-of-element)
409 collect (funcall function (funcall reader location offset))))
dba0c446 410 (t
9adccb27 411 (loop
412 with sequence = (make-sequence seqtype length)
413 for i from 0 below length
414 as offset = 0 then (+ offset size-of-element)
415 do (setf
dba0c446 416 (elt sequence i)
9adccb27 417 (funcall function (funcall reader location offset)))
418 finally (return sequence))))))
419
420
72e5ffec 421(defun destroy-c-vector (location element-type length)
422 (loop
423 with destroy = (destroy-function element-type)
424 with element-size = (size-of element-type)
425 for i from 0 below length
426 as offset = 0 then (+ offset element-size)
427 do (funcall destroy location offset))
428 (deallocate-memory location))
429
430
9adccb27 431(defmethod alien-type ((type (eql 'vector)) &rest args)
432 (declare (ignore type args))
433 (alien-type 'pointer))
434
435(defmethod size-of ((type (eql 'vector)) &rest args)
436 (declare (ignore type args))
437 (size-of 'pointer))
438
439(defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
440 (declare (ignore type))
441 (destructuring-bind (element-type &optional (length '*)) args
442 (if (eq length '*)
443 `(let* ((vector ,vector)
444 (location (sap+
445 (allocate-memory (+ ,+size-of-int+
446 (* ,(size-of element-type)
447 (length vector))))
448 ,+size-of-int+)))
449 (make-c-vector ',element-type (length vector) vector location)
450 (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
451 location)
452 `(make-c-vector ',element-type ,length ,vector))))
453
72e5ffec 454(defmethod from-alien-form (c-vector (type (eql 'vector)) &rest args)
455 (declare (ignore type))
456 (destructuring-bind (element-type &optional (length '*)) args
457 (if (eq length '*)
458 (error "Can't use vector of variable size as return type")
459 `(let ((c-vector ,c-vector))
460 (prog1
c9219df2 461 (map-c-vector 'vector #'identity c-vector ',element-type ,length)
72e5ffec 462 (destroy-c-vector c-vector ',element-type ,length))))))
463
464(defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
9adccb27 465 (declare (ignore type))
466 (destructuring-bind (element-type &optional (length '*)) args
467 (if (eq length '*)
468 (error "Can't use vector of variable size as return type")
e7765a40 469 `(map-c-vector 'vector #'identity ,c-vector ',element-type ,length))))
9adccb27 470
5e8ceafa 471(defmethod copy-from-alien-function ((type (eql 'vector)) &rest args)
472 (declare (ignore type))
473 (destructuring-bind (element-type &optional (length '*)) args
474 (if (eq length '*)
475 (error "Can't use vector of variable size as return type")
476 #'(lambda (c-vector)
477 (map-c-vector 'vector #'identity c-vector element-type length)))))
478
9adccb27 479(defmethod cleanup-form (location (type (eql 'vector)) &rest args)
480 (declare (ignore type))
481 (destructuring-bind (element-type &optional (length '*)) args
482 `(let* ((location ,location)
483 (length ,(if (eq length '*)
484 `(sap-ref-32 location ,(- +size-of-int+))
485 length)))
486 (loop
487 with destroy = (destroy-function ',element-type)
488 for i from 0 below length
489 as offset = 0 then (+ offset ,(size-of element-type))
490 do (funcall destroy location offset))
491 (deallocate-memory ,(if (eq length '*)
492 `(sap+ location ,(- +size-of-int+))
493 'location)))))
16bf1149 494
495(defmethod writer-function ((type (eql 'vector)) &rest args)
496 (declare (ignore type))
497 (destructuring-bind (element-type &optional (length '*)) args
498 #'(lambda (vector location &optional (offset 0))
499 (setf
500 (sap-ref-sap location offset)
501 (make-c-vector element-type length vector)))))
502
503(defmethod reader-function ((type (eql 'vector)) &rest args)
504 (declare (ignore type))
505 (destructuring-bind (element-type &optional (length '*)) args
506 (if (eq length '*)
507 (error "Can't create reader function for vector of variable size")
3005806e 508 #'(lambda (location &optional (offset 0) weak-p)
509 (declare (ignore weak-p))
16bf1149 510 (unless (null-pointer-p (sap-ref-sap location offset))
511 (map-c-vector 'vector #'identity (sap-ref-sap location offset)
512 element-type length))))))
513
514(defmethod destroy-function ((type (eql 'vector)) &rest args)
515 (declare (ignore type))
516 (destructuring-bind (element-type &optional (length '*)) args
517 (if (eq length '*)
518 (error "Can't create destroy function for vector of variable size")
519 #'(lambda (location &optional (offset 0))
520 (unless (null-pointer-p (sap-ref-sap location offset))
521 (destroy-c-vector
522 (sap-ref-sap location offset) element-type length)
523 (setf (sap-ref-sap location offset) (make-pointer 0)))))))
463fe62f 524
525
526;;;; Null terminated vector
527
528(defun make-0-vector (type content &optional location)
529 (let* ((size-of-type (size-of type))
530 (location (or
531 location
532 (allocate-memory (* size-of-type (1+ (length content))))))
533 (writer (writer-function type)))
534 (etypecase content
535 (vector
536 (loop
537 for element across content
538 as offset = 0 then (+ offset size-of-type)
539 do (funcall writer element location offset)
540 finally (setf (sap-ref-sap location offset) (make-pointer 0))))
541 (list
542 (loop
543 for element in content
544 as offset = 0 then (+ offset size-of-type)
545 do (funcall writer element location offset)
546 finally (setf (sap-ref-sap location (+ offset size-of-type)) (make-pointer 0)))))
547 location))
548
549
550(defun map-0-vector (seqtype function location element-type)
551 (let ((reader (reader-function element-type))
552 (size-of-element (size-of element-type)))
553 (case seqtype
554 ((nil)
555 (loop
556 as offset = 0 then (+ offset size-of-element)
557 until (null-pointer-p (sap-ref-sap location offset))
558 do (funcall function (funcall reader location offset))))
559 (list
560 (loop
561 as offset = 0 then (+ offset size-of-element)
562 until (null-pointer-p (sap-ref-sap location offset))
563 collect (funcall function (funcall reader location offset))))
564 (t
565 (coerce
566 (loop
567 as offset = 0 then (+ offset size-of-element)
568 until (null-pointer-p (sap-ref-sap location offset))
569 collect (funcall function (funcall reader location offset)))
570 seqtype)))))
571
572
573(defun destroy-0-vector (location element-type)
574 (loop
575 with destroy = (destroy-function element-type)
576 with element-size = (size-of element-type)
577 as offset = 0 then (+ offset element-size)
578 until (null-pointer-p (sap-ref-sap location offset))
579 do (funcall destroy location offset))
580 (deallocate-memory location))
581
5e8ceafa 582(deftype null-terminated-vector (element-type) `(vector ,element-type))
463fe62f 583
545712f4 584(defmethod alien-type ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 585 (declare (ignore type args))
586 (alien-type 'pointer))
587
545712f4 588(defmethod size-of ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 589 (declare (ignore type args))
5e8ceafa 590 (size-of 'pointer))
591
592(defmethod to-alien-form (vector (type (eql 'null-terminated-vector)) &rest args)
593 (declare (ignore type))
594 (destructuring-bind (element-type) args
595 `(make-0-vector ',element-type ,vector)))
596
597(defmethod from-alien-form (c-vector (type (eql 'null-terminated-vector)) &rest args)
598 (declare (ignore type))
599 (destructuring-bind (element-type) args
600 `(let ((c-vector ,c-vector))
601 (prog1
602 (map-0-vector 'vector #'identity c-vector ',element-type)
603 (destroy-0-vector c-vector ',element-type)))))
604
605(defmethod copy-from-alien-form (c-vector (type (eql 'null-terminated-vector)) &rest args)
606 (declare (ignore type))
607 (destructuring-bind (element-type) args
608 `(map-0-vector 'vector #'identity ,c-vector ',element-type)))
609
610(defmethod cleanup-form (location (type (eql 'null-terminated-vector)) &rest args)
611 (declare (ignore type))
612 (destructuring-bind (element-type) args
613 `(destroy-0-vector ,location ',element-type)))
463fe62f 614
545712f4 615(defmethod writer-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 616 (declare (ignore type))
545712f4 617 (destructuring-bind (element-type) args
463fe62f 618 (unless (eq (alien-type element-type) (alien-type 'pointer))
619 (error "Elements in null-terminated vectors need to be of pointer types"))
620 #'(lambda (vector location &optional (offset 0))
621 (setf
622 (sap-ref-sap location offset)
623 (make-0-vector element-type vector)))))
624
545712f4 625(defmethod reader-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 626 (declare (ignore type))
545712f4 627 (destructuring-bind (element-type) args
463fe62f 628 (unless (eq (alien-type element-type) (alien-type 'pointer))
629 (error "Elements in null-terminated vectors need to be of pointer types"))
3005806e 630 #'(lambda (location &optional (offset 0) weak-p)
631 (declare (ignore weak-p))
463fe62f 632 (unless (null-pointer-p (sap-ref-sap location offset))
633 (map-0-vector 'vector #'identity (sap-ref-sap location offset)
634 element-type)))))
635
545712f4 636(defmethod destroy-function ((type (eql 'null-terminated-vector)) &rest args)
463fe62f 637 (declare (ignore type))
545712f4 638 (destructuring-bind (element-type) args
463fe62f 639 (unless (eq (alien-type element-type) (alien-type 'pointer))
640 (error "Elements in null-terminated vectors need to be of pointer types"))
641 #'(lambda (location &optional (offset 0))
642 (unless (null-pointer-p (sap-ref-sap location offset))
545712f4 643 (destroy-0-vector
463fe62f 644 (sap-ref-sap location offset) element-type)
645 (setf (sap-ref-sap location offset) (make-pointer 0))))))
646
545712f4 647(defmethod unbound-value ((type (eql 'null-terminated-vector)) &rest args)
648 (declare (ignore type args))
463fe62f 649 (values t nil))
5e8ceafa 650
651
652;;; Counted vector
653
654(defun make-counted-vector (type content)
655 (let* ((size-of-type (size-of type))
656 (length (length content))
657 (location
658 (allocate-memory (+ +size-of-int+ (* size-of-type length)))))
659 (setf (sap-ref-32 location 0) length)
660 (make-c-vector type length content (sap+ location +size-of-int+))))
661
662(defun map-counted-vector (seqtype function location element-type)
663 (let ((length (sap-ref-32 location 0)))
664 (map-c-vector
665 seqtype function (sap+ location +size-of-int+)
666 element-type length)))
667
668(defun destroy-counted-vector (location element-type)
669 (loop
670 with destroy = (destroy-function element-type)
671 with element-size = (size-of element-type)
672 for i from 0 below (sap-ref-32 location 0)
673 as offset = +size-of-int+ then (+ offset element-size)
674 do (funcall destroy location offset))
675 (deallocate-memory location))
676
677
678(deftype counted-vector (element-type) `(vector ,element-type))
679
680(defmethod alien-type ((type (eql 'counted-vector)) &rest args)
681 (declare (ignore type args))
682 (alien-type 'pointer))
683
684(defmethod size-of ((type (eql 'counted-vector)) &rest args)
685 (declare (ignore type args))
686 (size-of 'pointer))
687
688(defmethod to-alien-form (vector (type (eql 'counted-vector)) &rest args)
689 (declare (ignore type))
690 (destructuring-bind (element-type) args
691 `(make-counted-vector ',element-type ,vector)))
692
693(defmethod from-alien-form (c-vector (type (eql 'counted-vector)) &rest args)
694 (declare (ignore type))
695 (destructuring-bind (element-type) args
696 `(let ((c-vector ,c-vector))
697 (prog1
698 (map-counted-vector 'vector #'identity c-vector ',element-type)
699 (destroy-counted-vector c-vector ',element-type)))))
700
701(defmethod copy-from-alien-form (c-vector (type (eql 'counted-vector)) &rest args)
702 (declare (ignore type))
703 (destructuring-bind (element-type) args
704 `(map-counted-vector 'vector #'identity ,c-vector ',element-type)))
705
706(defmethod copy-from-alien-function ((type (eql 'counted-vector)) &rest args)
707 (declare (ignore type))
708 (destructuring-bind (element-type) args
709 #'(lambda (c-vector)
710 (map-counted-vector 'vector #'identity c-vector element-type))))
711
712(defmethod cleanup-form (location (type (eql 'counted-vector)) &rest args)
713 (declare (ignore type))
714 (destructuring-bind (element-type) args
715 `(destroy-counted-vector ,location ',element-type)))
716
717(defmethod writer-function ((type (eql 'counted-vector)) &rest args)
718 (declare (ignore type))
719 (destructuring-bind (element-type) args
720 #'(lambda (vector location &optional (offset 0))
721 (setf
722 (sap-ref-sap location offset)
723 (make-counted-vector element-type vector)))))
724
725(defmethod reader-function ((type (eql 'counted-vector)) &rest args)
726 (declare (ignore type))
727 (destructuring-bind (element-type) args
3005806e 728 #'(lambda (location &optional (offset 0) weak-p)
729 (declare (ignore weak-p))
5e8ceafa 730 (unless (null-pointer-p (sap-ref-sap location offset))
731 (map-counted-vector 'vector #'identity
732 (sap-ref-sap location offset) element-type)))))
733
734(defmethod destroy-function ((type (eql 'counted-vector)) &rest args)
735 (declare (ignore type))
736 (destructuring-bind (element-type) args
737 #'(lambda (location &optional (offset 0))
738 (unless (null-pointer-p (sap-ref-sap location offset))
739 (destroy-counted-vector
740 (sap-ref-sap location offset) element-type)
741 (setf (sap-ref-sap location offset) (make-pointer 0))))))