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