Alt-Acme-Math-XS-CPP
view release on metacpan or search on metacpan
inc/Inline/CPP.pm view on Meta::CPAN
my $offset = scalar @args; # which is the first optional?
my $total = $offset + scalar @opts;
for my $i ($offset .. $total - 1) {
push @CODE, 'case ' . ($i + 1) . ":\n";
my @tmp;
for my $j ($offset .. $i) {
my $targ = $opts[$j - $offset]{name};
my $type = $opts[$j - $offset]{type};
my $src = "ST($j)";
my $conv = $o->typeconv($targ, $src, $type, 'input_expr');
push @CODE, $conv . ";\n";
push @tmp, $targ;
}
push @CODE, "\tRETVAL = " unless $void;
push @CODE,
call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
$thing->{rtype}, (map { $_->{name} } @args), @tmp);
push @CODE, "\tbreak; /* case " . ($i + 1) . " */\n";
}
push @CODE, "default:\n";
push @CODE, "\tRETVAL = " unless $void;
push @CODE,
call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
$thing->{rtype}, map { $_->{name} } @args);
push @CODE, "} /* switch(items) */ \n";
}
elsif ($void) {
push @CODE, "\t";
push @CODE,
call_or_instantiate($name, $ctor, $dtor, $class, 0, q{},
map { $_->{name} } @args);
}
elsif ($ellipsis or $thing->{rconst}) {
push @CODE, "\t";
push @CODE, 'RETVAL = ';
push @CODE,
call_or_instantiate($name, $ctor, $dtor, $class, $thing->{rconst},
$thing->{rtype}, map { $_->{name} } @args);
}
if ($void) {
push @CODE, <<'END';
if (PL_markstack_ptr != __temp_markstack_ptr) {
/* truly void, because dXSARGS not invoked */
PL_markstack_ptr = __temp_markstack_ptr;
XSRETURN_EMPTY; /* return empty stack */
}
/* must have used dXSARGS; list context implied */
return; /* assume stack size is correct */
END
}
elsif ($ellipsis) {
push @CODE, "\tPL_markstack_ptr = __temp_markstack_ptr;\n";
}
# The actual function:
local $" = q{};
push @XS, "${t}PREINIT:\n@PREINIT" if @PREINIT;
push @XS, $t;
push @XS, 'PP' if $void and @CODE;
push @XS, "CODE:\n@CODE" if @CODE;
push @XS, "${t}OUTPUT:\nRETVAL\n" if @CODE and not $void;
push @XS, "\n";
return "@XS";
}
sub _map_subnames_cpp_to_perl {
my ($thing, $name, $class) = @_;
my ($XS, $ctor, $dtor) = (q{}, 0, 0);
if ($name eq $class) { # ctor
$XS = $class . " *\n" . $class . '::new';
$ctor = 1;
}
elsif ($name eq "~$class") { # dtor
$XS = "void\n$class" . '::DESTROY';
$dtor = 1;
}
elsif ($class) { # method
$XS = "$thing->{rtype}\n$class" . "::$thing->{name}";
}
else { # function
$XS = "$thing->{rtype}\n$thing->{name}";
}
return ($XS, $ctor, $dtor);
}
sub call_or_instantiate {
my ($name, $ctor, $dtor, $class, $const, $type, @args) = @_;
# Create an rvalue (which might be const-casted later).
my $rval = q{};
$rval .= 'new ' if $ctor;
$rval .= 'delete ' if $dtor;
$rval .= 'THIS->' if ($class and not($ctor or $dtor));
$rval .= $name . '(' . join(q{,}, @args) . ')';
return const_cast($rval, $const, $type) . ";\n";
} ### Tested.
sub const_cast {
my ($value, $const, $type) = @_;
return $value unless $const and $type =~ m/[*&]/x;
return "const_cast<$type>($value)";
} ### Tested.
sub write_typemap {
my $o = shift;
my $filename = "$o->{API}{build_dir}/CPP.map";
my $type_kind = $o->{ILSM}{typeconv}{type_kind};
my $typemap = q{};
$typemap .= $_ . "\t" x 2 . $TYPEMAP_KIND . "\n"
for grep { $type_kind->{$_} eq $TYPEMAP_KIND } keys %{$type_kind};
return unless length $typemap;
my $tm_output = <<"END";
TYPEMAP
$typemap
OUTPUT
$TYPEMAP_KIND
$o->{ILSM}{typeconv}{output_expr}{$TYPEMAP_KIND}
INPUT
$TYPEMAP_KIND
$o->{ILSM}{typeconv}{input_expr}{$TYPEMAP_KIND}
END
# Open an output file, create if necessary, then lock, then truncate.
# This replaces the following, which wasn't lock-safe:
sysopen(my $TYPEMAP_FH, $filename, O_WRONLY | O_CREAT)
or croak "Error: Can't write to $filename: $!";
# Flock and truncate (truncating to zero length to simulate '>' mode).
flock $TYPEMAP_FH, LOCK_EX
or croak "Error: Can't obtain lock for $filename: $!";
truncate $TYPEMAP_FH, 0 or croak "Error: Can't truncate $filename: $!";
# End of new lock-safe code.
print {$TYPEMAP_FH} $tm_output;
close $TYPEMAP_FH or croak "Error: Can't close $filename after write: $!";
$o->validate(TYPEMAPS => $filename);
return;
}
# Generate type conversion code: perl2c or c2perl.
sub typeconv {
my ($o, $var, $arg, $type, $dir, $preproc) = @_;
my $tkind = $o->{ILSM}{typeconv}{type_kind}{$type};
my $ret;
{
no strict; ## no critic (strict)
# The conditional avoids uninitialized warnings if user passes
# a C++ function with 'void' as param.
if (defined $tkind) {
# eval of typemap gives "Uninit"
no warnings 'uninitialized'; ## no critic (warnings)
# Even without the conditional this line must remain.
$ret = eval ## no critic (eval)
qq{qq{$o->{ILSM}{typeconv}{$dir}{$tkind}}};
}
else {
$ret = q{};
}
}
chomp $ret;
$ret =~ s/\n/\\\n/xg if $preproc;
return $ret;
}
# Verify that the return type and all arguments can be bound to Perl.
sub check_type {
my ($o, $thing, $ctor, $dtor) = @_;
my $badtype;
# strip "useless" modifiers so the type is found in typemap:
BADTYPE: while (1) {
if (!($ctor || $dtor)) {
( run in 0.731 second using v1.01-cache-2.11-cpan-39bf76dae61 )