Hi guys!
It's me again, still going on about struct-by-value in
chicken-bind. This time I think I may have
code worthy of entering the official repo. The patches add three new features:
- Struct-by-value in arguments
- Struct-by-value return types
- Nested structs (practically same as 2)
Functions on the Scheme-side interface all functions using pointers or locatives, regardless of their original signature.
You can have a look at my 10 commits that make up the patch on
github. I tried to be descriptive in my commit messages. Please let me know of your thoughts and concerns. If nothing pops up, I'll pass it on Felix (chicken-bind maintainer) for review.
Motivation
While most C libraries pass structs by reference, both physics engines I've come across, Chipmunk and Box2D, pass small structs like 2d-vectors around by value everywhere. This patch made my life easier.
Code samples
Let's walk through the new foreign-lambda snippets that it generates. I use the point struct in my examples, pretend it's some 2d/3d vector of floats. First, let's look at passing a struct by reference:
1. Struct argumentsaddress@hidden chicken-bind]$ echo "float length(struct point*)" | chicken-bind - -o -
(begin
(begin
(define length
(foreign-lambda float "length" (c-pointer (struct "point"))))))
Nothing's changed there, my patch will kick in when you pass structs by value. The patch checks if any arguments are non-pointer struct arguments, and if there are any, it wraps the call in a foreign-lambda* with all struct-by-val arguments to c-pointer variant which are dereferenced in C:
address@hidden chicken-bind]$ echo "float length(struct point)" | chicken-bind - -o -
(begin
(begin
(define length
(foreign-lambda*
float
(((c-pointer (struct "point")) a0))
"C_return(length(*a0));"))))
2. Struct return-types
Struct return-types are a little trickier and are split into two functions. One will call the original function, storing the result in a additional destination operand. The other will allocate memory to use as this destination and calls the first:
address@hidden chicken-bind]$ echo "struct point intersection(struct line*, struct line)" | chicken-bind - -o -
(begin
(begin
(begin
(define intersection/overwrite!
(foreign-lambda*
void
(((c-pointer (struct "point")) dest)
((c-pointer (struct "line")) a0)
((c-pointer (struct "line")) a1))
"*dest=(intersection(a0,*a1));"))
(define (intersection a0 a1)
(let ((dest (location
(make-blob (foreign-value "sizeof(struct point)" int)))))
(intersection/overwrite! dest a0 a1)
dest)))))
As shown above, you can mix and match struct value-passing and pointer-passing in the arguments.
3. Nested structs
Nested structs face the same problem as struct return-types, but unfortunately I haven't looked into uniting the codebase. However, it follows the same destination-method as above:
address@hidden chicken-bind]$ echo "struct circle { struct point origin; float radius ; }" | chicken-bind - -o -
(begin
(define circle-origin
(lambda (s)
(let ((blob (location
(make-blob (foreign-value "sizeof(struct point)" int))))
(copy-struct!
(foreign-lambda*
void
(((c-pointer (struct "point")) _dest)
((c-pointer (struct "circle")) s))
"*_dest = s->origin;")))
(copy-struct! blob s)
blob)))
(define circle-radius
(foreign-lambda*
float
(((c-pointer (struct "circle")) s))
"return(s->radius);"))
(define make-circle
(foreign-lambda*
(c-pointer (struct "circle"))
(((c-pointer (struct "point")) origin) (float radius))
"struct circle *tmp_ = (struct circle *)C_malloc(sizeof(struct circle));\ntmp_->origin = *origin;\n\ntmp_->radius = radius;\n\nC_return(tmp_);")))
Caveats
Struct-by-value return types and nested-struct getters return locatives. This is nice because it will be like any other scheme-object and doesn't need to be explicitly freed. Be careful though, locatives will be moved around by the GC and thus pointers to it are not permanent.
A also added a small
test-suite for these features.
Cheers fellow Chickeners,
- Kris
_______________________________________________
Chicken-users mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/chicken-users