Proposal WITH-CASTED-POINTER (Was: Coercing pointers)
Edi Weitz <[email protected]> 14 Aug 2003 00:29:02 +0200
| Newsgroups | gmane.lisp.uffi.general |
|---|---|
| Message-ID | <[email protected]> |
I wrote:
> > OK, I'll see what I need for GD and send patches later. I
> > currently think it'd be best to mix the two approaches we talked
> > about and document this accordingly.
Forget what I just said... :)
Here's a proposal (patch at the end of this email):
Macro WITH-CASTED-POINTER (pointer type &optional binding-name) &body body
Executes BODY with POINTER casted to be a pointer to type TYPE. If
BINDING-NAME is provided the casted pointer will be bound to this
name during the execution of BODY. If BINDING-NAME is not provided
POINTER must be a name bound to the pointer which should be
casted. This name will be bound to the casted pointer during the
execution of BODY.
This is a no-op in AllegroCL but will wrap BODY in a LET form if
BINDING-NAME is provided.
This macro is meant to be used in conjunction with DEREF-POINTER or
DEREF-ARRAY. In Allegro CL the "cast" will actually take place in
DEREF-POINTER or DEREF-ARRAY.
The docs for DEREF-POINTER and DEREF-ARRAY should get the following
note:
The TYPE argument is ignored for CL implementations other than
AllegroCL. If you want to cast a pointer to another type use
WITH-CASTED-POINTER together with DEREF-POINTER/DEREF-ARRAY.
Rationale:
1. I didn't use the name WITH-COERCED-POINTER because it's already
taken by LW.
2. It'd probably be nicer to have a function CAST-POINTER instead of a
macro but I think this is not an option because LW doesn't seem to
offer this - you have to use their WITH-COERCED-POINTER.
3. It would be more natural to have
WITH-CASTED-POINTER (binding-name pointer type) &body body
but having your last remarks in mind I thought this might be a
performance penalty for AllegroCL because of the unnecessary LET
form. (Or do you think the compiler will be able to optimize it
away?)
Tests:
I've tested with CMUCL 18e, AllegroCL 6.2 trial, LW 4.2.7 pro and SBCL
0.8.2 - all on Linux. I used the following C function
void *foo (int n) {
int *x;
double *y;
if (n > 0) {
x = (int *) malloc(sizeof(int));
*x = 23;
return x;
} else {
y = (double *) malloc(sizeof(double));
*y = 3.21;
return y;
}
}
and this Lisp code
(uffi:load-foreign-library "/tmp/test/foo.so"
:module "foo")
(uffi:def-function "foo"
((n :int))
:returning :pointer-void
:module "foo")
(defun test (n)
(cond ((plusp n)
(uffi:with-casted-pointer ((foo n) :int temp)
(assert (= (uffi:deref-pointer temp :int) 23)))
(let ((result (foo n)))
(uffi:with-casted-pointer (result :int)
(assert (= (uffi:deref-pointer result :int) 23)))
(uffi:with-casted-pointer (result :int temp)
(assert (= (uffi:deref-pointer temp :int) 23)))))
(t
(uffi:with-casted-pointer ((foo n) :double temp)
(assert (= (uffi:deref-pointer temp :double) 3.21d0)))
(let ((result (foo n)))
(uffi:with-casted-pointer (result :double)
(assert (= (uffi:deref-pointer result :double) 3.21d0)))
(uffi:with-casted-pointer (result :double temp)
(assert (= (uffi:deref-pointer temp :double) 3.21d0)))))))
The tests ran fine on all four implementations, interpreted as well as
compiled.
Let me know what you think,
Edi.
---------------------------------- SNIP -----------------------------
edi@bird:/usr/local/lisp/source/uffi/src > diff -ru /tmp/uffi-1.2.21/ /usr/local/lisp/source/uffi
diff -ru /tmp/uffi-1.2.21/src/objects.lisp /usr/local/lisp/source/uffi/src/objects.lisp
--- /tmp/uffi-1.2.21/src/objects.lisp Tue Jul 8 14:37:26 2003
+++ /usr/local/lisp/source/uffi/src/objects.lisp Thu Aug 14 00:00:17 2003
@@ -197,3 +197,33 @@
`(with-foreign-objects ((,var ,type))
,@body))
+#+lispworks
+(defmacro with-casted-pointer ((pointer type &optional binding-name) &body body)
+ `(fli:with-coerced-pointer (,(or binding-name pointer)
+ :type ',(convert-from-uffi-type (eval type) :type))
+ ,pointer
+ ,@body))
+
+#+(or cmu scl sbcl)
+(defmacro with-casted-pointer ((pointer type &optional binding-name) &body body)
+ `(let ((,(or binding-name pointer)
+ (#+(or cmu scl) alien:cast
+ #+sbcl sb-alien:cast
+ ,pointer (* ,(convert-from-uffi-type (eval type) :type)))))
+ ,@body))
+
+#+allegro
+(defmacro with-casted-pointer ((pointer type &optional binding-name) &body body)
+ (declare (ignore type))
+ (cond (binding-name
+ `(let ((,binding-name ,pointer))
+ ,@body))
+ (t
+ `(progn
+ ,@body))))
+
+#-(or lispworks cmu scl sbcl allegro)
+(defmacro with-casted-pointer ((pointer type &optional binding-name) &body body)
+ '(error "WITH-CASTED-POINTER not (yet) implemented for ~A"
+ (lisp-implementation-type)))
+
diff -ru /tmp/uffi-1.2.21/src/package.lisp /usr/local/lisp/source/uffi/src/package.lisp
--- /tmp/uffi-1.2.21/src/package.lisp Sat Jun 7 00:06:28 2003
+++ /usr/local/lisp/source/uffi/src/package.lisp Wed Aug 13 16:45:23 2003
@@ -49,6 +49,7 @@
#:make-null-pointer
#:+null-cstring-pointer+
#:char-array-to-pointer
+ #:with-casted-pointer
;; string functions
#:convert-from-cstring