From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id D500B7EEF8 for ; Thu, 30 Jul 2015 20:00:47 +0200 (CEST) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of goswin-v-b@web.de) identity=pra; client-ip=212.227.17.11; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="goswin-v-b@web.de"; x-sender="goswin-v-b@web.de"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of goswin-v-b@web.de designates 212.227.17.11 as permitted sender) identity=mailfrom; client-ip=212.227.17.11; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="goswin-v-b@web.de"; x-sender="goswin-v-b@web.de"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mout.web.de) identity=helo; client-ip=212.227.17.11; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="goswin-v-b@web.de"; x-sender="postmaster@mout.web.de"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: A0DcAAA/ZbpVnAsR49Rbg25pviKGAQKBP0wBAQEBAQESAQEBAQEGDQkJIS6EIwEBAQMBJxNPCxgJJQ8FKE+HfQENDMkIH4VnDCCKTIEChQ6DGIEUBZR3hHuHTIFJhwIMiEOEPYNkgjQcgVVtAYJLAQEB X-IPAS-Result: A0DcAAA/ZbpVnAsR49Rbg25pviKGAQKBP0wBAQEBAQESAQEBAQEGDQkJIS6EIwEBAQMBJxNPCxgJJQ8FKE+HfQENDMkIH4VnDCCKTIEChQ6DGIEUBZR3hHuHTIFJhwIMiEOEPYNkgjQcgVVtAYJLAQEB X-IronPort-AV: E=Sophos;i="5.15,578,1432591200"; d="scan'208";a="172180611" Received: from mout.web.de ([212.227.17.11]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 30 Jul 2015 20:00:47 +0200 Received: from frosties.localnet ([95.208.221.151]) by smtp.web.de (mrweb103) with ESMTPSA (Nemesis) id 0LgpNC-1YZ8jA0xmg-00oJU5 for ; Thu, 30 Jul 2015 20:00:46 +0200 Received: from mrvn by frosties.localnet with local (Exim 4.84) (envelope-from ) id 1ZKs8I-00008R-L2 for caml-list@inria.fr; Thu, 30 Jul 2015 20:00:42 +0200 Date: Thu, 30 Jul 2015 20:00:42 +0200 From: Goswin von Brederlow To: caml-list@inria.fr Message-ID: <20150730180041.GA32510@frosties> References: <20150728184042.GA28321@frosties> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.23 (2014-03-12) X-Provags-ID: V03:K0:IRa2cVpvyqka3C4WP9x8LVdSrWoRq6QxOaYaJMrICvW6+RlZ6at Iw2scITov4a00V0fNR2pIUbEnnNBuxqBF5+xOX90EYFIyEMf8vn1k5fOteNOveUIBTJnUa9 mjj0sh8TdG7+5e9pLtPw1jiaGLTwUEAxkDhtx1ndHsMpuOUPrgbl/XgzpG0DXj6V4lUt1T4 IAH9PvLjpB/JcXn4qEX8w== X-UI-Out-Filterresults: notjunk:1;V01:K0:QeG4W+zZTX0=:bxWNzayQEVgzbUjqZ15f0r n1LLf3Im/lA4RryqXeyTowN7tc8iv87hNoGfIfgSq+uT+eDZxTCdjr2kHg1jdlbYfnBqMBFft +F2iwfr/g+0vnMlZVxHOP7XBhcBokav7BSpv63pyUJm9d+WrlLZwalC5BdGGZq9JJX/adQync 5W/8TdqTd9MHhheDbo7E9wfrscMSoFKnrUwDqfW0YLkuJqGZ8QDeEe4l7cEb489SpveBedcwE 1CWOhp4r1xY3+40echVeXcfgY/2pYusIEIN4Irx4i0JnlVuJ7d6u+0zCxJD7DonQl5G/CQ3tk /xbdLmjQ/5loYVyo3FzaZLAAU8SnhSQhcldjHHqVHhuJqqsKtMolLBP0XtvLSHcDQ4SBMhkBP C1aCnassNC19r2dr61ZRibRw3val5bp4F6NbpWHpjyxm5+PaNPWO28O6hM1qdLkejkj81d0RG nbgMopF2+d8/fDzNAv9stjFqEMVVnPX6PAjQX2eOHgnz9xfkbfogAgY7BNmJtdvt/iHwbvTZ1 QJZxDJT1Na5YlbByvMOP4fsJ9YKu49xijGePzefHQsJgEBsB7H0XSL21l/F5m60w9oc5+svUL /ALIsNw8Zl6aQUYSrKqEtBPM19OsgfTuvsW/b2XJogKvwo/IfUAZpcvigkpmsWzU+di2b0prz n4tPhe2aF1BywvcJ2DQf0GbDM0Imd5fpDkX0wzifwRt7Z6g== Subject: Re: [Caml-list] What's the best practice for bindings for c++ templates? On Wed, Jul 29, 2015 at 12:36:53PM +0000, Bauer, Christoph wrote: > Hi, > > > val make : 'a -> 'a t > > val swap : 'a t -> 'a -> 'a > > val get : 'a t -> 'a > > 1) For the stub code I need to instantiate the template with 'a, which > > obviously doesn't work since the C++ stub has no idea about what type > > ocaml will use in the future. > > > > So do I instantiate it with void *? uintptr_t? value? > > 1.) It's value, but I think you ocaml api would need an additional parameter in make to describe the type 'a (cmp to float32 in the bigarray library). Since make gets an initial 'a as argument the type of 'a t should be clear. No extra parameter needed. > > 2) I'm storing ocaml values in C++ structures and getting them back. > > How do I make that play nice with the GC? > > My advice: don't do this. It may work for a while but then the GC moves the values and your > program crashes. It would be better to keep the values in OCaml e.g. in a hashtable and to store the key > (integer or string) in C++. With callbacks to ocaml, you could define some setters/getters for the content > of the value itself. This approach means some overhead, but it should work quite well. > > Sometimes it is also a better idea to make just a copy of OCaml value (std::string(String_val(value))). Yeah, I've considered that the GC moves values around. So the address where c++ stores the value has to be added to the GC root set or there has to be an indirection, like putting the value into a hashtbl like you suggest. The later I find ugly so I was looking for a better solution. > > 3) I have the option of changing the libraries API as it's not set in stone yet. > > What would be beneficial to interfacing with ocaml (and maybe python) > > without making the c++ API to horrible? > > > > E.g. Foo could have: > > > > void set_T_destructor(void (*destructor)(T *t)); > > > > Then ~Foo() would call 'destructor(&t)' to "free" the stored T, which would > > unregister it from the GC. > > So you need something like this (I omit the template stuff): > > class Bar { > ~Bar() { > // call the custom destructor > } > } > > #define CppBar_val(x) (*((Bar**) Data_custom_val(x))) > > static > void finalize_cppbar( value v ) { > delete CppBar_val(v); > } > > > static struct custom_operations cpp_bar_ops = { > "de.web.cpp.bar", > finalize_cppbar, > custom_compare_default, > custom_hash_default, > custom_serialize_default, > custom_deserialize_default > }; > > > static value alloc_cppbar(Bar * bar) > { > value v = alloc_custom(&cpp_bar_ops, sizeof(Bar *), 0, 1); > CppBar_val(v) = bar; > return v; > } > > As Xavier Leroy suggested, you could also use a shared_ptr instead of Bar* and call reset() on it in the finalize_cppbar. > I didn't tried it. > > Regards, > Christoph Bauer I don't think you are seeing this the right way around. Your code would work if Bar was a C++ structure that you want to keep a reference to from ocaml. But here I need a C++ structure that keeps a reference to an ocaml value alive. And it must be destroyed by either ocaml or c++, whichever comes last. Maybe something more like this (pseudocode): class ValueHolder { ValueHolder(value val) : val_(val) { gc_register_root(&val); } ~ValueHolder() { gc_unregister_root(&val); } value val_; }; Now I can store ValueHolder in C++ and the GC will update val_ when it moves the value around. Probably better to store a std::shared_ptr because otherwise the move and copy constructors and assignment operators would need to aquire the runtime lock and update the GC roots too. Overall still not the brilliant and clean solution I'm hoping to exist somewhere out there. :( MfG Goswin