File Coverage

blib/lib/PDL/PP/PdlParObj.pm
Criterion Covered Total %
statement 107 122 87.7
branch 38 60 63.3
condition 11 20 55.0
subroutine 19 21 90.4
pod 0 17 0.0
total 175 240 72.9


line stmt bran cond sub pod time code
1             package # hide from PAUSE/MetaCPAN
2             PDL::PP::PdlParObj;
3              
4 4     4   25 use strict;
  4         8  
  4         150  
5 4     4   18 use warnings;
  4         8  
  4         235  
6 4     4   19 use Carp;
  4         8  
  4         293  
7 4     4   21 use PDL::Types ':All';
  4         5  
  4         16530  
8              
9             our %INVALID_PAR = map +($_=>1), qw(
10             I
11             );
12              
13             my $typeregex = join '|', map $_->ppforcetype, types;
14             my $complex_regex = join '|', qw(real complex !real !complex);
15             our $sqbr_re = qr/\[([^]]*)\]/x;
16             our $pars_re = qr/^
17             \s*(?:($complex_regex|$typeregex)\b([+]*)|)\s* # $1,2: first option then plus
18             (?:$sqbr_re)?\s* # $3: The initial [option] part
19             (\w+) # $4: The name
20             \((.*)\) # $5: The indices
21             \s*\Z # that's all
22             /x;
23             my %flag2info = (
24             io => [[qw(FlagW)]],
25             o => [[qw(FlagOut FlagCreat FlagW)]],
26             oca => [[qw(FlagOut FlagCreat FlagW FlagCreateAlways)]],
27             t => [[qw(FlagTemp FlagCreat FlagW)]],
28             phys => [[qw(FlagPhys)]],
29             real => [[qw(FlagTypeOverride FlagReal)]],
30             complex => [[qw(FlagTypeOverride FlagComplex)]],
31             '!real' => [[qw(FlagTypeOverride FlagNotReal)]],
32             '!complex' => [[qw(FlagTypeOverride FlagNotComplex)]],
33             (map +($_->ppforcetype => [[qw(FlagTypeOverride FlagTyped)], 'Type']), types),
34             );
35             my %flag2c = qw(
36             FlagReal PDL_PARAM_ISREAL
37             FlagComplex PDL_PARAM_ISCOMPLEX
38             FlagNotReal PDL_PARAM_ISNOTREAL
39             FlagNotComplex PDL_PARAM_ISNOTCOMPLEX
40             FlagTyped PDL_PARAM_ISTYPED
41             FlagTplus PDL_PARAM_ISTPLUS
42             FlagCreat PDL_PARAM_ISCREAT
43             FlagCreateAlways PDL_PARAM_ISCREATEALWAYS
44             FlagOut PDL_PARAM_ISOUT
45             FlagTemp PDL_PARAM_ISTEMP
46             FlagW PDL_PARAM_ISWRITE
47             FlagPhys PDL_PARAM_ISPHYS
48             FlagIgnore PDL_PARAM_ISIGNORE
49             );
50             my $calc_re = qr{
51             (\w+)\s*=\s* # paren group 1 (dim name) - from perlre/PARNO
52             CALC
53             ( # paren group 2 (parens)
54             \(
55             ( # paren group 3 (contents of parens)
56             (?:
57             (?> [^()]+ ) # Non-parens without backtracking
58             |
59             (?2) # Recurse to start of paren group 2
60             )*
61             )
62             \)
63             )
64             }xo;
65             sub new {
66 110     110 0 271 my ($type,$string,$opname) = @_;
67 110 50       1003 $string =~ $pars_re or croak "pp_def($opname): Invalid pdl def $string (regex $pars_re)\n";
68 110         465 my $this = bless {Number => "PDL_UNDEF_NUMBER", OpName=>$opname},$type;
69 110   100     1372 my($opt1,$opt_plus,$sqbr_opt,$name,$inds) = map $_ // '', $1,$2,$3,$4,$5;
70 110 50       383 print "PDL: '$opt1$opt_plus', '$sqbr_opt', '$name', '$inds'\n"
71             if $::PP_VERBOSE;
72 110 100       451 croak "pp_def($opname): Invalid Pars name: $name" if $INVALID_PAR{$name};
73             # Set my internal variables
74 109         266 $this->{Name} = $name;
75 109 100       393 $this->{Flags} = [(split ',',$sqbr_opt),($opt1?$opt1:())];
76 109         172 for(@{$this->{Flags}}) {
  109         262  
77             croak("pp_def($opname): Invalid flag $_ given for $string\n")
78 49 50       86 unless my ($set, $store) = @{ $flag2info{$_} || [] };
  49 50       308  
79 49 100       130 $this->{$store} = $_ if $store;
80 49         376 $this->{$_} = 1 for @$set;
81             }
82 109 100 100     934 $this->{FlagTplus} = 1 if $this->{FlagTyped} && $opt_plus;
83 109   66     345 $this->{Type} &&= PDL::Type->new($this->{Type});
84 109         280 $this->{Ind2Calc} = \my %ind2calc;
85 109         512 $ind2calc{$1} = $3 while $inds =~ s#$calc_re#$1#;
86             $this->{RawInds} = [map{
87 109         320 s/\s//g; # Remove spaces
  102         223  
88 102         330 $_;
89             } split ',', $inds];
90 109         386 return $this;
91             }
92              
93             sub cflags {
94 12     12 0 33 my ($this) = @_;
95 12         241 map $flag2c{$_}, grep $this->{$_}, sort keys %flag2c;
96             }
97              
98 363     363 0 1582 sub name {$_[0]{Name}}
99              
100             sub add_inds {
101 139     139 0 1800 my($this,$dimsobj) = @_;
102 139         288 $this->{IndObjs} = [my @objs = map $dimsobj->get_indobj_make($_, $this->{Ind2Calc}{$_}), @{$this->{RawInds}}];
  139         609  
103 139         242 my %indcount;
104 139         374 $this->{IndCounts} = [ map 0+($indcount{$_->name}++), @objs ];
105 139         361 $this->{IndTotCounts} = [ map $indcount{$_->name}, @objs ];
106             }
107              
108              
109             # do the dimension checking for perl level broadcasting
110             # assumes that IndObjs have been created
111             sub perldimcheck {
112 30     30 0 60 my ($this,$pdl) = @_;
113             croak ("can't create ".$this->name) if $pdl->isnull &&
114 30 50 66     165 !$this->{FlagCreat};
115 30 100       209 return 1 if $pdl->isnull;
116 22         29 my $rdims = @{$this->{RawInds}};
  22         43  
117 22 50       185 croak ("not enough dimensions for ".$this->name)
118             if ($pdl->broadcastids)[0] < $rdims;
119 22         84 my @dims = $pdl->dims;
120 22         46 my ($i,$ind) = (0,undef);
121 22         27 for $ind (@{$this->{IndObjs}}) {
  22         56  
122 18         58 $ind->add_value($dims[$i++]);
123             }
124 20         82 return 0; # not creating
125             }
126              
127             sub finalcheck {
128 27     27 0 55 my ($this,$pdl) = @_;
129 27 100       117 return [] if $pdl->isnull;
130 19         52 my @corr = ();
131 19         121 my @dims = $pdl->dims;
132 19         37 my $i = 0;
133 19         28 for my $ind (@{$this->{IndObjs}}) {
  19         40  
134 15 100       54 push @corr,[$i-1,$ind->{Value},$dims[$i-1]] if $dims[$i++] != $ind->{Value};
135             }
136 19         79 return \@corr;
137             }
138              
139             # get index sizes for a parameter that has to be created
140             sub getcreatedims {
141 8     8 0 17 my $this = shift;
142             return map
143             { croak "pp_def($this->{OpName}): can't create: index size ".$_->name." not initialised"
144 1 50 33     10 if !defined($_->{Value}) || $_->{Value} < 1;
145 8         13 $_->{Value} } @{$this->{IndObjs}};
  1         6  
  8         34  
146             }
147              
148             sub adjusted_type {
149 48     48 0 62 my ($this, $generic) = @_;
150 48 50       59 confess "adjusted_type given undefined generic type\n" if !defined $generic;
151 48 50 33     96 return $generic->realversion if $this->{FlagReal} || $this->{FlagNotComplex};
152 48 50       59 return $generic->complexversion if $this->{FlagComplex};
153 48 50       59 return $generic unless $this->{FlagTyped};
154             return $this->{Type}->numval > $generic->numval
155             ? $this->{Type} : $generic
156 48 0       56 if $this->{FlagTplus};
    50          
157 48         71 $this->{Type};
158             }
159              
160 16     16 0 23 sub get_nname{ my($this) = @_;
161 16         36 "(\$PRIV(pdls)[$this->{Number}])";
162             }
163              
164             sub get_substname {
165 16     16 0 29 my($this,$ind) = @_;
166 16 50       59 $this->{IndObjs}[$ind]->name.($this->{IndTotCounts}[$ind] > 1 ? $this->{IndCounts}[$ind] : '');
167             }
168              
169             sub get_incname {
170 32     32 0 67 my($this,$ind,$for_local) = @_;
171 32 100       117 return "inc_sizes[PDL_INC_ID(__privtrans->vtable,$this->{Number},$ind)]" if !$for_local;
172 16         51 "__inc_$this->{Name}_".$this->get_substname($ind);
173             }
174              
175             sub get_incregisters {
176 16     16 0 30 my($this) = @_;
177 16 100       15 return '' if scalar(@{$this->{IndObjs}}) == 0;
  16         67  
178             join '', map {
179 16         23 my $x = $_;
180 16         44 my ($name, $for_local) = map $this->get_incname($x, $_), 0, 1;
181 16         183 "register PDL_Indx $for_local = __privtrans->$name; (void)$for_local;";
182 14         24 } 0..$#{$this->{IndObjs}};
  14         35  
183             }
184              
185             # Print an access part.
186             sub do_access {
187 2     2 0 8 my($this,$inds,$context) = @_;
188 2         6 my $pdl = $this->{Name};
189             my %subst = map {
190 2 50       11 if (!/^\s*(\w+)\s*=>\s*(\S*)\s*$/) {
  2         12  
191 2         7 my $msg = "Invalid subst '$_' in \$$pdl($inds):";
192 2 100       8 $msg .= " no '=>' seen" if !/=>/;
193 2 50       10 $msg .= " invalid dim name '$1'" if /^\s*([^\w]*?)\s*=>/;
194 2 100       9 $msg .= " (no spaces in => value)" if /=>\s*\S\s*\S/;
195 2         657 croak "pp_def($this->{OpName}): $msg\n";
196             }
197 0         0 ($1,$2)
198             } PDL::PP::Rule::Substitute::split_cpp($inds);
199             my $text = "(${pdl}_datap)[" .
200 0         0 join('+','0', map $this->do_indterm($pdl,$_,\%subst,$context), 0..$#{$this->{IndObjs}})
  0         0  
201             . "]";
202             # If not all substitutions made, the user probably made a spelling error
203 0 0       0 croak "pp_def($this->{OpName}): Substitutions left for \$$pdl($inds): ".(join ',',sort keys %subst)."\n"
204             if keys(%subst) != 0;
205 0         0 $text;
206             }
207              
208             sub do_pdlaccess {
209 0     0 0 0 my($this) = @_;
210 0         0 '$PRIV(pdls)['.$this->{Number}.']';
211             }
212              
213             sub do_pointeraccess {
214 64     64 0 91 my($this) = @_;
215 64         299 return $this->{Name}."_datap";
216             }
217              
218 0     0 0 0 sub do_indterm { my($this,$pdl,$ind,$subst,$context) = @_;
219 0         0 my $substname = $this->get_substname($ind);
220             # See if substitutions
221 0   0     0 my $index = delete($subst->{$substname}) //
222             # No => get the one from the nearest context.
223             (grep $_ eq $substname, map $_->[1], reverse @$context)[0];
224 0 0       0 if (!defined $index) {
225             croak "pp_def($this->{OpName}): no value given for ndarray '$pdl' index '$substname'
226 0         0 You supplied (@{[sort keys %$subst]})
227 0         0 On stack: ".(join ' ',map {"($_->[0],$_->[1])"} @$context)."\n"
  0         0  
228             }
229 0         0 "(".($this->get_incname($ind,1))."*($index))";
230             }
231              
232             sub get_xsdatapdecl {
233 16     16 0 39 my ($this,$ctype,$nulldatacheck,$ppsym,$badflag) = @_;
234 16         44 my $pdl = $this->get_nname;
235 16         28 my $name = $this->{Name};
236 16 50       38 my $macro = "PDL_DECLARE_PARAMETER".($badflag ? "_BADVAL" : "");
237 16         73 "$macro($ctype, $name, $pdl, $nulldatacheck, $ppsym)";
238             }
239              
240             1;