I'm trying to work out the best way to honour overloading in XSUBs.
In pure perl I can write a function that expects an array reference,
and dereference the passed-in reference, regardless of whether the
passed-in parameter is a real array reference, a blessed object using
an array for its storage or any other blessed reference with '@{}'
overloading, like this:

#!perl -w
use strict;
use warnings;

sub rect {
        my($left, $top, $right, $bottom) = @{$_[0]};
        print "($left,$top) ($right,$bottom)\n";
}

rect([10,20,30,40]);
rect(Rect1->new(10,20,30,40));
rect(Rect2->new(10,20,30,40));

package Rect1;

sub new {
        my $class = shift;
        return bless [EMAIL PROTECTED], $class;
}

package Rect2;

use overload '@{}' => \&_rectify;

sub new {
        my $class = shift;
        return bless { l => $_[0], t => $_[1], r => $_[2], b => $_[3] } ,
$class;
}

sub _rectify {
        my $s = shift;
        return [ $s->{l}, $s->{t}, $s->{r}, $s->{b} ];
}
__END__

Now, I'd like to implement rect() in XS.  I can find very little
information about handling overloading for anything other than
standard scalar types, but after scouring the perl source, and working
my way through all those macros, I've come up with this (see below),
which seems to work.

Questions:
(1) Is this an OK way to do it?
(2) Is using this macro OK for an XS module?  I think the only
function that gets called is amagic_call() which is marked as public.
(3) Is there a better way?

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "ppport.h"

STATIC AV*
sv_2av(pTHX_ SV* sv)
{
  /* tryAMAGICunDEREF (attempt to apply AMAGIC (overloading),
   * using unary operation to dererference an RV.  Ultimately
   * this macro calls Perl_amagic_call() (gv.c).
   * This macro uses a pointer to an SV* called 'sp'
   * as input, and uses an SV* called 'sv' as output.  See pp_rv2av
   * in pp_hot.c and Perl_sv_2_cv in sv.c for example usage.
   */
  {
    SV* const *sp = &sv;
    tryAMAGICunDEREF(to_av);
  }

  /* Now take what we've got and attempt to use it as a standard
   * reference to an array
   */
  {
    AV* av;

    if(sv && SvROK(sv) && (av = (AV*)SvRV(sv)) && SvTYPE((SV*)av) ==
SVt_PVAV) {
      return av;
    }
  }

  return NULL;
}

MODULE = RectXS         PACKAGE = RectXS

void
rect(sv)
    SV *sv
  PPCODE:
    AV *av = sv_2av(aTHX_ sv);

    if(av) {
      printf("(%"UVuf",%"UVuf") (%"UVuf",%"UVuf")\n",
        SvUV(*av_fetch(av,0,0)),
        SvUV(*av_fetch(av,1,0)),
        SvUV(*av_fetch(av,2,0)),
        SvUV(*av_fetch(av,3,0))  ); /* Error checking omitted */
    }
    else {
      printf("Oops, not an array.\n");
    }

Thanks in advance for any assistance.
Rob.

Reply via email to