chiark / gitweb /
Replaced WEAK-READER-FUNCTION with optional WEAK-P argument to standard reader functions
[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.32 2006-02-06 18:12:19 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) weak-p)
234         (declare (ignore weak-p))
235         (unless (null-pointer-p (sap-ref-sap location offset))
236           (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
237
238 (defmethod destroy-function ((type (eql 'glist)) &rest args)
239   (declare (ignore type))
240   (destructuring-bind (element-type) args
241     #'(lambda (location &optional (offset 0))
242         (unless (null-pointer-p (sap-ref-sap location offset))
243           (destroy-glist (sap-ref-sap location offset) element-type)
244           (setf (sap-ref-sap location offset) (make-pointer 0))))))
245
246
247
248 ;;;; Single linked list (GSList)
249
250 (deftype gslist (type) `(or (null (cons ,type list))))
251
252 (defbinding (%gslist-prepend "g_slist_prepend") () pointer
253   (gslist pointer)
254   (nil null))
255
256 (defun make-gslist (type list)
257   (loop
258    with writer = (writer-function type)
259    for element in (reverse list)
260    as gslist = (%gslist-prepend (or gslist (make-pointer 0)))
261    do (funcall writer element gslist)
262    finally (return gslist)))
263
264 (defbinding (gslist-free "g_slist_free") () nil
265   (gslist pointer))
266
267 (defun destroy-gslist (gslist element-type)
268   (loop
269    with destroy = (destroy-function element-type)
270    as tmp = gslist then (glist-next tmp)
271    until (null-pointer-p tmp)
272    do (funcall destroy tmp 0))
273   (gslist-free gslist))
274
275 (defmethod alien-type ((type (eql 'gslist)) &rest args)
276   (declare (ignore type args))
277   (alien-type 'pointer))
278
279 (defmethod size-of ((type (eql 'gslist)) &rest args)
280   (declare (ignore type args))
281   (size-of 'pointer))
282
283 (defmethod to-alien-form (list (type (eql 'gslist)) &rest args)
284   (declare (ignore type))
285   (destructuring-bind (element-type) args    
286     `(make-sglist ',element-type ,list)))
287
288 (defmethod to-alien-function ((type (eql 'gslist)) &rest args)
289   (declare (ignore type))
290   (destructuring-bind (element-type) args    
291     #'(lambda (list)
292         (make-gslist element-type list))))
293
294 (defmethod from-alien-form (gslist (type (eql 'gslist)) &rest args)
295   (declare (ignore type))
296   (destructuring-bind (element-type) args
297     `(let ((gslist ,gslist))
298       (unwind-protect
299            (map-glist 'list #'identity gslist ',element-type)
300         (destroy-gslist gslist ',element-type)))))
301
302 (defmethod from-alien-function ((type (eql 'gslist)) &rest args)
303   (declare (ignore type))
304   (destructuring-bind (element-type) args
305     #'(lambda (gslist)
306         (unwind-protect
307              (map-glist 'list #'identity gslist element-type)
308           (destroy-gslist gslist element-type)))))
309
310 (defmethod copy-from-alien-form (gslist (type (eql 'gslist)) &rest args)
311   (declare (ignore type))
312   (destructuring-bind (element-type) args
313     `(map-glist 'list #'identity ,gslist ',element-type)))
314
315 (defmethod copy-from-alien-function ((type (eql 'gslist)) &rest args)
316   (declare (ignore type))
317   (destructuring-bind (element-type) args
318     #'(lambda (gslist)
319         (map-glist 'list #'identity gslist element-type))))
320
321 (defmethod cleanup-form (gslist (type (eql 'gslist)) &rest args)
322   (declare (ignore type))
323   (destructuring-bind (element-type) args
324     `(destroy-gslist ,gslist ',element-type)))
325
326 (defmethod cleanup-function ((type (eql 'gslist)) &rest args)
327   (declare (ignore type))
328   (destructuring-bind (element-type) args
329     #'(lambda (gslist)
330         (destroy-gslist gslist element-type))))
331
332 (defmethod writer-function ((type (eql 'gslist)) &rest args)
333   (declare (ignore type))
334   (destructuring-bind (element-type) args
335     #'(lambda (list location &optional (offset 0))
336         (setf 
337          (sap-ref-sap location offset)
338          (make-gslist element-type list)))))
339
340 (defmethod reader-function ((type (eql 'gslist)) &rest args)
341   (declare (ignore type))
342   (destructuring-bind (element-type) args
343     #'(lambda (location &optional (offset 0) weak-p)
344         (declare (ignore weak-p))
345         (unless (null-pointer-p (sap-ref-sap location offset))
346           (map-glist 'list #'identity (sap-ref-sap location offset) element-type)))))
347
348 (defmethod destroy-function ((type (eql 'gslist)) &rest args)
349   (declare (ignore type))
350   (destructuring-bind (element-type) args
351     #'(lambda (location &optional (offset 0))
352         (unless (null-pointer-p (sap-ref-sap location offset))
353           (destroy-gslist (sap-ref-sap location offset) element-type)
354           (setf (sap-ref-sap location offset) (make-pointer 0))))))
355
356
357 ;;; Vector
358
359 (defun make-c-vector (type length &optional content location)
360   (let* ((size-of-type (size-of type))
361          (location (or location (allocate-memory (* size-of-type length))))
362          (writer (writer-function type)))
363     (etypecase content
364       (vector
365        (loop
366         for element across content
367         for i from 0 below length
368         as offset = 0 then (+ offset size-of-type)
369         do (funcall writer element location offset)))
370       (list
371        (loop
372         for element in content
373         for i from 0 below length
374         as offset = 0 then (+ offset size-of-type)
375         do (funcall writer element location offset))))
376     location))
377
378
379 (defun map-c-vector (seqtype function location element-type length)
380   (let ((reader (reader-function element-type))
381         (size-of-element (size-of element-type)))
382     (case seqtype 
383      ((nil)
384       (loop
385        for i from 0 below length
386        as offset = 0 then (+ offset size-of-element)
387        do (funcall function (funcall reader location offset))))
388      (list
389       (loop
390        for i from 0 below length
391        as offset = 0 then (+ offset size-of-element)
392        collect (funcall function (funcall reader location offset))))
393      (t
394       (loop
395        with sequence = (make-sequence seqtype length)
396        for i from 0 below length
397        as offset = 0 then (+ offset size-of-element)
398        do (setf 
399            (elt sequence i)
400            (funcall function (funcall reader location offset)))
401        finally (return sequence))))))
402
403
404 (defun destroy-c-vector (location element-type length)
405   (loop
406    with destroy = (destroy-function element-type)
407    with element-size = (size-of element-type)
408    for i from 0 below length
409    as offset = 0 then (+ offset element-size)
410    do (funcall destroy location offset))
411   (deallocate-memory location))
412
413
414 (defmethod alien-type ((type (eql 'vector)) &rest args)
415   (declare (ignore type args))
416   (alien-type 'pointer))
417
418 (defmethod size-of ((type (eql 'vector)) &rest args)
419   (declare (ignore type args))
420   (size-of 'pointer))
421
422 (defmethod to-alien-form (vector (type (eql 'vector)) &rest args)
423   (declare (ignore type))
424   (destructuring-bind (element-type &optional (length '*)) args
425     (if (eq length '*)
426         `(let* ((vector ,vector)
427                 (location (sap+
428                            (allocate-memory (+ ,+size-of-int+ 
429                                                (* ,(size-of element-type) 
430                                                   (length vector))))
431                            ,+size-of-int+)))
432           (make-c-vector ',element-type (length vector) vector location)
433           (setf (sap-ref-32 location ,(- +size-of-int+)) (length vector))
434           location)       
435       `(make-c-vector ',element-type ,length ,vector))))
436
437 (defmethod from-alien-form (c-vector (type (eql 'vector)) &rest args)
438   (declare (ignore type))
439   (destructuring-bind (element-type &optional (length '*)) args
440     (if (eq length '*)
441         (error "Can't use vector of variable size as return type")
442       `(let ((c-vector ,c-vector))
443         (prog1
444             (map-c-vector 'vector #'identity c-vector ',element-type ,length)
445           (destroy-c-vector c-vector ',element-type ,length))))))
446
447 (defmethod copy-from-alien-form (c-vector (type (eql 'vector)) &rest args)
448   (declare (ignore type))
449   (destructuring-bind (element-type &optional (length '*)) args
450     (if (eq length '*)
451         (error "Can't use vector of variable size as return type")
452       `(map-c-vector 'vector #'identity ,c-vector ',element-type ,length))))
453
454 (defmethod copy-from-alien-function ((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       #'(lambda (c-vector)
460           (map-c-vector 'vector #'identity c-vector element-type length)))))
461
462 (defmethod cleanup-form (location (type (eql 'vector)) &rest args)
463   (declare (ignore type))
464   (destructuring-bind (element-type &optional (length '*)) args
465     `(let* ((location ,location)
466             (length ,(if (eq length '*)
467                          `(sap-ref-32 location ,(- +size-of-int+))
468                          length)))
469       (loop
470        with destroy = (destroy-function ',element-type)
471        for i from 0 below length
472        as offset = 0 then (+ offset ,(size-of element-type))
473        do (funcall destroy location offset))
474       (deallocate-memory ,(if (eq length '*) 
475                               `(sap+ location  ,(- +size-of-int+))
476                             'location)))))
477
478 (defmethod writer-function ((type (eql 'vector)) &rest args)
479   (declare (ignore type))
480   (destructuring-bind (element-type &optional (length '*)) args
481     #'(lambda (vector location &optional (offset 0))
482         (setf 
483          (sap-ref-sap location offset)
484          (make-c-vector element-type length vector)))))
485
486 (defmethod reader-function ((type (eql 'vector)) &rest args)
487   (declare (ignore type))
488   (destructuring-bind (element-type &optional (length '*)) args
489     (if (eq length '*)
490         (error "Can't create reader function for vector of variable size")
491       #'(lambda (location &optional (offset 0) weak-p)
492           (declare (ignore weak-p))
493           (unless (null-pointer-p (sap-ref-sap location offset))
494             (map-c-vector 'vector #'identity (sap-ref-sap location offset) 
495              element-type length))))))
496
497 (defmethod destroy-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 destroy function for vector of variable size")
502       #'(lambda (location &optional (offset 0))
503           (unless (null-pointer-p (sap-ref-sap location offset))
504             (destroy-c-vector 
505              (sap-ref-sap location offset) element-type length)
506             (setf (sap-ref-sap location offset) (make-pointer 0)))))))
507
508
509 ;;;; Null terminated vector
510
511 (defun make-0-vector (type content &optional location)
512   (let* ((size-of-type (size-of type))
513          (location (or 
514                     location 
515                     (allocate-memory (* size-of-type (1+ (length content))))))
516          (writer (writer-function type)))
517     (etypecase content
518       (vector
519        (loop
520         for element across content
521         as offset = 0 then (+ offset size-of-type)
522         do (funcall writer element location offset)
523         finally (setf (sap-ref-sap location offset) (make-pointer 0))))
524       (list
525        (loop
526         for element in content
527         as offset = 0 then (+ offset size-of-type)
528         do (funcall writer element location offset)
529         finally (setf (sap-ref-sap location (+ offset size-of-type)) (make-pointer 0)))))
530     location))
531
532
533 (defun map-0-vector (seqtype function location element-type)
534   (let ((reader (reader-function element-type))
535         (size-of-element (size-of element-type)))
536     (case seqtype 
537      ((nil)
538       (loop
539        as offset = 0 then (+ offset size-of-element)
540        until (null-pointer-p (sap-ref-sap location offset))
541        do (funcall function (funcall reader location offset))))
542      (list
543       (loop
544        as offset = 0 then (+ offset size-of-element)
545        until (null-pointer-p (sap-ref-sap location offset))
546        collect (funcall function (funcall reader location offset))))
547      (t
548       (coerce 
549        (loop
550         as offset = 0 then (+ offset size-of-element)
551         until (null-pointer-p (sap-ref-sap location offset))
552         collect (funcall function (funcall reader location offset)))
553        seqtype)))))
554
555
556 (defun destroy-0-vector (location element-type)
557   (loop
558    with destroy = (destroy-function element-type)
559    with element-size = (size-of element-type)
560    as offset = 0 then (+ offset element-size)
561    until (null-pointer-p (sap-ref-sap location offset))
562    do (funcall destroy location offset))
563   (deallocate-memory location))
564
565 (deftype null-terminated-vector (element-type) `(vector ,element-type))
566
567 (defmethod alien-type ((type (eql 'null-terminated-vector)) &rest args)
568   (declare (ignore type args))
569   (alien-type 'pointer))
570
571 (defmethod size-of ((type (eql 'null-terminated-vector)) &rest args)
572   (declare (ignore type args))
573   (size-of 'pointer))
574
575 (defmethod to-alien-form (vector (type (eql 'null-terminated-vector)) &rest args)
576   (declare (ignore type))
577   (destructuring-bind (element-type) args
578     `(make-0-vector ',element-type ,vector)))
579
580 (defmethod from-alien-form (c-vector (type (eql 'null-terminated-vector)) &rest args)
581   (declare (ignore type))
582   (destructuring-bind (element-type) args
583     `(let ((c-vector ,c-vector))
584        (prog1
585            (map-0-vector 'vector #'identity c-vector ',element-type)
586          (destroy-0-vector c-vector ',element-type)))))
587
588 (defmethod copy-from-alien-form (c-vector (type (eql 'null-terminated-vector)) &rest args)
589   (declare (ignore type))
590   (destructuring-bind (element-type) args
591     `(map-0-vector 'vector #'identity ,c-vector ',element-type)))
592
593 (defmethod cleanup-form (location (type (eql 'null-terminated-vector)) &rest args)
594   (declare (ignore type))
595   (destructuring-bind (element-type) args
596     `(destroy-0-vector ,location ',element-type)))
597
598 (defmethod writer-function ((type (eql 'null-terminated-vector)) &rest args)
599   (declare (ignore type))
600   (destructuring-bind (element-type) args
601     (unless (eq (alien-type element-type) (alien-type 'pointer))
602       (error "Elements in null-terminated vectors need to be of pointer types"))
603     #'(lambda (vector location &optional (offset 0))
604         (setf 
605          (sap-ref-sap location offset)
606          (make-0-vector element-type vector)))))
607
608 (defmethod reader-function ((type (eql 'null-terminated-vector)) &rest args)
609   (declare (ignore type))
610   (destructuring-bind (element-type) args
611     (unless (eq (alien-type element-type) (alien-type 'pointer))
612       (error "Elements in null-terminated vectors need to be of pointer types"))
613     #'(lambda (location &optional (offset 0) weak-p)
614         (declare (ignore weak-p))
615         (unless (null-pointer-p (sap-ref-sap location offset))
616           (map-0-vector 'vector #'identity (sap-ref-sap location offset) 
617            element-type)))))
618
619 (defmethod destroy-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))
625           (unless (null-pointer-p (sap-ref-sap location offset))
626             (destroy-0-vector 
627              (sap-ref-sap location offset) element-type)
628             (setf (sap-ref-sap location offset) (make-pointer 0))))))
629
630 (defmethod unbound-value ((type (eql 'null-terminated-vector)) &rest args)
631   (declare (ignore type args))
632   (values t nil))
633
634
635 ;;; Counted vector
636
637 (defun make-counted-vector (type content)
638   (let* ((size-of-type (size-of type))
639          (length (length content))
640          (location 
641           (allocate-memory (+ +size-of-int+ (* size-of-type length)))))
642     (setf (sap-ref-32 location 0) length)
643     (make-c-vector type length content (sap+ location +size-of-int+))))
644
645 (defun map-counted-vector (seqtype function location element-type)
646   (let ((length (sap-ref-32 location 0)))
647     (map-c-vector 
648      seqtype function (sap+ location +size-of-int+)
649      element-type length)))
650
651 (defun destroy-counted-vector (location element-type)
652   (loop
653    with destroy = (destroy-function element-type)
654    with element-size = (size-of element-type)
655    for i from 0 below (sap-ref-32 location 0)
656    as offset = +size-of-int+ then (+ offset element-size)
657    do (funcall destroy location offset))
658   (deallocate-memory location))
659
660
661 (deftype counted-vector (element-type) `(vector ,element-type))
662
663 (defmethod alien-type ((type (eql 'counted-vector)) &rest args)
664   (declare (ignore type args))
665   (alien-type 'pointer))
666
667 (defmethod size-of ((type (eql 'counted-vector)) &rest args)
668   (declare (ignore type args))
669   (size-of 'pointer))
670
671 (defmethod to-alien-form (vector (type (eql 'counted-vector)) &rest args)
672   (declare (ignore type))
673   (destructuring-bind (element-type) args
674     `(make-counted-vector ',element-type ,vector)))
675
676 (defmethod from-alien-form (c-vector (type (eql 'counted-vector)) &rest args)
677   (declare (ignore type))
678   (destructuring-bind (element-type) args
679     `(let ((c-vector ,c-vector))
680        (prog1
681            (map-counted-vector 'vector #'identity c-vector ',element-type)
682          (destroy-counted-vector c-vector ',element-type)))))
683
684 (defmethod copy-from-alien-form (c-vector (type (eql 'counted-vector)) &rest args)
685   (declare (ignore type))
686   (destructuring-bind (element-type) args
687     `(map-counted-vector 'vector #'identity ,c-vector ',element-type)))
688
689 (defmethod copy-from-alien-function ((type (eql 'counted-vector)) &rest args)
690   (declare (ignore type))
691   (destructuring-bind (element-type) args
692     #'(lambda (c-vector)
693         (map-counted-vector 'vector #'identity c-vector element-type))))
694
695 (defmethod cleanup-form (location (type (eql 'counted-vector)) &rest args)
696   (declare (ignore type))
697   (destructuring-bind (element-type) args
698     `(destroy-counted-vector ,location ',element-type)))
699
700 (defmethod writer-function ((type (eql 'counted-vector)) &rest args)
701   (declare (ignore type))
702   (destructuring-bind (element-type) args
703     #'(lambda (vector location &optional (offset 0))
704         (setf 
705          (sap-ref-sap location offset)
706          (make-counted-vector element-type vector)))))
707
708 (defmethod reader-function ((type (eql 'counted-vector)) &rest args)
709   (declare (ignore type))
710   (destructuring-bind (element-type) args
711     #'(lambda (location &optional (offset 0) weak-p)
712         (declare (ignore weak-p))
713         (unless (null-pointer-p (sap-ref-sap location offset))
714           (map-counted-vector 'vector #'identity 
715            (sap-ref-sap location offset) element-type)))))
716
717 (defmethod destroy-function ((type (eql 'counted-vector)) &rest args)
718   (declare (ignore type))
719   (destructuring-bind (element-type) args
720     #'(lambda (location &optional (offset 0))
721         (unless (null-pointer-p (sap-ref-sap location offset))
722           (destroy-counted-vector 
723            (sap-ref-sap location offset) element-type)
724           (setf (sap-ref-sap location offset) (make-pointer 0))))))