File Coverage

blib/lib/PDL/PP/CType.pm
Criterion Covered Total %
statement 44 90 48.8
branch 12 50 24.0
condition 8 21 38.1
subroutine 11 13 84.6
pod 0 10 0.0
total 75 184 40.7


line stmt bran cond sub pod time code
1             # Represent any C type.
2             # Type contains the size of arrays, which is either constant
3             # or resolved (into an object) from resolveobj.
4              
5             package # hide from PAUSE/MetaCPAN
6             PDL::PP::CType;
7 3     3   27 use strict;
  3         7  
  3         138  
8 3     3   16 use warnings;
  3         6  
  3         299  
9 3     3   25 use Carp;
  3         6  
  3         8227  
10              
11             # new PDL::PP::CType(resolveobj,str)
12              
13             sub new {
14 89     89 0 248 my $this = bless {},shift;
15 89 50       335 $this->parsefrom(shift) if @_;
16 89         163 return $this;
17             }
18              
19             sub stripptrs {
20 151     151 0 392 my($this,$str) = @_;
21 151 50       365 $this->{WasDollar} = 1 if $str =~ s/^\$//;
22 151 100       520 if($str =~ s/^\s*(\w+)\s*$/$1/g) {
23 89         270 $this->{ProtoName} = $str;
24 89         405 return [];
25             }
26             # Now, recall the different C syntaxes. First priority is a pointer:
27 62 50       318 return [["PTR"], @{$this->stripptrs($1)}] if $str =~ /^\s*\*(.*)$/;
  62         136  
28 0 0       0 return $this->stripptrs($1) if $str =~ /^\s*\(.*\)\s*$/; # XXX Should try to see if a funccall.
29 0 0       0 return [["ARR",$2], @{$this->stripptrs($1)}] if $str =~ /^(.*)\[([^]]*)\]\s*$/;
  0         0  
30 0         0 Carp::confess("Invalid C type '$str'");
31             }
32              
33             # XXX Correct to *real* parsing. This is only a subset.
34             sub parsefrom {
35 89     89 0 189 my($this,$str) = @_;
36             # First, take the words in the beginning
37 89         477 $str =~ /^\s*((?:\w+\b\s*)+)([^[].*)$/;
38 89         227 @$this{qw(Base Chain)} = ($1, $this->stripptrs($2));
39             }
40              
41             sub get_decl {
42 146     146 0 274 my($this,$name,$opts) = @_;
43 146         146 for(@{$this->{Chain}}) {
  146         309  
44 118         165 my ($type, $arg) = @$_;
45 118 50       166 if($type eq "PTR") {$name = "*$name"}
  118 0       232  
46             elsif($type eq "ARR") {
47 0 0       0 if($opts->{VarArrays2Ptrs}) {
48 0         0 $name = "*$name";
49             } else {
50 0         0 $name = "($name)[$arg]";
51             }
52 0         0 } else { confess("Invalid decl @$_") }
53             }
54 146 50       255 $name = "*$name" if $opts->{AddIndirect};
55 146         804 return "$this->{Base} $name";
56             }
57              
58             # Useful when parsing argument decls
59 37     37 0 79 sub protoname { return shift->{ProtoName} }
60              
61             sub get_copy {
62 7     7 0 20 my($this,$from,$to) = @_;
63 7 50       10 return "($to) = ($from); /* CType.get_copy */" if !@{$this->{Chain}};
  7         73  
64             # strdup loses portability :(
65             return "($to) = malloc(strlen($from)+1); strcpy($to,$from); /* CType.get_copy */"
66 0 0 0     0 if $this->{Base} =~ /^\s*char\s*$/ and @{$this->{Chain}} == 1;
  0         0  
67 0 0       0 return "($to) = newSVsv($from); /* CType.get_copy */" if $this->{Base} =~ /^\s*SV\s*$/;
68 0         0 my $code = $this->get_malloc($to,$from);
69 0 0       0 return "($to) = ($from); /* CType.get_copy */" if !defined $code; # pointer
70 0         0 my ($deref0,$deref1,$prev,$close) = ($from,$to);
71 0         0 my $no = 0;
72 0         0 for(@{$this->{Chain}}) {
  0         0  
73 0         0 my ($type, $arg) = @$_;
74 0 0       0 if($type eq "PTR") {confess("Cannot copy pointer, must be array");}
  0 0       0  
75             elsif($type eq "ARR") {
76 0         0 $no++;
77 0 0       0 $arg = "$this->{ProtoName}_count" if $this->is_array;
78 0         0 $prev .= "
79             if(!$deref0) {$deref1=0;} /* CType.get_copy */
80             else {int __malloc_ind_$no;
81             for(__malloc_ind_$no = 0;
82             __malloc_ind_$no < $arg;
83             __malloc_ind_$no ++) {";
84 0         0 $deref0 .= "[__malloc_ind_$no]";
85 0         0 $deref1 .= "[__malloc_ind_$no]";
86 0         0 $close .= "}}";
87 0         0 } else { confess("Invalid decl @$_") }
88             }
89 0         0 $code .= "$prev $deref1 = $deref0; $close";
90 0         0 return $code;
91             }
92              
93             sub get_free {
94 7     7 0 13 my($this,$from) = @_;
95 7   33     8 my $single_ptr = @{$this->{Chain}} == 1 && $this->{Chain}[0][0] eq 'PTR';
96 7 50 33     26 return "SvREFCNT_dec($from); /* CType.get_free */\n" if $this->{Base} =~ /^\s*SV\s*$/ and $single_ptr;
97 7 50 33     24 return "free($from); /* CType.get_free */\n" if $this->{Base} =~ /^\s*char\s*$/ and $single_ptr;
98 7 50 33     9 return "" if !@{$this->{Chain}} or $this->{Chain}[0][0] eq 'PTR';
  7         72  
99 0 0       0 croak("Can only free one layer!\n") if @{$this->{Chain}} > 1;
  0         0  
100 0         0 "free($from); /* CType.get_free */\n";
101             }
102              
103             sub need_malloc {
104 0     0 0 0 my($this) = @_;
105 0         0 grep /(ARR|PTR)/, map $_->[0], @{$this->{Chain}};
  0         0  
106             }
107              
108             # returns with the array string - undef if a pointer not needing malloc
109             sub get_malloc {
110 0     0 0 0 my($this,$assignto) = @_;
111 0         0 my $str = "";
112 0         0 for(@{$this->{Chain}}) {
  0         0  
113 0         0 my ($type, $arg) = @$_;
114 0 0       0 if($type eq "PTR") {return}
  0 0       0  
115             elsif($type eq "ARR") {
116 0 0       0 $arg = "$this->{ProtoName}_count" if $this->is_array;
117 0         0 $str .= "$assignto = malloc(sizeof(*$assignto) * $arg); /* CType.get_malloc */\n";
118 0         0 } else { confess("Invalid decl (@$_)") }
119             }
120 0         0 return $str;
121             }
122              
123             sub is_array {
124 131     131 0 193 my ($self) = @_;
125 131         565 @{$self->{Chain}} &&
126 10         59 @{$self->{Chain}[-1]} &&
127             $self->{Chain}[-1][0] eq 'ARR' &&
128 131 50 66     161 !$self->{Chain}[-1][1];
      66        
129             }
130              
131             1;