Version française
Home     About     Download     Resources     Contact us    
Browse thread
embedding ocaml from C++ -- PODs
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: Oliver Kania <kania.oliver@g...>
Subject: Re: [Caml-list] embedding ocaml from C++ -- PODs
thanks !!

On 7/3/07, Richard Jones <rich@annexia.org> wrote:
>
> On Mon, Jul 02, 2007 at 02:09:41PM +0200, Oliver Kania wrote:
> > Hi there,
> > yes, basically I can use ocaml-types.
> > I guess I will have to "unwrap" them on the C-side.
> > I have a favor to ask from you:
> > Could you please post a small example with, lets say
> > a strucutre with 4 members, showing both the C and the ocaml-side
> > modifying it ? I do not find the Ocaml documentatino to be very
> instructive
> > concerning this topic.
>
> Please CC replies to the list.
>
> Here's an example showing a four element structure shared between C
> and OCaml.  All the fields except the float can be modified on the
> OCaml side (you can get around that restriction by keeping any floats
> you need in a separate float-only structure).  All fields can be
> modified on the C side.
>
> It's only very lightly tested, so probably contains bugs.
>
> Rich.
>
> ------------------------------------------------------------ st.ml
> open Printf
>
> (* All fields in struct4 are mutable from the OCaml side, except
> * the boxed float.  If you want to share and update floats, then
> * it's better to use a separate float-only array or structure
> * for them, so they are stored unboxed and can be directly
> * modified from OCaml.
> *)
> type struct4 = {
>   mutable memb1 : int;
>   mutable memb2 : enum4;
>   memb3 : float;
>   mutable memb4 : int;
> }
> and enum4 = Is0 | Is1 | Is2 | Is3
>
> let string_of_enum4 = function
>   | Is0 -> "Is0" | Is1 -> "Is1" | Is2 -> "Is2" | Is3 -> "Is3"
>
> let next_enum4 = function
>   | Is0 -> Is1 | Is1 -> Is2 | Is2 -> Is3 | Is3 -> Is0
>
> external create_struct4_from_c : unit -> struct4 = "create_struct4"
>
> external print_struct4_from_c : struct4 -> unit = "print_struct4"
>
> external update_struct4_from_c : struct4 -> unit = "update_struct4"
>
> let print_struct4_from_ocaml data =
>   printf "OCaml: memb1 = %d\n" data.memb1;
>   printf "OCaml: memb2 = %s\n" (string_of_enum4 data.memb2);
>   printf "OCaml: memb3 = %f\n" data.memb3;
>   printf "OCaml: memb4 = %d\n" data.memb4;
>   flush stdout
>
> let update_struct4_from_ocaml data =
>   data.memb1 <- data.memb1 + 1;
>   data.memb2 <- next_enum4 data.memb2;
>   data.memb4 <- data.memb4 + 2
>
> let () =
>   let data = create_struct4_from_c () in
>   while true do
>     print_struct4_from_c data;
>     print_struct4_from_ocaml data;
>     printf "* updating struct4 from C\n"; flush stdout;
>     update_struct4_from_c data;
>     print_struct4_from_c data;
>     print_struct4_from_ocaml data;
>     printf "* updating struct4 from OCaml\n"; flush stdout;
>     update_struct4_from_ocaml data;
>     Gc.compact ()
>   done
>
>
> ------------------------------------------------------------ st_c.c
> #include <stdio.h>
>
> #include <caml/config.h>
> #include <caml/mlvalues.h>
> #include <caml/memory.h>
>
> struct struct4 {
>   value header;                 /* CAML header word. */
>   value memb1;
>   value memb2;
>   value memb3;                  /* NB: boxed */
>   value memb4;
> };
>
> #if defined(ARCH_ALIGN_DOUBLE)
> #warn "this code probably won't work on 32 bit ARCH_ALIGN_DOUBLE
> platforms"
> #endif
> struct memb3 {                  /* Storage for a float. */
>   value header;                 /* CAML header word. */
>   double d;                     /* The float itself. */
> };
>
> CAMLprim value
> create_struct4 (value unitv)
> {
>   CAMLparam1 (unitv);
>   struct struct4 *data;
>   struct memb3 *memb3;
>
>   /* Allocate on the C heap and return a raw pointer.  For
>    * provisos about this, see:
>    * http://caml.inria.fr/pub/old_caml_site/caml-list/1415.html
>    *
> http://caml.inria.fr/pub/ml-archives/caml-list/2006/09/977818689f4ceb2178c592453df7a343.en.html
>    */
>   data = malloc (sizeof *data);
>
>   /* We must initialise at least the header and the boxed memb3.
>    * Best to do all fields.
>    */
>   data->header = 4 << 10;
>   data->memb1 = Val_int (0);
>   data->memb2 = Val_int (0);    /* Is0 */
>
>   memb3 = malloc (sizeof *memb3);
>   memb3->header = 1 << 10 | Double_tag;
>   memb3->d = 0.;
>   data->memb3 = (value) &memb3->d;
>
>   data->memb4 = Val_int (0);
>
>   CAMLreturn ((value) &data->memb1);
> }
>
> CAMLprim value
> print_struct4 (value datav)
> {
>   CAMLparam0 ();                /* datav isn't on the CAML heap. */
>   struct struct4 *data = (struct struct4 *) Hp_val (datav);
>   struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);
>
>   printf ("    C: memb1 = %d\n", Int_val (data->memb1));
>   printf ("    C: memb2 = Is%d\n", Int_val (data->memb2));
>   printf ("    C: memb3 = %f\n", memb3->d);
>   printf ("    C: memb4 = %d\n", Int_val (data->memb4));
>   fflush (stdout);
>
>   CAMLreturn (Val_unit);
> }
>
> CAMLprim value
> update_struct4 (value datav)
> {
>   CAMLparam0 ();                /* datav isn't on the CAML heap. */
>   struct struct4 *data = (struct struct4 *) Hp_val (datav);
>   struct memb3 *memb3 = (struct memb3 *) Hp_val (data->memb3);
>   int i;
>
>   data->memb1 = Val_int (Int_val (data->memb1) + 1);
>   i = Int_val (data->memb2);
>   i++;
>   if (i > 3) i = 0;
>   data->memb2 = Val_int (i);
>   memb3->d += 0.1;
>   data->memb4 = Val_int (Int_val (data->memb4) + 2);
>
>   CAMLreturn (Val_unit);
> }
>
> ------------------------------------------------------------ Makefile
> CC      := gcc
> CFLAGS  := -Wall -Werror -I$(shell ocamlc -where)
>
> all:    test
>
> test:   st.cmx st_c.o
>         ocamlopt -o $@ $^
>
> st.cmx: st.ml
>         ocamlopt -o $@ -c $^
>
> ----------------------------------------------------------------------
>
>
> --
> Richard Jones
> Red Hat
>