On 12-May-06, at 4:39 PM, Bradley Lucier wrote:
Marc:
What do I put in my scm code to interface with this routine:
;; void rdft(long, long, double *, long *, double *);
And what type of scheme vectors can I pass to this?
You could use (untested):
(c-define-type double* (pointer double)) (c-define-type long* (pointer long))
(define rdft (c-lambda (long long double* long* double*) void "rdft"))
However, there is no automatic conversion from Scheme objects to double* and long*, so the above would have to be used with arrays allocated from C. For example you could:
(c-declare "#include <stdlib.h>")
(define make-double-vector (c-lambda (int) double* "___result = malloc(___arg1 * sizeof(double));"))
(define make-long-vector (c-lambda (int) long* "___result = malloc(___arg1 * sizeof(long));"))
(define v1 (make-double-vector 100)) (define v2 (make-long-vector 100)) (define v3 (make-double-vector 100))
(rdft 111 222 v1 v2 v3)
Of course adding accessors and mutators for the C vectors might be useful.
You might ask: Why isn't there an automatic conversion from Scheme vectors to C vectors? It is conceivable to add this to Gambit but for safety reasons it would have to copy the Scheme vector into a newly allocated C vector to be passed to C. This is required to avoid garbage collection problems (i.e. if the garbage collector kicks in during the call to C, then in general, the GC might move any Scheme vector so it is not safe to simply point to the body of the Scheme vector). Note: this is not true if you use ___STILL objects, but it is not easy way to allocate a ___STILL vector from Scheme (one way is with (##still-copy (make-f64vector 100)) but this is inefficient because it involves copying the vector).
If you know the GC will never be called in the C function or you don't care about safety, you could use the following approach. There is a macro ___BODY(obj) defined in include/gambit.h which returns a pointer to the body of any memory allocated object. In the case of vectors, it is a pointer to the first element. So you could write:
(define rdft (c-lambda (long long scheme-object scheme-object scheme-object) void "rdft(___arg1, ___arg2, (double*)___BODY(___arg3), (long*)___BODY(___arg4), (double*)___BODY(___arg5));"))
(rdft 111 222 (f64vector 1.0 2.0 3.0) (u32vector 111 222 333) ; use u64vector if "long" is a 64 bit int on your platform (f64vector 1.0 2.0 3.0))
There are three things you must remember about this approach: it is unsafe, it is unsafe, and it is unsafe. YMMV.
Marc