chiark / gitweb /
Modified WITH-ALLOCATED-MEMORY to use stack allocation when possible
[clg] / glib / proxy.lisp
CommitLineData
112ac1d3 1;; Common Lisp bindings for GTK+ v2.x
2;; Copyright 2000-2005 Espen S. Johnsen <espen@users.sf.net>
94f15c3c 3;;
112ac1d3 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:
94f15c3c 11;;
112ac1d3 12;; The above copyright notice and this permission notice shall be
13;; included in all copies or substantial portions of the Software.
94f15c3c 14;;
112ac1d3 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.
94f15c3c 22
b19bbc94 23;; $Id: proxy.lisp,v 1.33 2006-02-15 09:45:41 espen Exp $
94f15c3c 24
25(in-package "GLIB")
26
94f15c3c 27;;;; Superclass for all metaclasses implementing some sort of virtual slots
28
29(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 30 (defclass virtual-slots-class (standard-class)
4d83a8a6 31 ())
94f15c3c 32
33 (defclass direct-virtual-slot-definition (standard-direct-slot-definition)
12d0437e 34 ((setter :reader slot-definition-setter :initarg :setter)
4d83a8a6 35 (getter :reader slot-definition-getter :initarg :getter)
eeda1c2d 36 (unbound :reader slot-definition-unbound :initarg :unbound)
4d83a8a6 37 (boundp :reader slot-definition-boundp :initarg :boundp)))
94f15c3c 38
4d83a8a6 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)
eeda1c2d 42 (unbound :reader slot-definition-unbound :initarg :unbound)
e2ebafb1 43 (boundp :reader slot-definition-boundp :initarg :boundp)))
4d83a8a6 44
e2ebafb1 45 (defclass direct-special-slot-definition (standard-direct-slot-definition)
b19bbc94 46 ((special :initarg :special :accessor slot-definition-special)))
94f15c3c 47
e2ebafb1 48 (defclass effective-special-slot-definition (standard-effective-slot-definition)
b19bbc94 49 ((special :initarg :special :accessor slot-definition-special))))
e2ebafb1 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
94f15c3c 62
9adccb27 63(defmethod direct-slot-definition-class ((class virtual-slots-class) &rest initargs)
b19bbc94 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))))
94f15c3c 70
9adccb27 71(defmethod effective-slot-definition-class ((class virtual-slots-class) &rest initargs)
b19bbc94 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))))
94f15c3c 78
4d83a8a6 79
80(defmethod initialize-internal-slot-functions ((slotd effective-virtual-slot-definition))
eeda1c2d 81 (if (not (slot-boundp slotd 'getter))
82 (setf
4d83a8a6 83 (slot-value slotd 'reader-function)
eeda1c2d 84 #'(lambda (object)
85 (declare (ignore object))
308bfcab 86 (error "Slot is not readable: ~A" (slot-definition-name slotd)))
eeda1c2d 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
12b7df04 102 (setq reader
103 (mkbinding getter
104 (slot-definition-type slotd) 'pointer)))
09f6e237 105 (funcall reader (foreign-location object))))))))))
eeda1c2d 106
4d83a8a6 107 (setf
eeda1c2d 108 (slot-value slotd 'boundp-function)
109 (cond
eeda1c2d 110 ((slot-boundp slotd 'unbound)
111 (let ((unbound-value (slot-value slotd 'unbound)))
12b7df04 112 #'(lambda (object)
113 (not (eq (funcall getter-function object) unbound-value)))))
114 ((slot-boundp slotd 'boundp)
115 (let ((boundp (slot-value slotd 'boundp)))
eeda1c2d 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)))
09f6e237 126 (funcall reader (foreign-location object))))))))
12b7df04 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))))
eeda1c2d 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)))
12b7df04 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)))))
eeda1c2d 145 ((slot-boundp slotd 'boundp)
146 (let ((boundp-function (slot-value slotd 'boundp-function)))
12b7df04 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)))))))
eeda1c2d 160 (getter-function)))))
161
162 (setf
163 (slot-value slotd 'writer-function)
164 (if (not (slot-boundp slotd 'setter))
308bfcab 165 #'(lambda (value object)
166 (declare (ignore value object))
167 (error "Slot is not writable: ~A" (slot-definition-name slotd)))
eeda1c2d 168 (with-slots (setter) slotd
4d83a8a6 169 (etypecase setter
170 (function setter)
eeda1c2d 171 ((or symbol cons)
172 #'(lambda (value object)
173 (funcall (fdefinition setter) value object)))
7d1ddc9e 174 (string
eeda1c2d 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))))
09f6e237 183 (funcall writer (foreign-location object) value)))))))))
eeda1c2d 184
65466e9c 185 #-sbcl>=0.9.8(initialize-internal-slot-gfs (slot-definition-name slotd)))
4d83a8a6 186
187
188
eeda1c2d 189(defmethod compute-slot-accessor-info ((slotd effective-virtual-slot-definition) type gf)
4d83a8a6 190 nil)
191
9adccb27 192(defmethod compute-effective-slot-definition-initargs ((class virtual-slots-class) direct-slotds)
b19bbc94 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))))
4d83a8a6 212
94f15c3c 213
94f15c3c 214(defmethod slot-value-using-class
9adccb27 215 ((class virtual-slots-class) (object standard-object)
94f15c3c 216 (slotd effective-virtual-slot-definition))
4d83a8a6 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))))
94f15c3c 220
94f15c3c 221(defmethod slot-boundp-using-class
9adccb27 222 ((class virtual-slots-class) (object standard-object)
94f15c3c 223 (slotd effective-virtual-slot-definition))
4d83a8a6 224 (funcall (slot-value slotd 'boundp-function) object))
225
226(defmethod (setf slot-value-using-class)
9adccb27 227 (value (class virtual-slots-class) (object standard-object)
94f15c3c 228 (slotd effective-virtual-slot-definition))
4d83a8a6 229 (funcall (slot-value slotd 'writer-function) value object))
230
231
94f15c3c 232(defmethod validate-superclass
9adccb27 233 ((class virtual-slots-class) (super standard-class))
94f15c3c 234 t)
235
236
b19bbc94 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
94f15c3c 246;;;; Proxy cache
247
94f15c3c 248(defvar *instance-cache* (make-hash-table :test #'eql))
249
982a215a 250(defun cache-instance (instance &optional (weak-ref t))
94f15c3c 251 (setf
09f6e237 252 (gethash (sap-int (foreign-location instance)) *instance-cache*)
982a215a 253 (if weak-ref
254 (make-weak-pointer instance)
255 instance)))
94f15c3c 256
257(defun find-cached-instance (location)
73572c12 258 (let ((ref (gethash (sap-int location) *instance-cache*)))
94f15c3c 259 (when ref
982a215a 260 (if (weak-pointer-p ref)
261 (weak-pointer-value ref)
262 ref))))
94f15c3c 263
0f134a29 264(defun instance-cached-p (location)
73572c12 265 (gethash (sap-int location) *instance-cache*))
0f134a29 266
94f15c3c 267(defun remove-cached-instance (location)
73572c12 268 (remhash (sap-int location) *instance-cache*))
94f15c3c 269
9adccb27 270;; For debuging
982a215a 271(defun list-cached-instances ()
9adccb27 272 (let ((instances ()))
273 (maphash #'(lambda (location ref)
274 (declare (ignore location))
982a215a 275 (push ref instances))
9adccb27 276 *instance-cache*)
277 instances))
278
ca01de1b 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
94f15c3c 300
301
302;;;; Proxy for alien instances
303
4a64c16d 304;; TODO: add a ref-counted-proxy subclass
9adccb27 305(defclass proxy ()
b19bbc94 306 ((location :special t :type pointer))
e2ebafb1 307 (:metaclass virtual-slots-class))
94f15c3c 308
9adccb27 309(defgeneric instance-finalizer (object))
310(defgeneric reference-foreign (class location))
311(defgeneric unreference-foreign (class location))
4a64c16d 312(defgeneric invalidate-instance (object))
308bfcab 313(defgeneric allocate-foreign (object &key &allow-other-keys))
9adccb27 314
c0e19882 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
3b167652 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
9adccb27 330(defmethod unreference-foreign :around ((class class) location)
331 (unless (null-pointer-p location)
09f6e237 332 (call-next-method)))
94f15c3c 333
0f134a29 334(defmethod print-object ((instance proxy) stream)
335 (print-unreadable-object (instance stream :type t :identity nil)
09f6e237 336 (if (slot-boundp instance 'location)
337 (format stream "at 0x~X" (sap-int (foreign-location instance)))
338 (write-string "at \"unbound\"" stream))))
94f15c3c 339
308bfcab 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))
8958fa4a 344 (prog1
345 (call-next-method)
346 (cache-instance instance)
347 (finalize instance (instance-finalizer instance))))
94f15c3c 348
349(defmethod instance-finalizer ((instance proxy))
09f6e237 350 (let ((location (foreign-location instance))
9adccb27 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 ()
1dbf4216 355 (remove-cached-instance location)
9adccb27 356 (unreference-foreign class location))))
12d0437e 357
ca01de1b 358;; Any reference to the foreign object the instance may have held
359;; should be released before this method is invoked
4a64c16d 360(defmethod invalidate-instance ((instance proxy))
361 (remove-cached-instance (foreign-location instance))
ca01de1b 362 (slot-makunbound instance 'location)
363 (cancel-finalization instance)
364 (cache-invalidated-instance instance))
4a64c16d 365
94f15c3c 366
367;;;; Metaclass used for subclasses of proxy
368
73572c12 369(defgeneric most-specific-proxy-superclass (class))
370(defgeneric direct-proxy-superclass (class))
371
372
94f15c3c 373(eval-when (:compile-toplevel :load-toplevel :execute)
9adccb27 374 (defclass proxy-class (virtual-slots-class)
09f6e237 375 ((size :reader foreign-size)))
94f15c3c 376
377 (defclass direct-alien-slot-definition (direct-virtual-slot-definition)
b19bbc94 378 ((offset :reader slot-definition-offset :initarg :offset))
379 (:default-initargs :allocation :alien))
94f15c3c 380
381 (defclass effective-alien-slot-definition (effective-virtual-slot-definition)
4d83a8a6 382 ((offset :reader slot-definition-offset :initarg :offset)))
12d0437e 383
94f15c3c 384 (defmethod most-specific-proxy-superclass ((class proxy-class))
385 (find-if
386 #'(lambda (class)
387 (subtypep (class-name class) 'proxy))
4d83a8a6 388 (cdr (compute-class-precedence-list class))))
73572c12 389
12d0437e 390 (defmethod direct-proxy-superclass ((class proxy-class))
391 (find-if
392 #'(lambda (class)
393 (subtypep (class-name class) 'proxy))
4d83a8a6 394 (class-direct-superclasses class)))
395
eeda1c2d 396 (defmethod shared-initialize ((class proxy-class) names &key size)
94f15c3c 397 (call-next-method)
12d0437e 398 (cond
4d83a8a6 399 (size (setf (slot-value class 'size) (first size)))
9adccb27 400 ((slot-boundp class 'size) (slot-makunbound class 'size))))
09f6e237 401
4d83a8a6 402 (defmethod direct-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 403 (case (getf initargs :allocation)
e2ebafb1 404 (:alien (find-class 'direct-alien-slot-definition))
94f15c3c 405 (t (call-next-method))))
4d83a8a6 406
407 (defmethod effective-slot-definition-class ((class proxy-class) &rest initargs)
94f15c3c 408 (case (getf initargs :allocation)
409 (:alien (find-class 'effective-alien-slot-definition))
94f15c3c 410 (t (call-next-method))))
411
4d83a8a6 412
413 (defmethod compute-effective-slot-definition-initargs ((class proxy-class) direct-slotds)
b19bbc94 414 (if (eq (slot-definition-allocation (first direct-slotds)) :alien)
4d83a8a6 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
9adccb27 423 (let ((type (slot-definition-type slotd)))
eeda1c2d 424 (unless (slot-boundp slotd 'getter)
9adccb27 425 (let ((reader (reader-function type)))
426 (setf
eeda1c2d 427 (slot-value slotd 'getter)
9adccb27 428 #'(lambda (object)
09f6e237 429 (funcall reader (foreign-location object) offset)))))
4d83a8a6 430
eeda1c2d 431 (unless (slot-boundp slotd 'setter)
9adccb27 432 (let ((writer (writer-function type))
433 (destroy (destroy-function type)))
434 (setf
eeda1c2d 435 (slot-value slotd 'setter)
9adccb27 436 #'(lambda (value object)
09f6e237 437 (let ((location (foreign-location object)))
9adccb27 438 (funcall destroy location offset) ; destroy old value
eeda1c2d 439 (funcall writer value location offset))))))))
440
4d83a8a6 441 (call-next-method))
442
4d83a8a6 443 ;; TODO: call some C code to detect this a compile time
444 (defconstant +struct-alignmen+ 4)
94f15c3c 445
09f6e237 446 (defun align-offset (size)
447 (if (zerop (mod size +struct-alignmen+))
448 size
449 (+ size (- +struct-alignmen+ (mod size +struct-alignmen+)))))
450
94f15c3c 451 (defmethod compute-slots ((class proxy-class))
09f6e237 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))))
94f15c3c 468 (call-next-method))
3e15002d 469
4d83a8a6 470 (defmethod validate-superclass ((class proxy-class) (super standard-class))
471 (subtypep (class-name super) 'proxy))
472
09f6e237 473 (defmethod foreign-size ((class-name symbol))
474 (foreign-size (find-class class-name))))
47a11c16 475
09f6e237 476(defmethod foreign-size ((object proxy))
477 (foreign-size (class-of object)))
4d83a8a6 478
09f6e237 479
9adccb27 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)))
94f15c3c 496
9adccb27 497(defmethod to-alien-form (instance (class proxy-class) &rest args)
498 (declare (ignore class args))
09f6e237 499 `(foreign-location ,instance))
94f15c3c 500
9adccb27 501(defmethod to-alien-function ((class proxy-class) &rest args)
502 (declare (ignore class args))
09f6e237 503 #'foreign-location)
9adccb27 504
9ca5565a 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))
09f6e237 518 `(reference-foreign ',(class-name class) (foreign-location ,instance)))
9ca5565a 519
520(defmethod copy-to-alien-function ((class proxy-class) &rest args)
73572c12 521 (declare (ignore args))
9ca5565a 522 #'(lambda (instance)
09f6e237 523 (reference-foreign class (foreign-location instance))))
9ca5565a 524
9adccb27 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)
09f6e237 531 (reference-foreign class (foreign-location instance)))))
94f15c3c 532
9adccb27 533(defmethod reader-function ((class proxy-class) &rest args)
534 (declare (ignore args))
3005806e 535 #'(lambda (location &optional (offset 0) weak-p)
536 (declare (ignore weak-p))
9ca5565a 537 (let ((instance (sap-ref-sap location offset)))
538 (unless (null-pointer-p instance)
539 (ensure-proxy-instance class (reference-foreign class instance))))))
94f15c3c 540
9adccb27 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
12b7df04 546(defmethod unbound-value ((class proxy-class) &rest args)
47a11c16 547 (declare (ignore args))
12b7df04 548 (values t nil))
9adccb27 549
8958fa4a 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."
9adccb27 554 (unless (null-pointer-p location)
555 (or
aaced14e 556 #-debug-ref-counting(find-cached-instance location)
557 #+debug-ref-counting
4a64c16d 558 (let ((instance (find-cached-instance location)))
559 (when instance
560 (format t "Object found in cache: ~A~%" instance)
561 instance))
8958fa4a 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
4a64c16d 571(defmethod make-proxy-instance ((class symbol) location &rest initargs)
572 (apply #'make-proxy-instance (find-class class) location initargs))
8958fa4a 573
574(defmethod make-proxy-instance ((class proxy-class) location &key weak)
ca01de1b 575 (let ((instance
576 (or
577 (find-invalidated-instance class)
578 (allocate-instance class))))
c0e19882 579 (setf (foreign-location instance) location)
8958fa4a 580 (unless weak
581 (finalize instance (instance-finalizer instance)))
582 instance))
94f15c3c 583
12d0437e 584
585;;;; Superclasses for wrapping of C structures
94f15c3c 586
9adccb27 587(defclass struct (proxy)
588 ()
09f6e237 589 (:metaclass proxy-class)
590 (:size 0))
94f15c3c 591
308bfcab 592(defmethod allocate-foreign ((struct struct) &rest initargs)
94f15c3c 593 (declare (ignore initargs))
308bfcab 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))))
94f15c3c 598
599
9adccb27 600;;;; Metaclasses used for subclasses of struct
601
602(defclass struct-class (proxy-class)
603 ())
94f15c3c 604
e2ebafb1 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
9adccb27 610(defmethod reference-foreign ((class struct-class) location)
09f6e237 611 (copy-memory location (foreign-size class)))
9adccb27 612
613(defmethod unreference-foreign ((class struct-class) location)
12d0437e 614 (deallocate-memory location))
94f15c3c 615
65466e9c 616(defmethod compute-slots :around ((class struct-class))
617 (let ((slots (call-next-method)))
618 (when (and
b19bbc94 619 #-sbcl>=0.9.8(class-finalized-p class)
65466e9c 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))
09f6e237 629
3005806e 630(defmethod reader-function ((class struct-class) &rest args)
4a64c16d 631 (declare (ignore args))
3005806e 632 #'(lambda (location &optional (offset 0) weak-p)
4a64c16d 633 (let ((instance (sap-ref-sap location offset)))
634 (unless (null-pointer-p instance)
3005806e 635 (if weak-p
636 (ensure-proxy-instance class instance :weak t)
637 (ensure-proxy-instance class (reference-foreign class instance)))))))
4a64c16d 638
94f15c3c 639
9adccb27 640(defclass static-struct-class (struct-class)
641 ())
94f15c3c 642
9adccb27 643(defmethod reference-foreign ((class static-struct-class) location)
644 (declare (ignore class))
12d0437e 645 location)
94f15c3c 646
9adccb27 647(defmethod unreference-foreign ((class static-struct-class) location)
648 (declare (ignore class location))
12d0437e 649 nil)
bde0b906 650
3005806e 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
bde0b906 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))
09f6e237 664 (foreign-size (first args)))
bde0b906 665
666(defmethod reader-function ((type (eql 'inlined)) &rest args)
667 (declare (ignore type))
668 (destructuring-bind (class) args
3005806e 669 #'(lambda (location &optional (offset 0) weak-p)
670 (declare (ignore weak-p))
bde0b906 671 (ensure-proxy-instance class
672 (reference-foreign class (sap+ location offset))))))
673
4a64c16d 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
bde0b906 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)