TheGeniuS has asked for the wisdom of the Perl Monks concerning the following question:

We have embedded perl with c++ on a win32 environment to be able to use scripting power in one of our applications. We are able to read-write from perl to C++ and vice versa. We are trying to pass a structure from C++ to perl but are in failure. We can pass variables without a problem. We are still trying to figure some stuff out. We will have nearly 1 million members in our tree, so passing 1 by 1 is out of the question. Are we suppose to map them all 1 by 1 as well in our C++ code ? Isnt there a simpler or faster way of doing this ?? Please remember we are Win32 programmers and not Perl programmers, though we have had some perl experience prior version 5.

We are not expecting full codes. Please just point us in the right direction. Thank you :) !!


The structure we want is something like this
struct somestruct <----------- { int count; <--- This number could be from 25 to 25000 someotherstruct * pdata; <--- Obviously this number will match as +well } struct someotherstruct { <--- This structure can contain alot ... vectorstruct vSomething; vectorstruct vSomethingElse; float, int, char, and what not... } ...
Below is our testing code, mostly based on Perldoc, PerlEmbed and PerlCall
Link

************ // all the rest is temp : figuring this perl thing out... char * cpArguments[] = { "", "test1.pl" }; my_perl = perl_alloc(); ISNOTNULLRETURN(my_perl, "WinMain : NULL my_perl", "Error", -1); perl_construct(my_perl); PL_exit_flags |= PERL_EXIT_DESTRUCT_END; perl_parse(my_perl, NULL, 2, cpArguments, (char **)NULL); // run script // perl_run(my_perl); // run sub from script // char * cpArgumentsToSub[] = { NULL }; // call_argv("OnUpdate", G_DISCARD | G_NOARGS, cpArgumentsToSub); // run sub from script passing 2 vars into @_ (simple test). // ref http://www.apl.jhu.edu/Misc/Unix-info/perl/perlcall.html { SAFEMALLOCI(char, cpBuf, "WinMain : memory allocation failed", -1, + 1000); int a = 243; int b = 527; dSP; int count; SV * sva; //= NULL ? SV * svb; //= NULL ? ENTER; SAVETMPS; sva = sv_2mortal(newSViv(a)); svb = sv_2mortal(newSViv(b)); PUSHMARK(sp); XPUSHs(sva); XPUSHs(svb); PUTBACK; count = perl_call_pv("OnUpdate", G_DISCARD); if (count != 0) { croak("wtf\n"); BOX("wtf\n", "Error"); } int newa = SvIV(sva); int newb = SvIV(svb); sprintf (cpBuf, "A [ original = %d modified = %d ]\nB [ original = + %d modified = %d ]", a, newa, b, newb); BOX(cpBuf, "Debug"); FREETMPS; LEAVE; SAFEFREE(cpBuf); } perl_destruct(my_perl); perl_free(my_perl);
Our perl script :

#!perl use strict; sub OnUpdate { ######################################## # get data ######################################## my ($a, $b) = @_; ######################################## # code using the names ######################################## $a = 5; $b = 3; ######################################## # send data ######################################## $_[0] = $a; $_[1] = $b; }


So having $_[0] to $_[possibly up to 1 million] sounds like a very bad idea to us. We think perl supports structure like variables. We have seen things like, $bleh->sub.
This would be something we would want :
my $data = shift; for (my $i=0; $i<$data->count; $i++) { $data->pdata[$i]->vsomething->x = $whatever; }
Obviously again :), this creates a problem with the "send data" part of the perl script.

Would there be a way to directly modify the memory wihtout reassigning $_[n].
We are not expecting full codes. Please just point us in the right direction. Thank you :) !!




Any help is very appreciated. Thank you for reading

Replies are listed 'Best First'.
Re: Embedding Perl / C++ structure question
by Joost (Canon) on Nov 28, 2007 at 18:58 UTC
    The "most obvious" way to pass complex C++ data to perl is to use objects with accessors with a complementary perl XS mapping (so you're using a pointer to a C++ object like a perl object). You want the accessors because although perl can in theory access the data in a foreign object directly, it gets messy very quickly. IIRC in C++ structs are more or less the same as classes so you should be able to transform your structs into classes reasonably easily.

    In C++

    class SomeObject { public: int get_valueA(); void set_valueA(int value); // etc... }
    XS code (you need these to use the methods from SomeObject in perl:
    int SomeObject::get_valueA() void SomeObject::set_valueA(int value)
    You'll also want to set up a typemap for each class. See also the standard typemap file in your perl distribution for T_PTROBJ_SPECIAL.

    See also perlxstut and perlxs and the book "Extending and Embedding Perl".

      After a little testing we were able to pass a structure root and have the structure inside perl as we wanted.
      $foo->{whatever}->{whatever} = $bar;
      Obviously now we could send it back using the  $_[n]

      Going to verify your advice and links and eat some pizza :D

      Thank you very much for your prompt reply
        Just a general tip: there's a trade-off between passing a "pure perl" structure and using objects that are really C structs underneath (besides the general pros and cons about encapsulation of classes vs open structs etc):

        If you're going to pass a couple of thousands of structs containing many properties in a list (or nested) and you only really want to query a few of those properties in your perl code, you may well spend much more time converting all the data than you really need, while if you use objects you generally convert the property from perl to C or vice versa each time you access it from perl (but you don't need to convert anything you're not actually accessing).

        Using objects instead of complex nested hashes may also be more efficient when you're modifying the structures, since it's usually trivial to keep the C and perl side in sync when you're using objects, while otherwise you're have to inspect the complete structure each time you pass it from C to perl to C.