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