rif | 6 Jul 2006 00:01
Picon
Favicon

trying to understand foreign types and translations


I've been poking at this for over an hour, but I'm just not sure how to
get this to work.

I have a foreign object, points to a vector of (C) double-floats:

(defstruct (fnv-double (:constructor make-fnv-double-internal))
  (foreign-pointer nil :read-only t)
  (size 0 :type fixnum :read-only t))

I can create and manipulate it.  I need to know how to define (with
defcfun) an interface to a C function which expects a vector of
double-floats.  My attempts have been along the lines of:

(defmethod translate-to-foreign (val (f fnv-double)) (fnv-foreign-pointer f))

and then declaring something like

(defcfun ("foo" :%foo) :double
   (x fnv-double))

but neither this nor any of the variants I've tried seems to work at
all.  I think I need to either defctype or define-foreign-type first,
but I haven't gotten that to work either.  Can anyone suggest how to do
this?

Cheers,

rif
(Continue reading)

James Bielman | 6 Jul 2006 02:40

Re: trying to understand foreign types and translations

rif <rif <at> MIT.EDU> writes:

> I have a foreign object, points to a vector of (C) double-floats:
>
> (defstruct (fnv-double (:constructor make-fnv-double-internal))
>   (foreign-pointer nil :read-only t)
>   (size 0 :type fixnum :read-only t))
>
> I can create and manipulate it.  I need to know how to define (with
> defcfun) an interface to a C function which expects a vector of
> double-floats.  My attempts have been along the lines of:
>
> (defmethod translate-to-foreign (val (f fnv-double)) (fnv-foreign-pointer f))

The two arguments to TRANSLATE-TO-FOREIGN are the Lisp object to be
converted, and the name of the foreign type to convert to.  First,
declare a foreign typedef for :POINTER (since you will ultimately be
returning a pointer from the type translator) that you use to hang
your type translator on:

(defctype fnv-double :pointer)

Then you can specialize TRANSLATE-TO-FOREIGN on both the Lisp value
and the foreign type (using an EQL specializer):

(defmethod translate-to-foreign ((value fnv-double) (name (eql 'fnv-double)))
  (fnv-foreign-pointer value))

It might be confusing to call both the Lisp and foreign types
FNV-DOUBLE, but it is legal because foreign type names are a separate
(Continue reading)

rif | 6 Jul 2006 02:47
Picon
Favicon

Re: trying to understand foreign types and translations


> The two arguments to TRANSLATE-TO-FOREIGN are the Lisp object to be
> converted, and the name of the foreign type to convert to.  First,
> declare a foreign typedef for :POINTER (since you will ultimately be
> returning a pointer from the type translator) that you use to hang
> your type translator on:
> 
> (defctype fnv-double :pointer)
> 
> Then you can specialize TRANSLATE-TO-FOREIGN on both the Lisp value
> and the foreign type (using an EQL specializer):
> 
> (defmethod translate-to-foreign ((value fnv-double) (name (eql 'fnv-double)))
>   (fnv-foreign-pointer value))
> 
> It might be confusing to call both the Lisp and foreign types
> FNV-DOUBLE, but it is legal because foreign type names are a separate
> namespace from Lisp types (viva Lisp-N!).  It is important to remember
> the distinction between the two though.
> 
> > and then declaring something like
> >
> > (defcfun ("foo" :%foo) :double
> >    (x fnv-double))
> 
> should just work!
> 
> (This is untested and I haven't really been doing any CFFI hacking
> lately, so I apologize if I missed something obvious here.)
> 
(Continue reading)

James Bielman | 6 Jul 2006 03:03

Re: trying to understand foreign types and translations

rif <rif <at> MIT.EDU> writes:

> I don't quite understand.  fnv-double is NOT a pointer.  It's a CL
> struct that holds two arguments, one of which is the foreign
> pointer.  I see I was misusing translate-to-foreign, so maybe I
> don't need a defctype at all, just an appropriate
> translate-to-foreign?

Take the type translators out of the picture for a minute.  I assume
the C function you want to call looks like:

  double foo (double *array);

So, you could define an interface to "foo" like this:

  (defcfun "foo" :double
    (array :pointer))

And call it like:

  (let ((fnv ...))
    (foo (fnv-foreign-pointer fnv)))

Now, when we want to set up a type translator, we need to introduce a
new foreign type that will "own" the translator so that we don't
override the default behavior.  So instead of the :POINTER argument to
FOO above, we define a typedef for :POINTER that we can attach our
translation behavior to:

  (defctype fnv-pointer :pointer)
(Continue reading)

Stuart Sierra | 14 Jul 2006 02:39
Gravatar

Mutable Pointers

Hello,

I'm working on a CFFI interface to the Perl API (I thought
it would be fun - ha!) and I need to be able to do C-style
pointer arithmetic.  That is, I have a foreign pointer
declared with DEFCVAR and I need to alter the address stored
there.  I couldn't see a way to do this with CFFI, so I
created a new foreign type called :ADDRESS that would treat
the foreign pointer as an integer value that I could modify.

Here's my code:

  (defvar *pointer-size*
    (foreign-type-size :pointer)
    "The size of a pointer on the current platform, in bytes.")

  (ecase *pointer-size*
    (1 (defctype :address :uint8))   ; unlikely
    (2 (defctype :address :uint16))  ; possible
    (4 (defctype :address :uint32))  ; most common
    (8 (defctype :address :uint64))) ; possible

  (defmacro address-incf (address &optional (n 1))
    "Increment ADDRESS by N pointers, like ++i on a C pointer."
    `(incf ,address (* ,n *pointer-size*)))

  (defmacro address-decf (address &optional (n 1))
    "Decrement ADDRESS by N pointers, like --i on a C pointer."
    `(decf ,address (* ,n *pointer-size*)))

(Continue reading)

Stephen Compall | 14 Jul 2006 02:50
Picon

Re: Mutable Pointers

Stuart Sierra wrote:
> Hello,
> 
> I'm working on a CFFI interface to the Perl API (I thought
> it would be fun - ha!) and I need to be able to do C-style
> pointer arithmetic.  That is, I have a foreign pointer
> declared with DEFCVAR and I need to alter the address stored
> there.  I couldn't see a way to do this with CFFI, so I

You've got one half of the answer already -- `make-pointer'.  Now see
`pointer-address'
(http://common-lisp.net/project/cffi/manual/html_node/pointer_002daddress.html).

--

-- 
Stephen Compall
http://scompall.nocandysw.com/blog
Stuart Sierra | 14 Jul 2006 03:38
Gravatar

Re: Mutable Pointers

Stephen Compall <s11 <at> member.fsf.org> writes:
> Stuart Sierra wrote:
>> I'm working on a CFFI interface to the Perl API (I thought
>> it would be fun - ha!) and I need to be able to do C-style
>> pointer arithmetic.  That is, I have a foreign pointer
>> declared with DEFCVAR and I need to alter the address stored
>> there.  I couldn't see a way to do this with CFFI, so I
>
> You've got one half of the answer already -- `make-pointer'.  Now see
> `pointer-address'
> (http://common-lisp.net/project/cffi/manual/html_node/pointer_002daddress.html).

But POINTER-ADDRESS is not setf-able, is it?  I want to do
this:

  (defcvar "stack_pointer" :pointer)

  (incf (pointer-address *stack-pointer*))

where "stack_pointer" is a global variable in an external
library.  But...

  The function (SETF POINTER-ADDRESS) is undefined.
     [Condition of type UNDEFINED-FUNCTION]

-Stuart
Luís Oliveira | 14 Jul 2006 14:30
Picon
Gravatar

Re: Mutable Pointers

On 2006-jul-14, at 02:38, Stuart Sierra wrote:
> But POINTER-ADDRESS is not setf-able, is it?

Right. AFAICT, some of the Lisps supported by CFFI don't have mutable  
pointers.

> I want to do this:
>   (defcvar "stack_pointer" :pointer)
>
>   (incf (pointer-address *stack-pointer*))

See inc-pointer.
<http://common-lisp.net/project/cffi/manual/html_node/ 
inc_002dpointer.html>

(setf *stack-pointer* (inc-pointer *stack-pointer* 1)) should work.  
You can abstract that with a simple macro:

   (defmacro incf-pointer (place &optional (offset 1))
     `(setf ,place (inc-pointer ,place ,offset)))

Any objections to adding this macro to CFFI?

--

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
Stuart Sierra | 14 Jul 2006 17:18
Gravatar

Re: Mutable Pointers

Luís Oliveira wrote:
> On 2006-jul-14, at 02:38, Stuart Sierra wrote:
>> But POINTER-ADDRESS is not setf-able, is it?
> 
> Right. AFAICT, some of the Lisps supported by CFFI don't have mutable 
> pointers.

I suspected as much.  I couldn't find it in SBCL's FFI, at least.

> (setf *stack-pointer* (inc-pointer *stack-pointer* 1)) should work. 
 > You can abstract that with a simple macro:
> 
>   (defmacro incf-pointer (place &optional (offset 1))
>     `(setf ,place (inc-pointer ,place ,offset)))

But won't that set the value that *STACK-POINTER* points to?  In my 
example, *STACK-POINTER* is not a Lisp object but a foreign global 
variable accessed by name with DEFCVAR.  As I understand CFFI's :POINTER 
type, the above macro will modify the memory location that PLACE points 
to but will not modify PLACE itself.

-Stuart
Stephen Compall | 14 Jul 2006 18:01
Picon

Re: Mutable Pointers

On Fri, 2006-07-14 at 13:30 +0100, Luís Oliveira wrote:
> See inc-pointer.
> <http://common-lisp.net/project/cffi/manual/html_node/ 
> inc_002dpointer.html>
> 
> (setf *stack-pointer* (inc-pointer *stack-pointer* 1)) should work.  
> You can abstract that with a simple macro:
> 
>    (defmacro incf-pointer (place &optional (offset 1))
>      `(setf ,place (inc-pointer ,place ,offset)))
> 
> Any objections to adding this macro to CFFI?

This evaluates the PLACE forms twice.  If I follow correctly, this can
be more generally solved with a cross-platform setf-expander for
POINTER-ADDRESS that requires its PTR arg to be a place, whereupon
things like (incf (pointer-address *ptr*)) and any other place-modifier
should work.

--

-- 
Stephen Compall
http://scompall.nocandysw.com/blog
_______________________________________________
cffi-devel mailing list
cffi-devel <at> common-lisp.net
http://common-lisp.net/cgi-bin/mailman/listinfo/cffi-devel

Gmane