1

I would like to insert and remove elements into an existing Perl array passed into a XSUB.

perlapi has av_push, av_pop, av_fetch, av_store and friends for array manipulation. I was hoping for av_insert or av_splice or similar functions, but these don't seem to exist.

There is av_delete, but the documentation describes this as replacing the element with undef, not actually removing the item from the array.

Of course I could manually resize the array (av_extend) and loop moving elements (av_fetch/av_store).

Is there an existing API function I can use? If so a pointer to its documentation would be great.

toolic
  • 57,801
  • 17
  • 75
  • 117
drclaw
  • 2,463
  • 9
  • 23

1 Answers1

2
void av_insert( pTHX_ AV * av, Size_t key, SV * sv ) {
#define av_insert( a, b, c ) av_insert( aTHX_ a, b, c )
   sv = newSVsv( sv );

   Size_t count = av_count( av );
   if ( key < count ) {
      av_extend( av, count );
      SV ** a = AvARRAY( av );
      memmove( a+key, a+key+1, sizeof( SV * ) * ( count - key ) );
      a[ key ] = sv;
   } else {
      *av_fetch( av, key, 1 ) = sv;
   }
}
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • 1
    That would crash if applied to a tied array. – Dave Mitchell Sep 15 '22 at 08:28
  • @Dave Mitchell, If you post something better, I'll delete mine – ikegami Sep 15 '22 at 14:13
  • @ikegami I was playing with your code snippet and found an error and learnt a few things: 1. extend line should be like: `av_extend(av, av_count(av));`. 2. I used the 'perl memcpy': `Move(a+key, a+key+1), count-key, SV *);` 3. The direct assignment of `sv` into the array makes an alias and doesn't increase the refcount. `newSVsv(sv)` fixes that? I still need to look into what `pTHX_` is all about – drclaw Sep 15 '22 at 21:13
  • 2
    @drclaw, Fixed. /// It's part of what allows multiple Perl interpreters to be in the same process. Threads use this. `pTHX_` is the parameter form, `aTHX_` is the arg form .`_` represents a comma. They expand to `PerlInterpreter *my_perl,` and `my_perl,` in Perls with support for multiple interpreters (those with `MULTIPLICITY` defined), and to nothing in those without. The context can be fetched by using `dTHX;`, but it's cheaper to use `#define PERL_NO_GET_CONTEXT` and to pass it as a parameter. Perl uses macros just like I did to pass it to the functions that need it (virtually all of them) – ikegami Sep 15 '22 at 23:18