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