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

Dear fellow monks,
I am trying to use one of my own c files to extend (and ultimately speed up) one of my perl script.
I read the perlxstut and friends
I would like to pass a reference to an array of integers to a C function I have. The protype of the function looks like that:
double foo_in_c(int *, int);
I did something in XS that works but that in my opinion is not very elegant, and also not very efficient (I have to copy the array).
double foo(aref) SV * aref INIT: int i, last_index; int *array; if ((!SvROK(aref)) || (SvTYPE(SvRV(aref)) != SVt_PVAV) || ((last_i +ndex = av_len((AV *)SvRV(aref))) < 0)) { XSRETURN_UNDEF; } array = (int*)calloc(last_index+1, sizeof(int) CODE: for(i=0;i<=last_index;i++) array[i] = SvIV(*av_fetch((AV *)SvRV(array), i, 0)); RETVAL = foo_in_c(array, last_index+1); OUTPUT: RETVAL
My question is simple: does anyone know of a better way to do that? Especially, how is it possible to avoid the copying part?
Thanks in advance,
--
jey

Replies are listed 'Best First'.
Re: Extending Perl with C: how to use an array reference?
by ikegami (Patriarch) on Apr 11, 2007 at 21:26 UTC

    Especially, how is it possible to avoid the copying part?

    I don't know if there's an existing function to do this for you, but you must inevitably convert from an AV to an int* unless you change foo_in_c to work with the AV directly.

    On the bright side, I seriously doubt this is as inefficient as think. The time it takes to do the copy is surely dwarfed by the time foo_in_c spends processing it.

    You could always make a little helper function if you're concerned about neatness.

Re: Extending Perl with C: how to use an array reference?
by djp (Hermit) on Apr 12, 2007 at 04:35 UTC
Re: Extending Perl with C: how to use an array reference?
by renodino (Curate) on Apr 12, 2007 at 02:33 UTC
    Not certain if it'd be faster, and you might consider it uglier, but...

    Have you considered just using pack() in Perl to turn the Perl array into an int[], then passing the resulting binary scalar into your XS, grabbing the SvPV off the scalar, and treating it like an int[] ? That leaves most of the heavy lifting to Perl.

    BTW: In your version, I fear you've got a memory leak unless foo_in_c() free()'s your temp array...


    Perl Contrarian & SQL fanboy
Re: Extending Perl with C: how to use an array reference?
by BrowserUk (Patriarch) on Apr 11, 2007 at 23:15 UTC
Re: Extending Perl with C: how to use an array reference?
by salva (Canon) on Apr 12, 2007 at 08:27 UTC
    Another solution is to create the int array from Perl using vec, pack or some module like Tie::Array::PackedC or Tie::Array::Packed.

    On most cases this solution will be slower than converting the regular AV to an int array on the XS function wrapper. But, for instance, if you are just passing the arrays around between C functions, and manipulating them directly from Perl only in a few cases it can be faster.

Re: Extending Perl with C: how to use an array reference?
by aufflick (Deacon) on Apr 12, 2007 at 06:03 UTC
    For ad-hoc use of C, it might pay to take a look at Inline::C - it's pretty good at munging the parameters for you.