Hello,
Kenny complained about foreign-object-alloc not being documented a few hours ago which reminded me about the foreign-alloc vs. foreign-object-alloc issue James and I briefly discussed on IRC.
I would like to experiment with a typed pointer interface (something similar to CMUCL/SBCL's Alien objects) and was planning to call those pointers "foreign objects" in which case foreign-object-alloc would be confusing since all it does is allocate raw memory.
One idea James suggested was to move foreign-object-alloc's functionality to foreign-alloc and export the lower level %foreign-alloc (renamed to malloc or something similar). [Or just have the users use foreign-alloc with a :char type, why not?]
Well, but why not improve (and hopefully not bloat) foreign-alloc. Here's a proposed interface based mostly on Lispworks's ffi:allocate-foreign-object and CL's make-array:
foreign-alloc =============
Syntax ------
-- Function: foreign-alloc type &key initial-element initial-contents (count 1) => pointer
Arguments and Values --------------------
_type_ A foreign type.
_initial-element_ A Lisp object.
_initial-contents_ A sequence.
_count_ /Note: probably :nelems would be a better name?/ An integer bigger than or equal to 1. 1, by default.
_pointer_ A foreign pointer to the newly allocated memory.
Description -----------
The `foreign-alloc' function allocates enough memory to hold _count_ objects of type _type_ and returns a _pointer_. This memory must be explicitly freed using `foreign-free' once it is no longer needed.
If _initial-element_ is supplied, it is used to initialize the _count_ objects the newly allocated memory holds.
If an _initial-contents_ sequence is supplied, it must have a length less than or equal to _count_ and each of its elements will be used to initialize the contents of the newly allocated memory. /Note: Should the remainder be zero filled?/
/Note: also is initial-contents is supplied and count isn't then count will be (length initial-contents) [plus 1, probably]. See note in the examples./
_initial-element_ and _initial-contents_ are mutually exclusive.
Examples --------
CFFI> (foreign-alloc :char) #<A Mac Pointer #x1022E0> ; A pointer to 1 byte of memory.
CFFI> (foreign-alloc :char :count 20) #<A Mac Pointer #x1022E0> ; A pointer to 20 bytes of memory.
CFFI> (foreign-alloc :int :initial-element 12) #<A Mac Pointer #x1022E0> CFFI> (mem-ref * :int) 12
CFFI> (foreign-alloc :int :initial-contents '(1 2 3)) #<A Mac Pointer #x1022E0> CFFI> (loop for i from 0 below 3 collect (mem-ref * :int i)) (1 2 3)
CFFI> (foreign-alloc :int :initial-contents #(1 2 3)) #<A Mac Pointer #x1022E0> CFFI> (loop for i from 0 below 3 collect (mem-ref * :int i)) (1 2 3)
;; Another note: what should should be in (mem-ref ** :int 3)? ;; Zero? Ie. Should these previous two calls to foreign-alloc ;; allocate 3*sizeof(int) or 4*sizeof(int) bytes? Lispworks seems to ;; do the latter.
CFFI> (foreign-alloc :string :initial-element "foo") ;; I think this should do something similar to CLISP's ;; FFI:ALLOCATE-DEEP, and it should Just Work if we apply the :to-c ;; translator, which will allocate space for "foo".
;; A problem here is freeing this memory. Should we tell the user ;; he has to free the complex stuff inside by himself. Or should we ;; come up with something similar to CLISP's FFI:FOREIGN-FREE when ;; passed ":full t". (In this case CFFI:FOREIGN-FREE would have to ;; take an optional type or something to describe what needs ;; freeing.)
Comments are most welcome.
Hi there,
I've been lurking here for a couple of weeks to see how cffi is progressing. It looks good so far!
On Sun, 4 Sep 2005 20:03:54 +0100, Luis Oliveira luismbo@gmail.com said:
Luis> CFFI> (foreign-alloc :int :initial-contents #(1 2 3)) Luis> #<A Mac Pointer #x1022E0> Luis> CFFI> (loop for i from 0 below 3 Luis> collect (mem-ref * :int i)) Luis> (1 2 3)
Luis> ;; Another note: what should should be in (mem-ref ** :int 3)? Luis> ;; Zero? Ie. Should these previous two calls to foreign-alloc Luis> ;; allocate 3*sizeof(int) or 4*sizeof(int) bytes? Lispworks seems to Luis> ;; do the latter.
LispWorks allocates 3*sizeof(int), but the C heap manager might round this up to 4. (mem-ref ** :int 3) should be expected to give a random result or a crash.
Luis> CFFI> (foreign-alloc :string :initial-element "foo") Luis> ;; I think this should do something similar to CLISP's Luis> ;; FFI:ALLOCATE-DEEP, and it should Just Work if we apply the :to-c Luis> ;; translator, which will allocate space for "foo".
I think it depends on whether the :STRING type is an array type, a pointer type or some magic.
Luis> ;; A problem here is freeing this memory. Should we tell the user Luis> ;; he has to free the complex stuff inside by himself. Or should we Luis> ;; come up with something similar to CLISP's FFI:FOREIGN-FREE when Luis> ;; passed ":full t". (In this case CFFI:FOREIGN-FREE would have to Luis> ;; take an optional type or something to describe what needs Luis> ;; freeing.)
Complex stuff is complex to free, so I would say that the user has to do it.
Martin Simmons martin@lispworks.com writes:
Luis> CFFI> (foreign-alloc :int :initial-contents #(1 2 3)) Luis> #<A Mac Pointer #x1022E0> Luis> CFFI> (loop for i from 0 below 3 Luis> collect (mem-ref * :int i)) Luis> (1 2 3)
Luis> ;; Another note: what should should be in (mem-ref ** :int 3)? Luis> ;; Zero? Ie. Should these previous two calls to foreign-alloc Luis> ;; allocate 3*sizeof(int) or 4*sizeof(int) bytes? Lispworks seems to Luis> ;; do the latter.
LispWorks allocates 3*sizeof(int), but the C heap manager might round this up to 4. (mem-ref ** :int 3) should be expected to give a random result or a crash.
Yeah, that makes sense. My thoughts about 0 terminating such an array is probably a symptom of a missing :array type.
Luis> CFFI> (foreign-alloc :string :initial-element "foo") Luis> ;; I think this should do something similar to CLISP's Luis> ;; FFI:ALLOCATE-DEEP, and it should Just Work if we apply the :to-c Luis> ;; translator, which will allocate space for "foo".
I think it depends on whether the :STRING type is an array type, a pointer type or some magic.
CFFI's :string is a pointer and the translator will allocate memory for "foo", so will actually get a char** in this case, not a char*. Hmm..
Luis> ;; A problem here is freeing this memory. Should we tell the user Luis> ;; he has to free the complex stuff inside by himself. Or should we Luis> ;; come up with something similar to CLISP's FFI:FOREIGN-FREE when Luis> ;; passed ":full t". (In this case CFFI:FOREIGN-FREE would have to Luis> ;; take an optional type or something to describe what needs Luis> ;; freeing.)
Complex stuff is complex to free, so I would say that the user has to do it.
Well, I'm going with that. Experience will tell if this is needed or not.
Thanks for your feedback!
Meanwhile, I have implemented this and renamed foreign-alloc to %foreign-alloc (and didn't export this). James, before I rename every foreign-alloc in cffi-*.lisp do you think we should export %foreign-alloc (and rename it to malloc) or not?
By the way, I remember now I found some bugs in Lispworks's FLI (I'm using Lispworks 4.4.5 Personal Edition), will report them tomorrow with some test cases.
On Wed, 07 Sep 2005 06:54:49 +0100, Luis Oliveira luismbo@gmail.com said:
Luis> Martin Simmons martin@lispworks.com writes:
Luis> CFFI> (foreign-alloc :string :initial-element "foo") Luis> ;; I think this should do something similar to CLISP's Luis> ;; FFI:ALLOCATE-DEEP, and it should Just Work if we apply the :to-c Luis> ;; translator, which will allocate space for "foo".
I think it depends on whether the :STRING type is an array type, a pointer type or some magic.
Luis> CFFI's :string is a pointer and the translator will allocate memory for Luis> "foo", so will actually get a char** in this case, not a char*. Hmm..
Aha! :-)
Luis> By the way, I remember now I found some bugs in Lispworks's FLI (I'm Luis> using Lispworks 4.4.5 Personal Edition), will report them tomorrow with Luis> some test cases.
Thanks. BTW, if you had problems with the LW header-file parser and ALCvoid (from OpenAL) not working as void in nullary function decl then I've fix that one just now.
Martin Simmons martin@lispworks.com writes:
Luis> By the way, I remember now I found some bugs in Lispworks's FLI (I'm Luis> using Lispworks 4.4.5 Personal Edition), will report them tomorrow with Luis> some test cases.
Thanks. BTW, if you had problems with the LW header-file parser and ALCvoid (from OpenAL) not working as void in nullary function decl then I've fix that one just now.
No, and it wasn't a bug in Lispworks either, heh. The problem was in cffi-sys:%foreign-alloc. This also fixes a previous problem seen with fli:with-dynamic-foreign-objects, so Lispworks's cffi-sys:with-foreign-ptr now stack allocates again, yay.