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