chiark / gitweb /
Fixed bug in SET-PACKAGE-PREFIX
[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.36 2006-02-26 15:30:01 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(vm::system-area-fill 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 (define-type-method alien-type ((type glist))
183   (declare (ignore type))
184   (alien-type 'pointer))
185
186 (define-type-method size-of ((type glist))
187   (declare (ignore type))
188   (size-of 'pointer))
189
190 (define-type-method to-alien-form ((type glist) list)
191   (let ((element-type (second (type-expand-to 'glist type))))
192     `(make-glist ',element-type ,list)))
193
194 (define-type-method to-alien-function ((type glist))
195   (let ((element-type (second (type-expand-to 'glist type))))
196     #'(lambda (list)
197         (make-glist element-type list))))
198
199 (define-type-method from-alien-form ((type glist) glist)
200   (let ((element-type (second (type-expand-to 'glist type))))
201     `(let ((glist ,glist))
202       (unwind-protect
203            (map-glist 'list #'identity glist ',element-type)
204         (destroy-glist glist ',element-type)))))
205
206 (define-type-method from-alien-function ((type glist))
207   (let ((element-type (second (type-expand-to 'glist type))))
208     #'(lambda (glist)
209         (unwind-protect
210              (map-glist 'list #'identity glist element-type)
211           (destroy-glist glist element-type)))))
212
213 (define-type-method copy-from-alien-form ((type glist) glist)
214   (let ((element-type (second (type-expand-to 'glist type))))
215     `(map-glist 'list #'identity ,glist ',element-type)))
216
217 (define-type-method copy-from-alien-function ((type glist))
218   (let ((element-type (second (type-expand-to 'glist type))))
219     #'(lambda (glist)
220         (map-glist 'list #'identity glist element-type))))
221
222 (define-type-method cleanup-form ((type glist) glist)
223   (let ((element-type (second (type-expand-to 'glist type))))
224     `(destroy-glist ,glist ',element-type)))
225
226 (define-type-method cleanup-function ((type glist))
227   (let ((element-type (second (type-expand-to 'glist type))))
228     #'(lambda (glist)
229         (destroy-glist glist element-type))))
230
231 (define-type-method writer-function ((type glist))
232   (let ((element-type (second (type-expand-to 'glist type))))
233     #'(lambda (list location &optional (offset 0))
234         (setf 
235          (sap-ref-sap location offset)
236          (make-glist element-type list)))))
237
238 (define-type-method reader-function ((type glist))
239   (let ((element-type (second (type-expand-to 'glist type))))
240     #'(lambda (location &optional (offset 0) weak-p)
241         (declare (ignore weak-p))
242         (unless (null-pointer-p (sap-ref-sap location offset))
243           (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
244
245 (define-type-method destroy-function ((type glist))
246   (let ((element-type (second (type-expand-to 'glist type))))
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
253
254 ;;;; Single linked list (GSList)
255
256 (deftype gslist (type) `(or null (cons ,type list)))
257
258 (defbinding (%gslist-prepend "g_slist_prepend") () pointer
259   (gslist pointer)
260   (nil null))
261
262 (defun make-gslist (type list)
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)))
269
270 (defbinding (gslist-free "g_slist_free") () nil
271   (gslist pointer))
272
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))
280
281 (define-type-method alien-type ((type gslist))
282   (declare (ignore type))
283   (alien-type 'pointer))
284
285 (define-type-method size-of ((type gslist))
286   (declare (ignore type))
287   (size-of 'pointer))
288
289 (define-type-method to-alien-form ((type gslist) list)
290   (let ((element-type (second (type-expand-to 'gslist type))))
291     `(make-sglist ',element-type ,list)))
292
293 (define-type-method to-alien-function ((type gslist))
294   (let ((element-type (second (type-expand-to 'gslist type))))
295     #'(lambda (list)
296         (make-gslist element-type list))))
297
298 (define-type-method from-alien-form ((type gslist) gslist)
299   (let ((element-type (second (type-expand-to 'gslist type))))
300     `(let ((gslist ,gslist))
301       (unwind-protect
302            (map-glist 'list #'identity gslist ',element-type)
303         (destroy-gslist gslist ',element-type)))))
304
305 (define-type-method from-alien-function ((type gslist))
306   (let ((element-type (second (type-expand-to 'gslist type))))
307     #'(lambda (gslist)
308         (unwind-protect
309              (map-glist 'list #'identity gslist element-type)
310           (destroy-gslist gslist element-type)))))
311
312 (define-type-method copy-from-alien-form ((type gslist) gslist)
313   (let ((element-type (second (type-expand-to 'gslist type))))
314     `(map-glist 'list #'identity ,gslist ',element-type)))
315
316 (define-type-method copy-from-alien-function ((type gslist))
317   (let ((element-type (second (type-expand-to 'gslist type))))
318     #'(lambda (gslist)
319         (map-glist 'list #'identity gslist element-type))))
320
321 (define-type-method cleanup-form ((type gslist) gslist)
322   (let ((element-type (second (type-expand-to 'gslist type))))
323     `(destroy-gslist ,gslist ',element-type)))
324
325 (define-type-method cleanup-function ((type gslist))
326   (let ((element-type (second (type-expand-to 'gslist type))))
327     #'(lambda (gslist)
328         (destroy-gslist gslist element-type))))
329
330 (define-type-method writer-function ((type gslist))
331   (let ((element-type (second (type-expand-to 'gslist type))))
332     #'(lambda (list location &optional (offset 0))
333         (setf 
334          (sap-ref-sap location offset)
335          (make-gslist element-type list)))))
336
337 (define-type-method reader-function ((type gslist))
338   (let ((element-type (second (type-expand-to 'gslist type))))
339     #'(lambda (location &optional (offset 0) weak-p)
340         (declare (ignore weak-p))
341         (unless (null-pointer-p (sap-ref-sap location offset))
342           (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
343
344 (define-type-method destroy-function ((type gslist))
345   (let ((element-type (second (type-expand-to 'gslist type))))
346     #'(lambda (location &optional (offset 0))
347         (unless (null-pointer-p (sap-ref-sap location offset))
348           (destroy-gslist (sap-ref-sap location offset) element-type)
349           (setf (sap-ref-sap location offset) (make-pointer 0))))))
350
351
352 ;;; Vector
353
354 (defun make-c-vector (type length &optional content location)
355   (let* ((size-of-type (size-of type))
356          (location (or location (allocate-memory (* size-of-type length))))
357          (writer (writer-function type)))
358     (etypecase content
359       (vector
360        (loop
361         for element across content
362         for i from 0 below length
363         as offset = 0 then (+ offset size-of-type)
364         do (funcall writer element location offset)))
365       (list
366        (loop
367         for element in content
368         for i from 0 below length
369         as offset = 0 then (+ offset size-of-type)
370         do (funcall writer element location offset))))
371     location))
372
373
374 (defun map-c-vector (seqtype function location element-type length)
375   (let ((reader (reader-function element-type))
376         (size-of-element (size-of element-type)))
377     (case seqtype 
378      ((nil)
379       (loop
380        for i from 0 below length
381        as offset = 0 then (+ offset size-of-element)
382        do (funcall function (funcall reader location offset))))
383      (list
384       (loop
385        for i from 0 below length
386        as offset = 0 then (+ offset size-of-element)
387        collect (funcall function (funcall reader location offset))))
388      (t
389       (loop
390        with sequence = (make-sequence seqtype length)
391        for i from 0 below length
392        as offset = 0 then (+ offset size-of-element)
393        do (setf 
394            (elt sequence i)
395            (funcall function (funcall reader location offset)))
396        finally (return sequence))))))
397
398
399 (defun destroy-c-vector (location element-type length)
400   (loop
401    with destroy = (destroy-function element-type)
402    with element-size = (size-of element-type)
403    for i from 0 below length
404    as offset = 0 then (+ offset element-size)
405    do (funcall destroy location offset))
406   (deallocate-memory location))
407
408
409 (define-type-method alien-type ((type vector))
410   (declare (ignore type))
411   (alien-type 'pointer))
412
413 (define-type-method size-of ((type vector))
414   (declare (ignore type))
415   (size-of 'pointer))
416
417 (define-type-method to-alien-form ((type vector) vector)
418   (destructuring-bind (element-type &optional (length '*)) 
419       (rest (type-expand-to 'vector type))
420     (if (eq length '*)
421         `(let* ((vector ,vector)
422                 (location (sap+
423                            (allocate-memory (+ ,+size-of-int+ 
424                                                (* ,(size-of element-type) 
425                                                   (length vector))))
426                            ,+size-of-int+)))
427           (make-c-vector ',element-type (length vector) vector location)
428           (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
429           location)       
430       `(make-c-vector ',element-type ,length ,vector))))
431
432 (define-type-method from-alien-form ((type vector) c-vector)
433   (destructuring-bind (element-type &optional (length '*))
434       (rest (type-expand-to 'vector type))
435     (if (eq length '*)
436         (error "Can't use vector of variable size as return type")
437       `(let ((c-vector ,c-vector))
438         (prog1
439             (map-c-vector 'vector #'identity c-vector ',element-type ,length)
440           (destroy-c-vector c-vector ',element-type ,length))))))
441
442 (define-type-method copy-from-alien-form ((type vector) c-vector)
443   (destructuring-bind (element-type &optional (length '*))
444       (rest (type-expand-to 'vector type))
445     (if (eq length '*)
446         (error "Can't use vector of variable size as return type")
447       `(map-c-vector 'vector #'identity ,c-vector ',element-type ,length))))
448
449 (define-type-method copy-from-alien-function ((type vector))
450   (destructuring-bind (element-type &optional (length '*))
451       (rest (type-expand-to 'vector type))
452     (if (eq length '*)
453         (error "Can't use vector of variable size as return type")
454       #'(lambda (c-vector)
455           (map-c-vector 'vector #'identity c-vector element-type length)))))
456
457 (define-type-method cleanup-form ((type vector) location)
458   (destructuring-bind (element-type &optional (length '*))
459       (rest (type-expand-to 'vector type))
460     `(let* ((location ,location)
461             (length ,(if (eq length '*)
462                          `(sap-ref-32 location ,(- +size-of-int+))
463                          length)))
464       (loop
465        with destroy = (destroy-function ',element-type)
466        for i from 0 below length
467        as offset = 0 then (+ offset ,(size-of element-type))
468        do (funcall destroy location offset))
469       (deallocate-memory ,(if (eq length '*) 
470                               `(sap+ location  ,(- +size-of-int+))
471                             'location)))))
472
473 ;; We need these so that we can specify vectors with length given as
474 ;; a non constant in callbacks
475 (define-type-method callback-from-alien-form ((type vector) form)
476   (copy-from-alien-form type form))
477 (define-type-method callback-cleanup-form ((type vector) form)
478   (declare (ignore type form))
479   nil)
480
481
482 (define-type-method writer-function ((type vector))
483   (destructuring-bind (element-type &optional (length '*))
484       (rest (type-expand-to 'vector type))
485     #'(lambda (vector location &optional (offset 0))
486         (setf 
487          (sap-ref-sap location offset)
488          (make-c-vector element-type length vector)))))
489
490 (define-type-method reader-function ((type vector))
491   (destructuring-bind (element-type &optional (length '*))
492       (rest (type-expand-to 'vector type))
493     (if (eq length '*)
494         (error "Can't create reader function for vector of variable size")
495       #'(lambda (location &optional (offset 0) weak-p)
496           (declare (ignore weak-p))
497           (unless (null-pointer-p (sap-ref-sap location offset))
498             (map-c-vector 'vector #'identity (sap-ref-sap location offset) 
499              element-type length))))))
500
501 (define-type-method destroy-function ((type vector))
502   (destructuring-bind (element-type &optional (length '*))
503       (rest (type-expand-to 'vector type))
504     (if (eq length '*)
505         (error "Can't create destroy function for vector of variable size")
506       #'(lambda (location &optional (offset 0))
507           (unless (null-pointer-p (sap-ref-sap location offset))
508             (destroy-c-vector 
509              (sap-ref-sap location offset) element-type length)
510             (setf (sap-ref-sap location offset) (make-pointer 0)))))))
511
512
513 ;;;; Null terminated vector
514
515 (defun make-0-vector (type content &optional location)
516   (let* ((size-of-type (size-of type))
517          (location (or 
518                     location 
519                     (allocate-memory (* size-of-type (1+ (length content))))))
520          (writer (writer-function type)))
521     (etypecase content
522       (vector
523        (loop
524         for element across content
525         as offset = 0 then (+ offset size-of-type)
526         do (funcall writer element location offset)
527         finally (setf (sap-ref-sap location offset) (make-pointer 0))))
528       (list
529        (loop
530         for element in content
531         as offset = 0 then (+ offset size-of-type)
532         do (funcall writer element location offset)
533         finally (setf (sap-ref-sap location (+ offset size-of-type)) (make-pointer 0)))))
534     location))
535
536
537 (defun map-0-vector (seqtype function location element-type)
538   (let ((reader (reader-function element-type))
539         (size-of-element (size-of element-type)))
540     (case seqtype 
541      ((nil)
542       (loop
543        as offset = 0 then (+ offset size-of-element)
544        until (null-pointer-p (sap-ref-sap location offset))
545        do (funcall function (funcall reader location offset))))
546      (list
547       (loop
548        as offset = 0 then (+ offset size-of-element)
549        until (null-pointer-p (sap-ref-sap location offset))
550        collect (funcall function (funcall reader location offset))))
551      (t
552       (coerce 
553        (loop
554         as offset = 0 then (+ offset size-of-element)
555         until (null-pointer-p (sap-ref-sap location offset))
556         collect (funcall function (funcall reader location offset)))
557        seqtype)))))
558
559
560 (defun destroy-0-vector (location element-type)
561   (loop
562    with destroy = (destroy-function element-type)
563    with element-size = (size-of element-type)
564    as offset = 0 then (+ offset element-size)
565    until (null-pointer-p (sap-ref-sap location offset))
566    do (funcall destroy location offset))
567   (deallocate-memory location))
568
569 (deftype null-terminated-vector (element-type) `(vector ,element-type))
570
571 (define-type-method alien-type ((type null-terminated-vector))
572   (declare (ignore type))
573   (alien-type 'pointer))
574
575 (define-type-method size-of ((type null-terminated-vector))
576   (declare (ignore type))
577   (size-of 'pointer))
578
579 (define-type-method to-alien-form ((type null-terminated-vector) vector)
580   (destructuring-bind (element-type)
581       (rest (type-expand-to 'null-terminated-vector type))
582     `(make-0-vector ',element-type ,vector)))
583
584 (define-type-method from-alien-form ((type null-terminated-vector) c-vector)
585   (destructuring-bind (element-type)
586       (rest (type-expand-to 'null-terminated-vector type))
587     `(let ((c-vector ,c-vector))
588        (prog1
589            (map-0-vector 'vector #'identity c-vector ',element-type)
590          (destroy-0-vector c-vector ',element-type)))))
591
592 (define-type-method copy-from-alien-form ((type null-terminated-vector) c-vector)
593   (destructuring-bind (element-type)
594       (rest (type-expand-to 'null-terminated-vector type))
595     `(map-0-vector 'vector #'identity ,c-vector ',element-type)))
596
597 (define-type-method cleanup-form ((type null-terminated-vector) location)
598   (destructuring-bind (element-type)
599       (rest (type-expand-to 'null-terminated-vector type))
600     `(destroy-0-vector ,location ',element-type)))
601
602 (define-type-method writer-function ((type null-terminated-vector))
603   (destructuring-bind (element-type)
604       (rest (type-expand-to 'null-terminated-vector type))
605     (unless (eq (alien-type element-type) (alien-type 'pointer))
606       (error "Elements in null-terminated vectors need to be of pointer types"))
607     #'(lambda (vector location &optional (offset 0))
608         (setf 
609          (sap-ref-sap location offset)
610          (make-0-vector element-type vector)))))
611
612 (define-type-method reader-function ((type null-terminated-vector))
613   (destructuring-bind (element-type)
614       (rest (type-expand-to 'null-terminated-vector type))
615     (unless (eq (alien-type element-type) (alien-type 'pointer))
616       (error "Elements in null-terminated vectors need to be of pointer types"))
617     #'(lambda (location &optional (offset 0) weak-p)
618         (declare (ignore weak-p))
619         (unless (null-pointer-p (sap-ref-sap location offset))
620           (map-0-vector 'vector #'identity (sap-ref-sap location offset) 
621            element-type)))))
622
623 (define-type-method destroy-function ((type null-terminated-vector))
624   (destructuring-bind (element-type)
625       (rest (type-expand-to 'null-terminated-vector type))
626     (unless (eq (alien-type element-type) (alien-type 'pointer))
627       (error "Elements in null-terminated vectors need to be of pointer types"))
628     #'(lambda (location &optional (offset 0))
629           (unless (null-pointer-p (sap-ref-sap location offset))
630             (destroy-0-vector 
631              (sap-ref-sap location offset) element-type)
632             (setf (sap-ref-sap location offset) (make-pointer 0))))))
633
634 (define-type-method unbound-value ((type null-terminated-vector))
635   (declare (ignore type))
636   nil)
637
638
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 (define-type-method alien-type ((type counted-vector))
670   (declare (ignore type))
671   (alien-type 'pointer))
672
673 (define-type-method size-of ((type counted-vector))
674   (declare (ignore type))
675   (size-of 'pointer))
676
677 (define-type-method to-alien-form ((type counted-vector) vector)
678   (destructuring-bind (element-type)
679       (rest (type-expand-to 'counted-vector type))
680     `(make-counted-vector ',element-type ,vector)))
681
682 (define-type-method from-alien-form ((type counted-vector) c-vector)
683   (destructuring-bind (element-type)
684       (rest (type-expand-to 'counted-vector type))
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 (define-type-method copy-from-alien-form ((type counted-vector) c-vector)
691   (destructuring-bind (element-type)
692       (rest (type-expand-to 'counted-vector type))
693     `(map-counted-vector 'vector #'identity ,c-vector ',element-type)))
694
695 (define-type-method copy-from-alien-function ((type counted-vector))
696   (destructuring-bind (element-type)
697       (rest (type-expand-to 'counted-vector type))
698     #'(lambda (c-vector)
699         (map-counted-vector 'vector #'identity c-vector element-type))))
700
701 (define-type-method cleanup-form ((type counted-vector) location)
702   (destructuring-bind (element-type)
703       (rest (type-expand-to 'counted-vector type))
704     `(destroy-counted-vector ,location ',element-type)))
705
706 (define-type-method writer-function ((type counted-vector))
707   (destructuring-bind (element-type)
708       (rest (type-expand-to 'counted-vector type))
709     #'(lambda (vector location &optional (offset 0))
710         (setf 
711          (sap-ref-sap location offset)
712          (make-counted-vector element-type vector)))))
713
714 (define-type-method reader-function ((type counted-vector))
715   (destructuring-bind (element-type)
716       (rest (type-expand-to 'counted-vector type))
717     #'(lambda (location &optional (offset 0) weak-p)
718         (declare (ignore weak-p))
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 (define-type-method destroy-function ((type counted-vector))
724   (destructuring-bind (element-type)
725       (rest (type-expand-to 'counted-vector type))
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))))))