caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Richard Jones <rich@annexia.org>
To: Oliver Kania <kania.oliver@googlemail.com>, caml-list@inria.fr
Subject: Re: [Caml-list] embedding ocaml from C++ -- PODs
Date: Tue, 3 Jul 2007 09:59:52 +0100	[thread overview]
Message-ID: <20070703085951.GA15238@furbychan.cocan.org> (raw)
In-Reply-To: <1262c4ee0707020509h48d43e24s5e8902810cae7985@mail.gmail.com>

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


  parent reply	other threads:[~2007-07-03  8:59 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-02 11:06 Oliver Kania
2007-07-02 11:48 ` [Caml-list] " Richard Jones
     [not found]   ` <1262c4ee0707020509h48d43e24s5e8902810cae7985@mail.gmail.com>
2007-07-03  8:59     ` Richard Jones [this message]
2007-07-05 20:43       ` Oliver Kania
2007-07-02 11:49 ` Thomas Fischbacher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070703085951.GA15238@furbychan.cocan.org \
    --to=rich@annexia.org \
    --cc=caml-list@inria.fr \
    --cc=kania.oliver@googlemail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).