Great! It works.
I've made this little variation to allow different scheme-type and c-type names:
(define-macro (import-enum-constants scheme-type c-type . names) (define (interval lo hi) (if (< lo hi) (cons lo (interval (+ lo 1) hi)) '())) (let ((c-type-str (symbol->string c-type)) (nb-names (length names)) (wrapper (gensym))) `(begin (define ,wrapper (c-lambda (int) ,scheme-type ,(string-append "static " c-type-str " _tmp_[] = {\n" (apply string-append (map (lambda (i name) (let ((name-str (symbol->string name))) (string-append (if (> i 0) "," "") name-str))) (interval 0 nb-names) names)) "};\n" "___ASSIGN_NEW_WITH_INIT(___result_voidstar," c-type-str ",_tmp_[___arg1]);\n"))) ,@(map (lambda (i name) `(define ,name (,wrapper ,i))) (interval 0 nb-names) names))))
On Mon, Feb 6, 2012 at 9:30 PM, Marc Feeley feeley@iro.umontreal.ca wrote:
On 2012-02-06, at 1:04 PM, REPLeffect wrote:
2012/2/6 Marc Feeley feeley@iro.umontreal.ca:
On 2012-02-06, at 9:59 AM, Álvaro Castro-Castilla wrote:
Thank you Marc. Those are all better solutions than my wrapper
function.
Best regards
Álvaro
Actually, using a wrapper function is a good idea to reduce code size.
Its intricacies can be hidden in a macro which generates the appropriate Scheme and C code. I've written something like this in the past and even posted an example to the Gambit mailing list (unfortunately my mail system's search function is broken right now so I can't find the message).
Marc
Marc,
Is this the message you're referring to?
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2011-November/005445....
Yes. Using that macro as an inspiration, I wrote the following import-enum-constants macro which imports a number of enum constants without using a wrapper function:
(c-declare #<<end-of-c-declare
#include <stdio.h>
typedef enum { A0, B0, C0, D0, E0, F0, G0, H0, I0, J0, A1, B1, C1, D1, E1, F1, G1, H1, I1, J1, A2, B2, C2, D2, E2, F2, G2, H2, I2, J2, A3, B3, C3, D3, E3, F3, G3, H3, I3, J3, A4, B4, C4, D4, E4, F4, G4, H4, I4, J4, A5, B5, C5, D5, E5, F5, G5, H5, I5, J5, A6, B6, C6, D6, E6, F6, G6, H6, I6, J6, A7, B7, C7, D7, E7, F7, G7, H7, I7, J7, A8, B8, C8, D8, E8, F8, G8, H8, I8, J8, A9, B9, C9, D9, E9, F9, G9, H9, I9, J9 } foo;
void f(foo x) { printf("%d\n", x); }
end-of-c-declare )
;;;---------------------------------------------------------------------------
(define-macro (import-enum-constants type . names) (let ((type-str (symbol->string type))) `(begin ,@(map (lambda (name) (let ((name-str (symbol->string name))) `(define ,name ((c-lambda () ,type ,(string-append
"___ASSIGN_NEW_WITH_INIT(___result_voidstar," type-str "," name-str ");")))))) names))))
;;;---------------------------------------------------------------------------
(c-define-type foo "foo")
(import-enum-constants foo A0 B0 C0 D0 E0 F0 G0 H0 I0 J0 A1 B1 C1 D1 E1 F1 G1 H1 I1 J1 A2 B2 C2 D2 E2 F2 G2 H2 I2 J2 A3 B3 C3 D3 E3 F3 G3 H3 I3 J3 A4 B4 C4 D4 E4 F4 G4 H4 I4 J4 A5 B5 C5 D5 E5 F5 G5 H5 I5 J5 A6 B6 C6 D6 E6 F6 G6 H6 I6 J6 A7 B7 C7 D7 E7 F7 G7 H7 I7 J7 A8 B8 C8 D8 E8 F8 G8 H8 I8 J8 A9 B9 C9 D9 E9 F9 G9 H9 I9 J9 )
(define f (c-lambda (foo) void "f"))
(f A0) (f F6) (f J9)
When a wrapper function is used, the macro can be implemented like this:
;;;---------------------------------------------------------------------------
(define-macro (import-enum-constants type . names)
(define (interval lo hi) (if (< lo hi) (cons lo (interval (+ lo 1) hi)) '()))
(let ((type-str (symbol->string type)) (nb-names (length names)) (wrapper (gensym))) `(begin (define ,wrapper (c-lambda (int) ,type ,(string-append "static " type-str " _tmp_[] = {\n" (apply string-append (map (lambda (i name) (let ((name-str (symbol->string name))) (string-append (if (> i 0) "," "") name-str))) (interval 0 nb-names) names)) "};\n" "___ASSIGN_NEW_WITH_INIT(___result_voidstar," type-str ",_tmp_[___arg1]);\n"))) ,@(map (lambda (i name) `(define ,name (,wrapper ,i))) (interval 0 nb-names) names))))
;;;---------------------------------------------------------------------------
The version with the wrapper function is much more compact. On Mac OS X with LLVM gcc the first version compiles to a 80kb file (roughly 700 bytes of machine code per enum constant that is imported), and the version with a wrapper function compiles to a 20kb file (roughly a factor of 5 times more compact).
Marc
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list