Class-Accessor-Fast-GXS

 view release on metacpan or  search on metacpan

lib/Class/Accessor/Fast/GXS.pm  view on Meta::CPAN

    } while @parts;
    unless ( $found ) {
        warn "not found dynamic library for $class" if $DEBUG;
        return $self->$method($field, @_);
    }

    return \&{"${class}::__xs_$name"}
        if defined &{"${class}::__xs_$name"};

    warn "C lib has no $name in $class" if $DEBUG;
    return $self->$method($field, @_);
}

my %handles = ();
sub __get_handle_for_xs {
    my $self = shift;
    my $class = ref $self || $self;
    my $module = $MODULE || $class;

    my $fh = $handles{ $module };
    return $fh if $fh;

    my $fn = $GENERATE_TO;
    $fn = join '/', $GENERATE_TO, split /::/, $module .".xs"
        if -d $GENERATE_TO;

    open $fh, ">", $fn or die "couldn't open file '$fn': $!";
    $handles{ $module } = $fh;

    print $fh $head, "\n\n";

    return $fh;
}

# XXX: escaping and unicode support
my %done = ();

sub make_ro_accessor {
    my $self = shift;
    my $field = shift;
    my $name = $self->accessor_name_for($field);
    return $self->__xs_load_or_fallback_to_super('make_ro_accessor', $name, $field, @_)
        unless defined $GENERATE_TO;

    my $class = ref $self || $self;
    return if $done{$class."::".$name}++;

    warn "making $field ro accessor for $class" if $DEBUG;

    my $fh = $self->__get_handle_for_xs;
    print $fh "MODULE = ". ($MODULE||$class) ." PACKAGE = $class\n\n";

    my $length = length $field;
    print $fh <<END;
void
__xs_$name(self)
    SV* self;
  PROTOTYPE: DISABLE
  INIT:
    SV** res;
  PPCODE:
    res = hv_fetch((HV *)SvRV(self), "$field", $length, 0);
    if (res == NULL)
        XSRETURN_UNDEF;

    XPUSHs(*res);

END

    return undef;
}

sub make_wo_accessor {
    my $self = shift;
    my $field = shift;
    my $name = $self->mutator_name_for($field);
    return $self->__xs_load_or_fallback_to_super('make_wo_accessor', $name, $field, @_)
        unless defined $GENERATE_TO;

    my $class = ref $self || $self;
    return if $done{$class."::".$name}++;

    warn "making $field wo accessor for $class" if $DEBUG;

    my $fh = $self->__get_handle_for_xs;
    print $fh "MODULE = ". ($MODULE||$class) ." PACKAGE = $class\n\n";

    my $length = length $field;
    print $fh <<END;
void
__xs_$name(self, ...)
    SV* self;
  PROTOTYPE: DISABLE
  INIT:
    SV **res;
    SV *newvalue;
    IV i;
  PPCODE:
    if ( items == 2 ) {
        newvalue = SvREFCNT_inc(ST(1));
    } else if ( items > 2 ) {
        AV* tmp = newAV();
        av_extend(tmp, items-1);
        for(i = 1; i < items; i++) {
            if (!av_store(tmp, i - 1, SvREFCNT_inc(ST(i)))) {
                SvREFCNT_dec(ST(i));
                croak("Cannot store value in array");
            }
        }
        newvalue = newRV_noinc((SV*) tmp);
    } else {
        croak("Cannot access the value");
    }

    if (res = hv_store((HV*)SvRV(self), "$field", $length, newvalue, 0)) {
        XPUSHs(*res);
    } else {
        SvREFCNT_dec(newvalue);
        croak("Failed to write new value to hash.");
        XSRETURN_UNDEF;
    }

END

    return undef;
}

sub make_accessor {
    my $self = shift;
    my $field = shift;
    # doesn't matter here what to call, they are equal
    my $name = $self->mutator_name_for($field);
    return $self->__xs_load_or_fallback_to_super('make_accessor', $name, $field, @_)
        unless defined $GENERATE_TO;

    my $class = ref $self || $self;
    return if $done{$class."::".$name}++;

    warn "making $field accessor for $class" if $DEBUG;

    my $fh = $self->__get_handle_for_xs;
    print $fh "MODULE = ". ($MODULE||$class) ." PACKAGE = $class\n\n";

    my $length = length $field;
    print $fh <<END;
void
__xs_$name(self, ...)
    SV* self;
  PROTOTYPE: DISABLE
  INIT:
    SV **res;
    SV *newvalue;
    IV i;
  PPCODE:
    if ( items == 1 ) {
        res = hv_fetch((HV *)SvRV(self), "$field", $length, 0);
        if (res == NULL)
            XSRETURN_UNDEF;

        XPUSHs(*res);
        XSRETURN(1);
    }
    else if ( items == 2 ) {
        newvalue = SvREFCNT_inc(ST(1));
    }
    else {
        AV* tmp = newAV();
        av_extend(tmp, items-1);
        for(i = 1; i < items; i++) {
            if (!av_store(tmp, i - 1, SvREFCNT_inc(ST(i)))) {
                SvREFCNT_dec(ST(i));
                croak("Cannot store value in array");
            }
        }
        newvalue = newRV_noinc((SV*) tmp);
    }

    if (res = hv_store((HV*)SvRV(self), "$field", $length, newvalue, 0)) {
        XPUSHs(*res);
    } else {
        SvREFCNT_dec(newvalue);
        croak("Failed to write new value to hash.");
        XSRETURN_UNDEF;
    }

END

    return undef;
}

1;

__END__

=head1 AUTHOR

Ruslan Zakirov E<lt>ruz@bestpractical.comE<gt>

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut



( run in 2.207 seconds using v1.01-cache-2.11-cpan-71847e10f99 )