chiark / gitweb /
Modified WITH-ALLOCATED-MEMORY to use stack allocation when possible
[clg] / glib / glib.lisp
1 ;; Common Lisp bindings for GTK+ 2.x
2 ;; Copyright 1999-2005 Espen S. Johnsen <espen@users.sf.net>
3 ;;
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:
11 ;;
12 ;; The above copyright notice and this permission notice shall be
13 ;; included in all copies or substantial portions of the Software.
14 ;;
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
23 ;; $Id: glib.lisp,v 1.34 2006-02-15 09:53:42 espen Exp $
24
25
26 (in-package "GLIB")
27
28 (use-prefix "g")
29
30
31 ;;;; Memory management
32
33 (defbinding (allocate-memory "g_malloc0") () pointer
34   (size unsigned-long))
35
36 (defbinding (reallocate-memory "g_realloc") () pointer
37   (address pointer)
38   (size unsigned-long))
39
40 (defbinding (deallocate-memory "g_free") () nil
41   (address pointer))
42 ;; (defun deallocate-memory (address)
43 ;;   (declare (ignore address)))
44
45 (defun copy-memory (from length &optional (to (allocate-memory length)))
46   #+cmu(system-area-copy from 0 to 0 (* 8 length))
47   #+sbcl(system-area-ub8-copy from 0 to 0 length)
48   to)
49
50 (defmacro with-allocated-memory ((var size) &body body)
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)))))
60
61
62 ;;;; User data mechanism
63
64 (internal *user-data* *user-data-count*)
65
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
82 (defun user-data-exists-p (id)
83   (nth-value 1 (find-user-data id)))
84
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
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
102
103 ;;;; Quarks
104
105 (deftype quark () 'unsigned)
106
107 (defbinding %quark-from-string () quark
108   (string string))
109
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)))))
117
118 (defbinding quark-to-string () (copy-of string)
119   (quark quark))
120
121
122 ;;;; Linked list (GList)
123
124 (deftype glist (type) 
125   `(or (null (cons ,type list))))
126
127 (defbinding (%glist-append "g_list_append") () pointer
128   (glist pointer)
129   (nil null))
130
131 (defun make-glist (type list)
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)))
138
139 (defun glist-next (glist)
140   (unless (null-pointer-p glist)
141     (sap-ref-sap glist +size-of-pointer+)))
142   
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
165 (defbinding (glist-free "g_list_free") () nil
166   (glist pointer))
167
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))
175
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))
182   (size-of 'pointer))
183
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)
190   (declare (ignore type))
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
198     `(let ((glist ,glist))
199       (unwind-protect
200            (map-glist 'list #'identity glist ',element-type)
201         (destroy-glist glist ',element-type)))))
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)
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))))
221
222 (defmethod cleanup-form (glist (type (eql 'glist)) &rest args)
223   (declare (ignore type))
224   (destructuring-bind (element-type) args
225     `(destroy-glist ,glist ',element-type)))
226
227 (defmethod cleanup-function ((type (eql 'glist)) &rest args)
228   (declare (ignore type))
229   (destructuring-bind (element-type) args
230     #'(lambda (glist)
231         (destroy-glist glist element-type))))
232
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
244     #'(lambda (location &optional (offset 0) weak-p)
245         (declare (ignore weak-p))
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
258
259 ;;;; Single linked list (GSList)
260
261 (deftype gslist (type) `(or (null (cons ,type list))))
262
263 (defbinding (%gslist-prepend "g_slist_prepend") () pointer
264   (gslist pointer)
265   (nil null))
266
267 (defun make-gslist (type list)
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)))
274
275 (defbinding (gslist-free "g_slist_free") () nil
276   (gslist pointer))
277
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))
285
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))
292   (size-of 'pointer))
293
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)
300   (declare (ignore type))
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
308     `(let ((gslist ,gslist))
309       (unwind-protect
310            (map-glist 'list #'identity gslist ',element-type)
311         (destroy-gslist gslist ',element-type)))))
312
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)
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
326 (defmethod copy-from-alien-function ((type (eql 'gslist)) &rest args)
327   (declare (ignore type))
328   (destructuring-bind (element-type) args
329     #'(lambda (gslist)
330         (map-glist 'list #'identity gslist element-type))))
331
332 (defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
333   (declare (ignore type))
334   (destructuring-bind (element-type) args
335     `(destroy-gslist ,gslist ',element-type)))
336
337 (defmethod cleanup-function ((type (eql 'gslist)) &rest args)
338   (declare (ignore type))
339   (destructuring-bind (element-type) args
340     #'(lambda (gslist)
341         (destroy-gslist gslist element-type))))
342
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
354     #'(lambda (location &optional (offset 0) weak-p)
355         (declare (ignore weak-p))
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))))))
366
367
368 ;;; Vector
369
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)))
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))))
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)))
393     (case seqtype 
394      ((nil)
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))))
399      (list
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))))
404      (t
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 
410            (elt sequence i)
411            (funcall function (funcall reader location offset)))
412        finally (return sequence))))))
413
414
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
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
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
455             (map-c-vector 'vector #'identity c-vector ',element-type ,length)
456           (destroy-c-vector c-vector ',element-type ,length))))))
457
458 (defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
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")
463       `(map-c-vector 'vector #'identity ,c-vector ',element-type ,length))))
464
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
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)))))
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")
502       #'(lambda (location &optional (offset 0) weak-p)
503           (declare (ignore weak-p))
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)))))))
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
576 (deftype null-terminated-vector (element-type) `(vector ,element-type))
577
578 (defmethod alien-type ((type (eql 'null-terminated-vector)) &rest args)
579   (declare (ignore type args))
580   (alien-type 'pointer))
581
582 (defmethod size-of ((type (eql 'null-terminated-vector)) &rest args)
583   (declare (ignore type args))
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)))
608
609 (defmethod writer-function ((type (eql 'null-terminated-vector)) &rest args)
610   (declare (ignore type))
611   (destructuring-bind (element-type) args
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
619 (defmethod reader-function ((type (eql 'null-terminated-vector)) &rest args)
620   (declare (ignore type))
621   (destructuring-bind (element-type) args
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) weak-p)
625         (declare (ignore weak-p))
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
630 (defmethod destroy-function ((type (eql 'null-terminated-vector)) &rest args)
631   (declare (ignore type))
632   (destructuring-bind (element-type) args
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))
637             (destroy-0-vector 
638              (sap-ref-sap location offset) element-type)
639             (setf (sap-ref-sap location offset) (make-pointer 0))))))
640
641 (defmethod unbound-value ((type (eql 'null-terminated-vector)) &rest args)
642   (declare (ignore type args))
643   (values t nil))
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
722     #'(lambda (location &optional (offset 0) weak-p)
723         (declare (ignore weak-p))
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))))))