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