Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Afficher les réponses par date
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
This is the definition in C:
typedef enum _cairo_format { CAIRO_FORMAT_INVALID = -1, CAIRO_FORMAT_ARGB32 = 0, CAIRO_FORMAT_RGB24 = 1, CAIRO_FORMAT_A8 = 2, CAIRO_FORMAT_A1 = 3, CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t;
AFAIK, bindings in Gambit usually deal with this as an integer, but with C++ enabled, conversion is needed.
2012/2/5 Mikael mikael.rcv@gmail.com
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Are you sure that, now that each constant has a fixed integer value, the compiler is allowed to represent this internally as anything else than an int? Check it out. If not, you know it's an int, so you could just typecast
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
This is the definition in C:
typedef enum _cairo_format { CAIRO_FORMAT_INVALID = -1, CAIRO_FORMAT_ARGB32 = 0, CAIRO_FORMAT_RGB24 = 1, CAIRO_FORMAT_A8 = 2, CAIRO_FORMAT_A1 = 3, CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t;
AFAIK, bindings in Gambit usually deal with this as an integer, but with C++ enabled, conversion is needed.
2012/2/5 Mikael mikael.rcv@gmail.com
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Mikael,
I think I don't follow you. The problem is that C++ doesn't allow casting from int to enum, while I think C does. There is a link about this in stackoverflow: http://stackoverflow.com/questions/4165439/generic-way-to-cast-int-to-enum-i...
The cairo type is defined as an enum, so if compiling with the C compiler it works seamlessly with scheme's integers, however, if using C++ compiler, it doesn't cast it implicitly. Thus the need for this -more complex- machiner.
That's my understanding, but I might be wrong.
On Sun, Feb 5, 2012 at 8:10 PM, Mikael mikael.rcv@gmail.com wrote:
Are you sure that, now that each constant has a fixed integer value, the compiler is allowed to represent this internally as anything else than an int? Check it out. If not, you know it's an int, so you could just typecast
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
This is the definition in C:
typedef enum _cairo_format { CAIRO_FORMAT_INVALID = -1, CAIRO_FORMAT_ARGB32 = 0, CAIRO_FORMAT_RGB24 = 1, CAIRO_FORMAT_A8 = 2, CAIRO_FORMAT_A1 = 3, CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t;
AFAIK, bindings in Gambit usually deal with this as an integer, but with C++ enabled, conversion is needed.
2012/2/5 Mikael mikael.rcv@gmail.com
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Ouch. Well then what we addressed in previous email makes the most sense, I suppose - defining constant variables with integer contents (define const1 0) (define const2 1) etc. and then manually converting in the C code: (define p (c-lambda (int) .. #<<c enumtype v; switch where based on ___arg1 you set v case 0: v = CONST1; break; case 1: v = CONST2; and so on.
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Mikael,
I think I don't follow you. The problem is that C++ doesn't allow casting from int to enum, while I think C does. There is a link about this in stackoverflow: http://stackoverflow.com/questions/4165439/generic-way-to-cast-int-to-enum-i...
The cairo type is defined as an enum, so if compiling with the C compiler it works seamlessly with scheme's integers, however, if using C++ compiler, it doesn't cast it implicitly. Thus the need for this -more complex- machiner.
That's my understanding, but I might be wrong.
On Sun, Feb 5, 2012 at 8:10 PM, Mikael mikael.rcv@gmail.com wrote:
Are you sure that, now that each constant has a fixed integer value, the compiler is allowed to represent this internally as anything else than an int? Check it out. If not, you know it's an int, so you could just typecast
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
This is the definition in C:
typedef enum _cairo_format { CAIRO_FORMAT_INVALID = -1, CAIRO_FORMAT_ARGB32 = 0, CAIRO_FORMAT_RGB24 = 1, CAIRO_FORMAT_A8 = 2, CAIRO_FORMAT_A1 = 3, CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t;
AFAIK, bindings in Gambit usually deal with this as an integer, but with C++ enabled, conversion is needed.
2012/2/5 Mikael mikael.rcv@gmail.com
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
Ouch. Well then what we addressed in previous email makes the most sense, I suppose - defining constant variables with integer contents (define const1 0) (define const2 1) etc. and then manually converting in the C code: (define p (c-lambda (int) .. #<<c enumtype v; switch where based on ___arg1 you set v case 0: v = CONST1; break; case 1: v = CONST2; and so on.
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Mikael,
I think I don't follow you. The problem is that C++ doesn't allow casting from int to enum, while I think C does. There is a link about this in stackoverflow: http://stackoverflow.com/questions/4165439/generic-way-to-cast-int-to-enum-i...
The cairo type is defined as an enum, so if compiling with the C compiler it works seamlessly with scheme's integers, however, if using C++ compiler, it doesn't cast it implicitly. Thus the need for this -more complex- machiner.
That's my understanding, but I might be wrong.
On Sun, Feb 5, 2012 at 8:10 PM, Mikael mikael.rcv@gmail.com wrote:
Are you sure that, now that each constant has a fixed integer value, the compiler is allowed to represent this internally as anything else than an int? Check it out. If not, you know it's an int, so you could just typecast
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
This is the definition in C:
typedef enum _cairo_format { CAIRO_FORMAT_INVALID = -1, CAIRO_FORMAT_ARGB32 = 0, CAIRO_FORMAT_RGB24 = 1, CAIRO_FORMAT_A8 = 2, CAIRO_FORMAT_A1 = 3, CAIRO_FORMAT_RGB16_565 = 4 } cairo_format_t;
AFAIK, bindings in Gambit usually deal with this as an integer, but with C++ enabled, conversion is needed.
2012/2/5 Mikael mikael.rcv@gmail.com
2012/2/5 Álvaro Castro-Castilla alvaro.castro.castilla@gmail.com
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
Ouch - your declaration makes Gambit identify, I think, cairo_format_t as a C structure, and tries to copy its contents fully. Hmm. If this is not how it really is, do (c-define-type cairo-format-t integer) or sth?
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
Best regards,
Álvaro
Gambit-list mailing list Gambit-list@iro.umontreal.ca https://webmail.iro.umontreal.ca/mailman/listinfo/gambit-list
On 2012-02-05, at 1:51 PM, Álvaro Castro-Castilla wrote:
Hi!
I open a new thread, because this is a deeper issue than the C++ enums conversion problem.
When I declare this:
(define CAIRO_FORMAT_RGB24 ((c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")))
or: (define CAIRO_FORMAT_RGB24 (c-lambda () cairo-format-t "___result = CAIRO_FORMAT_RGB24;")) and then call (CAIRO_FORMAT_RGB24)
my program segfaults. It seems that just executing that c-lambda, returning an enum, fails. The enum is defined as: (c-define-type cairo-format-t "cairo_format_t")
I don't understand why this segfaults: 1) I'm declaring the type 2) I'm returning the proper type. What's the problem?
I can reproduce the problem. It seems to be a bug. I'll look into it today.
Marc
On 2012-02-06, at 8:08 AM, Marc Feeley wrote:
I can reproduce the problem. It seems to be a bug. I'll look into it today.
I can confirm that it is a bug in the C-interface which occurs with opaque types (such as (c-define-type foo "foo")), and "struct" and "union" types when the body of the c-lambda is inline code (the case where the c-lambda body is a function name is handled correctly).
I'll work on a fix.
In the meantime, you can use one of the styles given in the attached example.
Marc
(c-declare #<<end-of-c-declare
#include <stdio.h>
typedef enum { A, B, C } foo;
void f(foo x) { printf("%d\n", x); }
end-of-c-declare )
;;;---------------------------------------------------------------------------
;#|
;; This interface to the "foo" enum type works on C and C++ compilers. ;; The use of ___ASSIGN_NEW_WITH_INIT is needed to avoid a bug in the ;; C-interface that occurs when the body of the c-lambda is not the ;; name of a function (i.e. when the body is inline code).
(c-define-type foo "foo")
(define A ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,A);")))
(define B ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,B);")))
(define C ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,C);")))
(define f (c-lambda (foo) void "f")) ;|#
;;;---------------------------------------------------------------------------
#|
;; This interface to the "foo" enum type causes a bug in the ;; C-interface on C and C++ compilers.
(c-define-type foo "foo")
(define A ((c-lambda () foo "___result = A;"))) (define B ((c-lambda () foo "___result = B;"))) (define C ((c-lambda () foo "___result = C;")))
(define f (c-lambda (foo) void "f")) |#
;;;---------------------------------------------------------------------------
#|
;; This interface works on C and C++ compilers, but is klunky.
(c-declare #<<end-of-c-declare
foo get_A() { return A; } foo get_B() { return B; } foo get_C() { return C; }
end-of-c-declare )
(c-define-type foo "foo")
(define A ((c-lambda () foo "get_A"))) (define B ((c-lambda () foo "get_B"))) (define C ((c-lambda () foo "get_C")))
(define f (c-lambda (foo) void "f")) |#
;;;---------------------------------------------------------------------------
#|
;; This is an alternate interface to the "foo" enum type. The ;; explicit cast in the definition of "f" is required when compiling ;; with a C++ compiler because the conversion from int to enum is not ;; implicit in C++.
(c-define-type foo int) ;; NOTE: using "int" type for "foo"
(define A ((c-lambda () foo "___result = A;"))) (define B ((c-lambda () foo "___result = B;"))) (define C ((c-lambda () foo "___result = C;")))
(define f (c-lambda (foo) void "f((foo)___arg1);")) ;; NOTE: explicit cast |#
;;;---------------------------------------------------------------------------
(f A) (f B) (f C)
Thank you Marc. Those are all better solutions than my wrapper function.
Best regards
Álvaro
2012/2/6 Marc Feeley feeley@iro.umontreal.ca
On 2012-02-06, at 8:08 AM, Marc Feeley wrote:
I can reproduce the problem. It seems to be a bug. I'll look into it
today.
I can confirm that it is a bug in the C-interface which occurs with opaque types (such as (c-define-type foo "foo")), and "struct" and "union" types when the body of the c-lambda is inline code (the case where the c-lambda body is a function name is handled correctly).
I'll work on a fix.
In the meantime, you can use one of the styles given in the attached example.
Marc
(c-declare #<<end-of-c-declare
#include <stdio.h>
typedef enum { A, B, C } foo;
void f(foo x) { printf("%d\n", x); }
end-of-c-declare )
;;;---------------------------------------------------------------------------
;#|
;; This interface to the "foo" enum type works on C and C++ compilers. ;; The use of ___ASSIGN_NEW_WITH_INIT is needed to avoid a bug in the ;; C-interface that occurs when the body of the c-lambda is not the ;; name of a function (i.e. when the body is inline code).
(c-define-type foo "foo")
(define A ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,A);")))
(define B ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,B);")))
(define C ((c-lambda () foo "___ASSIGN_NEW_WITH_INIT(___result_voidstar,foo,C);")))
(define f (c-lambda (foo) void "f")) ;|#
;;;---------------------------------------------------------------------------
#|
;; This interface to the "foo" enum type causes a bug in the ;; C-interface on C and C++ compilers.
(c-define-type foo "foo")
(define A ((c-lambda () foo "___result = A;"))) (define B ((c-lambda () foo "___result = B;"))) (define C ((c-lambda () foo "___result = C;")))
(define f (c-lambda (foo) void "f")) |#
;;;---------------------------------------------------------------------------
#|
;; This interface works on C and C++ compilers, but is klunky.
(c-declare #<<end-of-c-declare
foo get_A() { return A; } foo get_B() { return B; } foo get_C() { return C; }
end-of-c-declare )
(c-define-type foo "foo")
(define A ((c-lambda () foo "get_A"))) (define B ((c-lambda () foo "get_B"))) (define C ((c-lambda () foo "get_C")))
(define f (c-lambda (foo) void "f")) |#
;;;---------------------------------------------------------------------------
#|
;; This is an alternate interface to the "foo" enum type. The ;; explicit cast in the definition of "f" is required when compiling ;; with a C++ compiler because the conversion from int to enum is not ;; implicit in C++.
(c-define-type foo int) ;; NOTE: using "int" type for "foo"
(define A ((c-lambda () foo "___result = A;"))) (define B ((c-lambda () foo "___result = B;"))) (define C ((c-lambda () foo "___result = C;")))
(define f (c-lambda (foo) void "f((foo)___arg1);")) ;; NOTE: explicit cast |#
;;;---------------------------------------------------------------------------
(f A) (f B) (f C)
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
Does it really reduce code size to wrap the function instead of explicitly cast? I've always believed that casts are mostly a compiler artifact coming from static typing, didn't usually generate complex code for runtime...
Thanks for your comments,
Álvaro
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
On 2012-02-06, at 12:53 PM, Álvaro Castro-Castilla wrote:
Does it really reduce code size to wrap the function instead of explicitly cast? I've always believed that casts are mostly a compiler artifact coming from static typing, didn't usually generate complex code for runtime...
Relatively speaking, there is quite a bit of code generated for each c-lambda in the code. So if you write your code so that there is a single c-lambda (the "wrapper"), it will be more compact. The casts themselves don't add code. It is the calls to the type conversion functions and the exception handling code.
Marc
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....
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
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