chiark / gitweb /
Removed dependency of some internal PCL symbols
[clg] / glib / proxy.lisp
CommitLineData
55212af1 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
b44caf77 3;;
55212af1 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:
b44caf77 11;;
55212af1 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
b44caf77 14;;
55212af1 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.
b44caf77 22
c23cc486 23;; $Id: proxy.lisp,v 1.33 2006/02/15 09:45:41 espen Exp $
b44caf77 24
25(in-package "GLIB")
26
b44caf77 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 30 (defclass virtual-slots-class (standard-class)
935a783c 31 ())
b44caf77 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
ba25fa44 34 ((setter :reader slot-definition-setter :initarg :setter)
935a783c 35 (getter :reader slot-definition-getter :initarg :getter)
64bce834 36 (unbound :reader slot-definition-unbound :initarg :unbound)
935a783c 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
b44caf77 38
935a783c 39 (defclass effective-virtual-slot-definition (standard-effective-slot-definition)
40 ((setter :reader slot-definition-setter :initarg :setter)
41 (getter :reader slot-definition-getter :initarg :getter)
64bce834 42 (unbound :reader slot-definition-unbound :initarg :unbound)
82defe4d 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
935a783c 44
82defe4d 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
c23cc486 46 ((special :initarg :special :accessor slot-definition-special)))
b44caf77 47
82defe4d 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
c23cc486 49 ((special :initarg :special :accessor slot-definition-special))))
82defe4d 50
51(defvar *unbound-marker* (gensym "UNBOUND-MARKER-"))
52
53(defun most-specific-slot-value (instances slot &optional (default *unbound-marker*))
54 (let ((object (find-if
55 #'(lambda (ob)
56 (and (slot-exists-p ob slot) (slot-boundp ob slot)))
57 instances)))
58 (if object
59 (slot-value object slot)
60 default)))
61
b44caf77 62
6baf860c 63(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 64 (cond
65 ((eq (getf initargs :allocation) :virtual)
66 (find-class 'direct-virtual-slot-definition))
67 ((getf initargs :special)
68 (find-class 'direct-special-slot-definition))
69 (t (call-next-method))))
b44caf77 70
6baf860c 71(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
c23cc486 72 (cond
73 ((eq (getf initargs :allocation) :virtual)
74 (find-class 'effective-virtual-slot-definition))
75 ((getf initargs :special)
76 (find-class 'effective-special-slot-definition))
77 (t (call-next-method))))
b44caf77 78
935a783c 79
80(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
64bce834 81 (if (not (slot-boundp slotd 'getter))
82 (setf
935a783c 83 (slot-value slotd 'reader-function)
64bce834 84 #'(lambda (object)
85 (declare (ignore object))
adcadd53 86 (error "Slot is not readable: ~A" (slot-definition-name slotd)))
64bce834 87 (slot-value slotd 'boundp-function)
88 #'(lambda (object) (declare (ignore object)) nil))
89
90 (let ((getter-function
91 (let ((getter (slot-value slotd 'getter)))
92 (etypecase getter
93 (function getter)
94 (symbol
95 #'(lambda (object)
96 (funcall getter object)))
97 (string
98 (let ((reader nil))
99 (setf (slot-value slotd 'reader-function)
100 #'(lambda (object)
101 (unless reader
b6bf802c 102 (setq reader
103 (mkbinding getter
104 (slot-definition-type slotd) 'pointer)))
7ce0497d 105 (funcall reader (foreign-location object))))))))))
64bce834 106
935a783c 107 (setf
64bce834 108 (slot-value slotd 'boundp-function)
109 (cond
64bce834 110 ((slot-boundp slotd 'unbound)
111 (let ((unbound-value (slot-value slotd 'unbound)))
b6bf802c 112 #'(lambda (object)
113 (not (eq (funcall getter-function object) unbound-value)))))
114 ((slot-boundp slotd 'boundp)
115 (let ((boundp (slot-value slotd 'boundp)))
64bce834 116 (etypecase boundp
117 (function boundp)
118 (symbol #'(lambda (object)
119 (funcall boundp object)))
120 (string (let ((reader ()))
121 #'(lambda (object)
122 (unless reader
123 (setq reader
124 (mkbinding boundp
125 (slot-definition-type slotd) 'pointer)))
7ce0497d 126 (funcall reader (foreign-location object))))))))
b6bf802c 127 ((multiple-value-bind (unbound-p unbound-value)
128 (unbound-value (slot-definition-type slotd))
129 (when unbound-p
130 #'(lambda (object)
131 (not (eq (funcall getter-function object) unbound-value))))))
132 (#'(lambda (object) (declare (ignore object)) t))))
64bce834 133
134 (setf
135 (slot-value slotd 'reader-function)
136 (cond
137 ((slot-boundp slotd 'unbound)
138 (let ((unbound (slot-value slotd 'unbound))
139 (slot-name (slot-definition-name slotd)))
b6bf802c 140 #'(lambda (object)
141 (let ((value (funcall getter-function object)))
142 (if (eq value unbound)
143 (slot-unbound (class-of object) object slot-name)
144 value)))))
64bce834 145 ((slot-boundp slotd 'boundp)
146 (let ((boundp-function (slot-value slotd 'boundp-function)))
b6bf802c 147 #'(lambda (object)
148 (and
149 (funcall boundp-function object)
150 (funcall getter-function object)))))
151 ((multiple-value-bind (unbound-p unbound-value)
152 (unbound-value (slot-definition-type slotd))
153 (let ((slot-name (slot-definition-name slotd)))
154 (when unbound-p
155 #'(lambda (object)
156 (let ((value (funcall getter-function object)))
157 (if (eq value unbound-value)
158 (slot-unbound (class-of object) object slot-name)
159 value)))))))
64bce834 160 (getter-function)))))
161
162 (setf
163 (slot-value slotd 'writer-function)
164 (if (not (slot-boundp slotd 'setter))
adcadd53 165 #'(lambda (value object)
166 (declare (ignore value object))
167 (error "Slot is not writable: ~A" (slot-definition-name slotd)))
64bce834 168 (with-slots (setter) slotd
935a783c 169 (etypecase setter
170 (function setter)
64bce834 171 ((or symbol cons)
172 #'(lambda (value object)
173 (funcall (fdefinition setter) value object)))
0466f75e 174 (string
64bce834 175 (let ((writer ()))
176 (setf
177 (slot-value slotd 'writer-function)
178 #'(lambda (value object)
179 (unless writer
180 (setq writer
181 (mkbinding setter 'nil 'pointer
182 (slot-definition-type slotd))))
7ce0497d 183 (funcall writer (foreign-location object) value)))))))))
64bce834 184
3d2378de 185 #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
935a783c 186
187
188
64bce834 189(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
935a783c 190 nil)
191
6baf860c 192(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
c23cc486 193 (typecase (first direct-slotds)
194 (direct-virtual-slot-definition
195 (let ((initargs ()))
196 (let ((getter (most-specific-slot-value direct-slotds 'getter)))
197 (unless (eq getter *unbound-marker*)
198 (setf (getf initargs :getter) getter)))
199 (let ((setter (most-specific-slot-value direct-slotds 'setter)))
200 (unless (eq setter *unbound-marker*)
201 (setf (getf initargs :setter) setter)))
202 (let ((unbound (most-specific-slot-value direct-slotds 'unbound)))
203 (unless (eq unbound *unbound-marker*)
204 (setf (getf initargs :unbound) unbound)))
205 (let ((boundp (most-specific-slot-value direct-slotds 'boundp)))
206 (unless (eq boundp *unbound-marker*)
207 (setf (getf initargs :boundp) boundp)))
208 (nconc initargs (call-next-method))))
209 (direct-special-slot-definition
210 (append '(:special t) (call-next-method)))
211 (t (call-next-method))))
935a783c 212
b44caf77 213
b44caf77 214(defmethod slot-value-using-class
6baf860c 215 ((class virtual-slots-class) (object standard-object)
b44caf77 216 (slotd effective-virtual-slot-definition))
935a783c 217 (if (funcall (slot-value slotd 'boundp-function) object)
218 (funcall (slot-value slotd 'reader-function) object)
219 (slot-unbound class object (slot-definition-name slotd))))
b44caf77 220
b44caf77 221(defmethod slot-boundp-using-class
6baf860c 222 ((class virtual-slots-class) (object standard-object)
b44caf77 223 (slotd effective-virtual-slot-definition))
935a783c 224 (funcall (slot-value slotd 'boundp-function) object))
225
226(defmethod (setf slot-value-using-class)
6baf860c 227 (value (class virtual-slots-class) (object standard-object)
b44caf77 228 (slotd effective-virtual-slot-definition))
935a783c 229 (funcall (slot-value slotd 'writer-function) value object))
230
231
b44caf77 232(defmethod validate-superclass
6baf860c 233 ((class virtual-slots-class) (super standard-class))
b44caf77 234 t)
235
236
c23cc486 237(defmethod slot-definition-special ((slotd standard-direct-slot-definition))
238 (declare (ignore slotd))
239 nil)
240
241(defmethod slot-definition-special ((slotd standard-effective-slot-definition))
242 (declare (ignore slotd))
243 nil)
244
245
b44caf77 246;;;; Proxy cache
247
b44caf77 248(defvar *instance-cache* (make-hash-table :test #'eql))
249
a2bc0f3a 250(defun cache-instance (instance &optional (weak-ref t))
b44caf77 251 (setf
7ce0497d 252 (gethash (sap-int (foreign-location instance)) *instance-cache*)
a2bc0f3a 253 (if weak-ref
254 (make-weak-pointer instance)
255 instance)))
b44caf77 256
257(defun find-cached-instance (location)
3d36c5d6 258 (let ((ref (gethash (sap-int location) *instance-cache*)))
b44caf77 259 (when ref
a2bc0f3a 260 (if (weak-pointer-p ref)
261 (weak-pointer-value ref)
262 ref))))
b44caf77 263
a5c3a597 264(defun instance-cached-p (location)
3d36c5d6 265 (gethash (sap-int location) *instance-cache*))
a5c3a597 266
b44caf77 267(defun remove-cached-instance (location)
3d36c5d6 268 (remhash (sap-int location) *instance-cache*))
b44caf77 269
6baf860c 270;; For debuging
a2bc0f3a 271(defun list-cached-instances ()
6baf860c 272 (let ((instances ()))
273 (maphash #'(lambda (location ref)
274 (declare (ignore location))
a2bc0f3a 275 (push ref instances))
6baf860c 276 *instance-cache*)
277 instances))
278
2a9afe6f 279;; Instances that gets invalidated tend to be short lived, but created
280;; in large numbers. So we're keeping them in a hash table to be able
281;; to reuse them (and thus reduce consing)
282(defvar *invalidated-instance-cache* (make-hash-table :test #'eql))
283
284(defun cache-invalidated-instance (instance)
285 (push instance
286 (gethash (class-of instance) *invalidated-instance-cache*)))
287
288(defun find-invalidated-instance (class)
289 (when (gethash class *invalidated-instance-cache*)
290 (pop (gethash class *invalidated-instance-cache*))))
291
292(defun list-invalidated-instances ()
293 (let ((instances ()))
294 (maphash #'(lambda (location ref)
295 (declare (ignore location))
296 (push ref instances))
297 *invalidated-instance-cache*)
298 instances))
299
b44caf77 300
301
302;;;; Proxy for alien instances
303
253c1339 304;; TODO: add a ref-counted-proxy subclass
6baf860c 305(defclass proxy ()
c23cc486 306 ((location :special t :type pointer))
82defe4d 307 (:metaclass virtual-slots-class))
b44caf77 308
6baf860c 309(defgeneric instance-finalizer (object))
310(defgeneric reference-foreign (class location))
311(defgeneric unreference-foreign (class location))
253c1339 312(defgeneric invalidate-instance (object))
adcadd53 313(defgeneric allocate-foreign (object &key &allow-other-keys))
6baf860c 314
cf45719a 315(defun foreign-location (instance)
316 (slot-value instance 'location))
317
318(defun (setf foreign-location) (location instance)
319 (setf (slot-value instance 'location) location))
320
321(defun proxy-valid-p (instance)
322 (slot-boundp instance 'location))
323
c55abd76 324(defmethod reference-foreign ((name symbol) location)
325 (reference-foreign (find-class name) location))
326
327(defmethod unreference-foreign ((name symbol) location)
328 (unreference-foreign (find-class name) location))
329
6baf860c 330(defmethod unreference-foreign :around ((class class) location)
331 (unless (null-pointer-p location)
7ce0497d 332 (call-next-method)))
b44caf77 333
a5c3a597 334(defmethod print-object ((instance proxy) stream)
335 (print-unreadable-object (instance stream :type t :identity nil)
7ce0497d 336 (if (slot-boundp instance 'location)
337 (format stream "at 0x~X" (sap-int (foreign-location instance)))
338 (write-string "at \"unbound\"" stream))))
b44caf77 339
adcadd53 340(defmethod initialize-instance :around ((instance proxy) &rest initargs &key &allow-other-keys)
341 (setf
342 (foreign-location instance)
343 (apply #'allocate-foreign instance initargs))
1d06a422 344 (prog1
345 (call-next-method)
346 (cache-instance instance)
347 (finalize instance (instance-finalizer instance))))
b44caf77 348
349(defmethod instance-finalizer ((instance proxy))
7ce0497d 350 (let ((location (foreign-location instance))
6baf860c 351 (class (class-of instance)))
352;; (unless (find-method #'unreference-foreign nil (list (class-of class) t) nil)
353;; (error "No matching method for UNREFERENCE-INSTANCE when called with class ~A" class))
354 #'(lambda ()
29933e83 355 (remove-cached-instance location)
6baf860c 356 (unreference-foreign class location))))
ba25fa44 357
2a9afe6f 358;; Any reference to the foreign object the instance may have held
359;; should be released before this method is invoked
253c1339 360(defmethod invalidate-instance ((instance proxy))
361 (remove-cached-instance (foreign-location instance))
2a9afe6f 362 (slot-makunbound instance 'location)
363 (cancel-finalization instance)
364 (cache-invalidated-instance instance))
253c1339 365
b44caf77 366
367;;;; Metaclass used for subclasses of proxy
368
3d36c5d6 369(defgeneric most-specific-proxy-superclass (class))
370(defgeneric direct-proxy-superclass (class))
371
372
b44caf77 373(eval-when (:compile-toplevel :load-toplevel :execute)
6baf860c 374 (defclass proxy-class (virtual-slots-class)
7ce0497d 375 ((size :reader foreign-size)))
b44caf77 376
377 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
c23cc486 378 ((offset :reader slot-definition-offset :initarg :offset))
379 (:default-initargs :allocation :alien))
b44caf77 380
381 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
935a783c 382 ((offset :reader slot-definition-offset :initarg :offset)))
ba25fa44 383
b44caf77 384 (defmethod most-specific-proxy-superclass ((class proxy-class))
385 (find-if
386 #'(lambda (class)
387 (subtypep (class-name class) 'proxy))
935a783c 388 (cdr (compute-class-precedence-list class))))
3d36c5d6 389
ba25fa44 390 (defmethod direct-proxy-superclass ((class proxy-class))
391 (find-if
392 #'(lambda (class)
393 (subtypep (class-name class) 'proxy))
935a783c 394 (class-direct-superclasses class)))
395
64bce834 396 (defmethod shared-initialize ((class proxy-class) names &key size)
b44caf77 397 (call-next-method)
ba25fa44 398 (cond
935a783c 399 (size (setf (slot-value class 'size) (first size)))
6baf860c 400 ((slot-boundp class 'size) (slot-makunbound class 'size))))
7ce0497d 401
935a783c 402 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 403 (case (getf initargs :allocation)
82defe4d 404 (:alien (find-class 'direct-alien-slot-definition))
b44caf77 405 (t (call-next-method))))
935a783c 406
407 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
b44caf77 408 (case (getf initargs :allocation)
409 (:alien (find-class 'effective-alien-slot-definition))
b44caf77 410 (t (call-next-method))))
411
935a783c 412
413 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
c23cc486 414 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
935a783c 415 (nconc
416 (list :offset (most-specific-slot-value direct-slotds 'offset))
417 (call-next-method))
418 (call-next-method)))
419
420
421 (defmethod initialize-internal-slot-functions ((slotd effective-alien-slot-definition))
422 (with-slots (offset) slotd
6baf860c 423 (let ((type (slot-definition-type slotd)))
64bce834 424 (unless (slot-boundp slotd 'getter)
6baf860c 425 (let ((reader (reader-function type)))
426 (setf
64bce834 427 (slot-value slotd 'getter)
6baf860c 428 #'(lambda (object)
7ce0497d 429 (funcall reader (foreign-location object) offset)))))
935a783c 430
64bce834 431 (unless (slot-boundp slotd 'setter)
6baf860c 432 (let ((writer (writer-function type))
433 (destroy (destroy-function type)))
434 (setf
64bce834 435 (slot-value slotd 'setter)
6baf860c 436 #'(lambda (value object)
7ce0497d 437 (let ((location (foreign-location object)))
6baf860c 438 (funcall destroy location offset) ; destroy old value
64bce834 439 (funcall writer value location offset))))))))
440
935a783c 441 (call-next-method))
442
935a783c 443 ;; TODO: call some C code to detect this a compile time
444 (defconstant +struct-alignmen+ 4)
b44caf77 445
7ce0497d 446 (defun align-offset (size)
447 (if (zerop (mod size +struct-alignmen+))
448 size
449 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
450
b44caf77 451 (defmethod compute-slots ((class proxy-class))
7ce0497d 452 (let ((alien-slots
453 (remove-if-not
454 #'(lambda (slotd)
455 (eq (slot-definition-allocation slotd) :alien))
456 (class-direct-slots class))))
457 (when alien-slots
458 (loop
459 as offset = (align-offset (foreign-size
460 (most-specific-proxy-superclass class)))
461 then (align-offset
462 (+
463 (slot-definition-offset slotd)
464 (size-of (slot-definition-type slotd))))
465 for slotd in alien-slots
466 unless (slot-boundp slotd 'offset)
467 do (setf (slot-value slotd 'offset) offset))))
b44caf77 468 (call-next-method))
8ae7ddc2 469
935a783c 470 (defmethod validate-superclass ((class proxy-class) (super standard-class))
471 (subtypep (class-name super) 'proxy))
472
7ce0497d 473 (defmethod foreign-size ((class-name symbol))
474 (foreign-size (find-class class-name))))
556b4a05 475
7ce0497d 476(defmethod foreign-size ((object proxy))
477 (foreign-size (class-of object)))
935a783c 478
7ce0497d 479
6baf860c 480(defmethod alien-type ((class proxy-class) &rest args)
481 (declare (ignore class args))
482 (alien-type 'pointer))
483
484(defmethod size-of ((class proxy-class) &rest args)
485 (declare (ignore class args))
486 (size-of 'pointer))
487
488(defmethod from-alien-form (location (class proxy-class) &rest args)
489 (declare (ignore args))
490 `(ensure-proxy-instance ',(class-name class) ,location))
491
492(defmethod from-alien-function ((class proxy-class) &rest args)
493 (declare (ignore args))
494 #'(lambda (location)
495 (ensure-proxy-instance class location)))
b44caf77 496
6baf860c 497(defmethod to-alien-form (instance (class proxy-class) &rest args)
498 (declare (ignore class args))
7ce0497d 499 `(foreign-location ,instance))
b44caf77 500
6baf860c 501(defmethod to-alien-function ((class proxy-class) &rest args)
502 (declare (ignore class args))
7ce0497d 503 #'foreign-location)
6baf860c 504
508d13a7 505(defmethod copy-from-alien-form (location (class proxy-class) &rest args)
506 (declare (ignore args))
507 (let ((class-name (class-name class)))
508 `(ensure-proxy-instance ',class-name
509 (reference-foreign ',class-name ,location))))
510
511(defmethod copy-from-alien-function ((class proxy-class) &rest args)
512 (declare (ignore args))
513 #'(lambda (location)
514 (ensure-proxy-instance class (reference-foreign class location))))
515
516(defmethod copy-to-alien-form (instance (class proxy-class) &rest args)
517 (declare (ignore args))
7ce0497d 518 `(reference-foreign ',(class-name class) (foreign-location ,instance)))
508d13a7 519
520(defmethod copy-to-alien-function ((class proxy-class) &rest args)
3d36c5d6 521 (declare (ignore args))
508d13a7 522 #'(lambda (instance)
7ce0497d 523 (reference-foreign class (foreign-location instance))))
508d13a7 524
6baf860c 525(defmethod writer-function ((class proxy-class) &rest args)
526 (declare (ignore args))
527 #'(lambda (instance location &optional (offset 0))
528 (assert (null-pointer-p (sap-ref-sap location offset)))
529 (setf
530 (sap-ref-sap location offset)
7ce0497d 531 (reference-foreign class (foreign-location instance)))))
b44caf77 532
6baf860c 533(defmethod reader-function ((class proxy-class) &rest args)
534 (declare (ignore args))
0739b019 535 #'(lambda (location &optional (offset 0) weak-p)
536 (declare (ignore weak-p))
508d13a7 537 (let ((instance (sap-ref-sap location offset)))
538 (unless (null-pointer-p instance)
539 (ensure-proxy-instance class (reference-foreign class instance))))))
b44caf77 540
6baf860c 541(defmethod destroy-function ((class proxy-class) &rest args)
542 (declare (ignore args))
543 #'(lambda (location &optional (offset 0))
544 (unreference-foreign class (sap-ref-sap location offset))))
545
b6bf802c 546(defmethod unbound-value ((class proxy-class) &rest args)
556b4a05 547 (declare (ignore args))
b6bf802c 548 (values t nil))
6baf860c 549
1d06a422 550(defun ensure-proxy-instance (class location &rest initargs)
551 "Returns a proxy object representing the foreign object at the give
552location. If an existing object is not found in the cache
553MAKE-PROXY-INSTANCE is called to create one."
6baf860c 554 (unless (null-pointer-p location)
555 (or
e4a48e09 556 #-debug-ref-counting(find-cached-instance location)
557 #+debug-ref-counting
253c1339 558 (let ((instance (find-cached-instance location)))
559 (when instance
560 (format t "Object found in cache: ~A~%" instance)
561 instance))
1d06a422 562 (let ((instance (apply #'make-proxy-instance class location initargs)))
563 (cache-instance instance)
564 instance))))
565
566(defgeneric make-proxy-instance (class location &key weak)
567 (:documentation "Creates a new proxy object representing the foreign
568object at the give location. If WEAK is non NIL the foreign memory
569will not be released when the proxy is garbage collected."))
570
253c1339 571(defmethod make-proxy-instance ((class symbol) location &rest initargs)
572 (apply #'make-proxy-instance (find-class class) location initargs))
1d06a422 573
574(defmethod make-proxy-instance ((class proxy-class) location &key weak)
2a9afe6f 575 (let ((instance
576 (or
577 (find-invalidated-instance class)
578 (allocate-instance class))))
cf45719a 579 (setf (foreign-location instance) location)
1d06a422 580 (unless weak
581 (finalize instance (instance-finalizer instance)))
582 instance))
b44caf77 583
ba25fa44 584
585;;;; Superclasses for wrapping of C structures
b44caf77 586
6baf860c 587(defclass struct (proxy)
588 ()
7ce0497d 589 (:metaclass proxy-class)
590 (:size 0))
b44caf77 591
adcadd53 592(defmethod allocate-foreign ((struct struct) &rest initargs)
b44caf77 593 (declare (ignore initargs))
adcadd53 594 (let ((size (foreign-size (class-of struct))))
595 (if (zerop size)
596 (error "~A has zero size" (class-of struct))
597 (allocate-memory size))))
b44caf77 598
599
6baf860c 600;;;; Metaclasses used for subclasses of struct
601
602(defclass struct-class (proxy-class)
603 ())
b44caf77 604
82defe4d 605(defmethod direct-slot-definition-class ((class struct-class) &rest initargs)
606 (if (not (getf initargs :allocation))
607 (find-class 'direct-alien-slot-definition)
608 (call-next-method)))
609
6baf860c 610(defmethod reference-foreign ((class struct-class) location)
7ce0497d 611 (copy-memory location (foreign-size class)))
6baf860c 612
613(defmethod unreference-foreign ((class struct-class) location)
ba25fa44 614 (deallocate-memory location))
b44caf77 615
3d2378de 616(defmethod compute-slots :around ((class struct-class))
617 (let ((slots (call-next-method)))
618 (when (and
c23cc486 619 #-sbcl>=0.9.8(class-finalized-p class)
3d2378de 620 (not (slot-boundp class 'size)))
621 (let ((size (loop
622 for slotd in slots
623 when (eq (slot-definition-allocation slotd) :alien)
624 maximize (+
625 (slot-definition-offset slotd)
626 (size-of (slot-definition-type slotd))))))
627 (setf (slot-value class 'size) (+ size (mod size +struct-alignmen+)))))
628 slots))
7ce0497d 629
0739b019 630(defmethod reader-function ((class struct-class) &rest args)
253c1339 631 (declare (ignore args))
0739b019 632 #'(lambda (location &optional (offset 0) weak-p)
253c1339 633 (let ((instance (sap-ref-sap location offset)))
634 (unless (null-pointer-p instance)
0739b019 635 (if weak-p
636 (ensure-proxy-instance class instance :weak t)
637 (ensure-proxy-instance class (reference-foreign class instance)))))))
253c1339 638
b44caf77 639
6baf860c 640(defclass static-struct-class (struct-class)
641 ())
b44caf77 642
6baf860c 643(defmethod reference-foreign ((class static-struct-class) location)
644 (declare (ignore class))
ba25fa44 645 location)
b44caf77 646
6baf860c 647(defmethod unreference-foreign ((class static-struct-class) location)
648 (declare (ignore class location))
ba25fa44 649 nil)
b4edcbf0 650
0739b019 651(defmethod reader-function ((class struct-class) &rest args)
652 (declare (ignore args))
653 #'(lambda (location &optional (offset 0) weak-p)
654 (declare (ignore weak-p))
655 (let ((instance (sap-ref-sap location offset)))
656 (unless (null-pointer-p instance)
657 (ensure-proxy-instance class instance :weak t)))))
658
b4edcbf0 659
660;;; Pseudo type for structs which are inlined in other objects
661
662(defmethod size-of ((type (eql 'inlined)) &rest args)
663 (declare (ignore type))
7ce0497d 664 (foreign-size (first args)))
b4edcbf0 665
666(defmethod reader-function ((type (eql 'inlined)) &rest args)
667 (declare (ignore type))
668 (destructuring-bind (class) args
0739b019 669 #'(lambda (location &optional (offset 0) weak-p)
670 (declare (ignore weak-p))
b4edcbf0 671 (ensure-proxy-instance class
672 (reference-foreign class (sap+ location offset))))))
673
253c1339 674(defmethod writer-function ((type (eql 'inlined)) &rest args)
675 (declare (ignore type))
676 (destructuring-bind (class) args
677 #'(lambda (instance location &optional (offset 0))
678 (copy-memory (foreign-location instance) (foreign-size class) (sap+ location offset)))))
679
b4edcbf0 680(defmethod destroy-function ((type (eql 'inlined)) &rest args)
681 (declare (ignore args))
682 #'(lambda (location &optional (offset 0))
683 (declare (ignore location offset))))
684
685(export 'inlined)