File Coverage

blib/lib/PDL/PP/PdlParObj.pm
Criterion Covered Total %
statement 137 242 56.6
branch 27 94 28.7
condition 14 78 17.9
subroutine 22 32 68.7
pod 0 26 0.0
total 200 472 42.3


line stmt bran cond sub pod time code
1             ##############################################
2              
3             ##############################################
4              
5             package PDL::PP::PdlParObj;
6              
7 3     3   21 use Carp;
  3         7  
  3         178  
8 3     3   18 use PDL::Types;
  3         5  
  3         414  
9              
10             # check for bad value support
11             #
12 3     3   443 use PDL::Config;
  3         14  
  3         162  
13             my $usenan = $PDL::Config{BADVAL_USENAN} || 0;
14              
15             our %Typemap = ();
16 3     3   20 use PDL::Types ':All';
  3         4  
  3         5204  
17              
18             # build a typemap for our translation purposes
19             # again from info in PDL::Types
20             for my $typ (typesrtkeys) {
21             $Typemap{typefld($typ,'ppforcetype')} = {
22             Ctype => typefld($typ,'ctype'),
23             Cenum => typefld($typ,'sym'),
24             Val => typefld($typ,'numval'),
25             };
26             }
27              
28             # Try to load Text::Balanced
29             my $hasTB = 0;
30 3     3   1490 eval q{
  3         20991  
  3         135  
31             use Text::Balanced;
32             $hasTB = 1;
33             };
34              
35             # split regex $re separated arglist
36             # but ignore bracket-protected bits
37             # (i.e. text that is within matched brackets)
38             # fallback to simple split if we can't find Text::Balanced
39             my $prebrackreg = qr/^([^\(\{\[]*)/;
40             sub splitprotected ($$) {
41 0     0 0 0 my ($re,$txt) = @_;
42 0 0       0 return split $re, $txt unless $hasTB;
43 0 0 0     0 return () if !defined $txt || $txt =~ /^\s*$/;
44 0         0 my ($got,$pre) = (1,'');
45 0         0 my @chunks = ('');
46 0         0 my $ct = 0; # infinite loop protection
47 0   0     0 while ($got && $txt =~ /[({\[]/ && $ct++ < 1000) {
      0        
48             # print "iteration $ct\n";
49 0         0 ($got,$txt,$pre) =
50             Text::Balanced::extract_bracketed($txt,'{}()[]',$prebrackreg);
51 0         0 my @partialargs = split $re, $pre, -1;
52 0 0       0 $chunks[-1] .= shift @partialargs if @partialargs;
53 0         0 push @chunks, @partialargs;
54 0         0 $chunks[-1] .= $got;
55             }
56 0 0       0 confess "possible infinite parse loop, splitting '$txt' "
57             if $ct >= 1000;
58 0         0 my @partialargs = split $re, $txt, -1;
59 0 0       0 $chunks[-1] .= shift @partialargs if @partialargs;
60 0 0       0 push @chunks, @partialargs if @partialargs;
61             # print STDERR "args found: $#chunks\n";
62             # print STDERR "splitprotected $txt on $re: [",join('|',@chunks),"]\n";
63 0         0 return @chunks;
64             }
65              
66             # null != [0]
67             # - in Core.
68              
69             #{package PDL;
70             # sub isnull {
71             # my $this = shift;
72             # return ($this->getndims==1 && $this->getdim(0)==0) ? 1:0 }
73             #}
74              
75             1;
76              
77             #__DATA__
78              
79             # need for $badflag is due to hacked get_xsdatapdecl()
80             # - this should disappear when (if?) things are done sensibly
81             #
82             my $typeregex = join '|', map {typefld($_,'ppforcetype')} typesrtkeys;
83             our $pars_re = qr/^
84             \s*((?:$typeregex)[+]*|)\s* # $1: first option
85             (?:
86             \[([^]]*)\] # $2: The initial [option] part
87             )?\s*
88             (\w+) # $3: The name
89             \(([^)]*)\) # $4: The indices
90             /x;
91             sub new {
92 9     9 0 5146 my($type,$string,$number,$badflag) = @_;
93 9   50     45 $badflag ||= 0;
94 9         30 my $this = bless {Number => $number, BadFlag => $badflag},$type;
95             # Parse the parameter string. Note that the regexes for this match were
96             # originally defined here, but were moved to PDL::PP for FullDoc parsing.
97 9 50       69 $string =~ $pars_re
98             or confess "Invalid pdl def $string (regex $typeregex)\n";
99 9         51 my($opt1,$opt2,$name,$inds) = ($1,$2,$3,$4);
100 9 100       21 map {$_ = '' unless defined($_)} ($opt1,$opt2,$inds); # shut up -w
  27         85  
101 9 50       21 print "PDL: '$opt1', '$opt2', '$name', '$inds'\n"
102             if $::PP_VERBOSE;
103             # Set my internal variables
104 9         36 $this->{Name} = $name;
105 9 50       35 $this->{Flags} = [(split ',',$opt2),($opt1?$opt1:())];
106 9         13 for(@{$this->{Flags}}) {
  9         25  
107             /^io$/ and $this->{FlagW}=1 or
108             /^nc$/ and $this->{FlagNCreat}=1 or
109             /^o$/ and $this->{FlagOut}=1 and $this->{FlagCreat}=1 and $this->{FlagW}=1 or
110             /^oca$/ and $this->{FlagOut}=1 and $this->{FlagCreat}=1 and $this->{FlagW}=1
111             and $this->{FlagCreateAlways}=1 or
112             /^t$/ and $this->{FlagTemp}=1 and $this->{FlagCreat}=1 and $this->{FlagW}=1 or
113             /^phys$/ and $this->{FlagPhys} = 1 or
114 1 0 50     31 /^((?:$typeregex)[+]*)$/ and $this->{Type} = $1 and $this->{FlagTyped} = 1 or
      50        
      33        
      50        
      50        
      50        
      33        
      0        
      0        
      0        
      0        
      33        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
      0        
115             confess("Invalid flag $_ given for $string\n");
116             }
117             # if($this->{FlagPhys}) {
118             # # warn("Warning: physical flag not implemented yet");
119             # }
120 9 50 33     30 if ($this->{FlagTyped} && $this->{Type} =~ s/[+]$// ) {
121 0         0 $this->{FlagTplus} = 1;
122             }
123 9 50       21 if($this->{FlagNCreat}) {
124 0         0 delete $this->{FlagCreat};
125 0         0 delete $this->{FlagCreateAlways};
126             }
127             my @inds = map{
128 9         20 s/\s//g; # Remove spaces
  9         19  
129 9         27 $_;
130             } split ',', $inds;
131 9         25 $this->{RawInds} = [@inds];
132 9         25 return $this;
133             }
134              
135 19     19 0 93 sub name {return (shift)->{Name}}
136              
137             sub add_inds {
138 11     11 0 60 my($this,$dimsobj) = @_;
139 11         29 $this->{IndObjs} = [map {$dimsobj->get_indobj_make($_)}
140 11         19 @{$this->{RawInds}}];
  11         22  
141 11         18 my %indcount;
142             $this->{IndCounts} = [
143             map {
144 11         30 0+($indcount{$_->name}++);
145 11         18 } @{$this->{IndObjs}}
  11         22  
146             ];
147             $this->{IndTotCounts} = [
148             map {
149 11         25 ($indcount{$_->name});
150 11         19 } @{$this->{IndObjs}}
  11         21  
151             ];
152             }
153              
154              
155             # do the dimension checking for perl level threading
156             # assumes that IndObjs have been created
157             sub perldimcheck {
158 9     9 0 68 my ($this,$pdl) = @_;
159             croak ("can't create ".$this->name) if $pdl->isnull &&
160 9 50 66     44 !$this->{FlagCreat};
161 9 100       24 return 1 if $pdl->isnull;
162 8         13 my $rdims = @{$this->{RawInds}};
  8         13  
163 8 50       24 croak ("not enough dimensions for ".$this->name)
164             if ($pdl->threadids)[0] < $rdims;
165 8         22 my @dims = $pdl->dims;
166 8         17 my ($i,$ind) = (0,undef);
167 8         19 for $ind (@{$this->{IndObjs}}) {
  8         26  
168 9         26 $ind->add_value($dims[$i++]);
169             }
170 6         22 return 0; # not creating
171             }
172              
173             sub finalcheck {
174 6     6 0 59 my ($this,$pdl) = @_;
175 6 100       20 return [] if $pdl->isnull;
176 5         8 my @corr = ();
177 5         12 my @dims = $pdl->dims;
178 5         10 my ($i,$ind) = (0,undef);
179 5         7 for $ind (@{$this->{IndObjs}}) {
  5         10  
180 6 100       18 push @corr,[$i-1,$ind->{Value},$dims[$i-1]] if $dims[$i++] != $ind->{Value};
181             }
182 5         13 return [@corr];
183             }
184              
185             # get index sizes for a parameter that has to be created
186             sub getcreatedims {
187 1     1 0 10 my $this = shift;
188             return map
189             { croak "can't create: index size ".$_->name." not initialised"
190 0 0 0     0 if !defined($_->{Value}) || $_->{Value} < 1;
191 1         2 $_->{Value} } @{$this->{IndObjs}};
  0         0  
  1         4  
192             }
193              
194              
195             # find the value for a given PDL type
196             sub typeval {
197 0     0 0 0 my $ctype = shift;
198 0         0 my @match = grep {$Typemap{$_}->{Ctype} =~ /^$ctype$/} keys(%Typemap);
  0         0  
199 0 0       0 if ($#match < 0) {
200 3     3   669 use Data::Dumper;
  3         6830  
  3         7764  
201 0         0 print Dumper \%Typemap;
202 0         0 croak "unknown PDL type '$ctype'" ;
203             }
204 0         0 return $Typemap{$match[0]}->{Val};
205             }
206              
207             # return the PDL type for this pdl
208             sub ctype {
209 4     4 0 7 my ($this,$generic) = @_;
210 4 50       12 return $generic unless $this->{FlagTyped};
211             croak "ctype: unknownn type"
212 0 0       0 unless defined($Typemap{$this->{Type}});
213 0         0 my $type = $Typemap{$this->{Type}}->{Ctype};
214 0 0       0 if ($this->{FlagTplus}) {
215             $type = $Typemap{$this->{Type}}->{Val} >
216             PDL::PP::PdlParObj::typeval($generic) ?
217 0 0       0 $Typemap{$this->{Type}}->{Ctype} : $generic;
218             }
219 0         0 return $type;
220             }
221              
222             # return the enum type for a parobj; it'd better be typed
223             sub cenum {
224 0     0 0 0 my $this = shift;
225             croak "cenum: unknown type [" . $this->{Type} . "]"
226 0 0       0 unless defined($PDL::PP::PdlParObj::Typemap{$this->{Type}});
227 0         0 return $PDL::PP::PdlParObj::Typemap{$this->{Type}}->{Cenum};
228             }
229              
230 5     5 0 8 sub get_nname{ my($this) = @_;
231 5         16 "(\$PRIV(pdls[$this->{Number}]))";
232             }
233              
234 4     4 0 7 sub get_nnflag { my($this) = @_;
235 4         10 "(\$PRIV(vtable->per_pdl_flags[$this->{Number}]))";
236             }
237              
238              
239             # XXX There might be weird backprop-of-changed stuff for [phys].
240             #
241             # Have changed code to assume that, if(!$this->{FlagCreat})
242             # then __creating[] will == 0
243             # -- see make_redodims_thread() in ../PP.pm
244             #
245             sub get_xsnormdimchecks {
246 1     1 0 2 my($this) = @_;
247 1         3 my $pdl = $this->get_nname;
248 1         2 my $iref = $this->{IndObjs};
249 1         3 my $ninds = 0+scalar(@$iref);
250              
251 1         3 my $str = PDL::PP::pp_line_numbers(__LINE__, "");
252 1 50       4 $str .= "if(!__creating[$this->{Number}]) {\n" if $this->{FlagCreat};
253            
254             # Dimensional Promotion when number of dims is less than required:
255             # Previous warning message now commented out,
256             # which means we only need include the code if $ninds > 0
257             #
258 1 50       4 if ( $ninds > 0 ) {
259             $str .= " if(($pdl)->ndims < $ninds) {\n" .
260             join('', map {
261 1         6 my $size = $iref->[$_-1]->get_size();
  1         6  
262 1         18 " if (($pdl)->ndims < $_ && $size <= 1) $size = 1;\n"
263             } (1..$ninds))
264             # XXX why is this here, commented, and not removed? If re-inserted, be sure to use PDL_COMMENT
265             ## ." /* \$CROAK(\"Too few dimensions for argument \'$this->{Name}\'\\n\"); */\n"
266             . " }\n";
267             }
268              
269             # Now, the real check.
270 1         3 my $no = 0;
271 1         3 for( @$iref ) {
272 1         3 my $siz = $_->get_size();
273 1         4 my $dim = "($pdl)->dims[$no]";
274 1         3 my $ndims = "($pdl)->ndims";
275 1         11 $str .= " if($siz == -1 || ($ndims > $no && $siz == 1)) {\n" .
276             " $siz = $dim;\n" .
277             " } else if($ndims > $no && $siz != $dim) {\n" .
278             " if($dim != 1) {\n" .
279 1         3 " \$CROAK(\"Wrong dimensions for parameter '@{[ $this->name ]}'\\n\");\n" .
280             " }\n }\n";
281 1         4 $no++;
282             }
283              
284 1 50       4 $str .= "PDL->make_physical(($pdl));\n" if $this->{FlagPhys};
285              
286 1 50       3 if ( $this->{FlagCreat} ) {
287 0         0 $str .= "} else {\n";
288            
289             # We are creating this pdl.
290 0         0 $str .= " PDL_Indx dims[".($ninds+1)."]; PDL_COMMENT(\"Use ninds+1 to avoid smart (stupid) compilers\")";
291             $str .= join "",
292 0         0 (map {"dims[$_] = ".$iref->[$_]->get_size().";"} 0 .. $#$iref);
  0         0  
293 0 0       0 my $istemp = $this->{FlagTemp} ? 1 : 0;
294 0         0 $str .="\n PDL->thread_create_parameter(&\$PRIV(__pdlthread),$this->{Number},dims,$istemp);\n";
295 0         0 $str .= "}";
296             }
297 1         13 return $str;
298            
299             } # sub: get_xsnormdimchecks()
300              
301             sub get_incname {
302 10     10 0 21 my($this,$ind) = @_;
303 10 50       28 if($this->{IndTotCounts}[$ind] > 1) {
304 0         0 "__inc_".$this->{Name}."_".($this->{IndObjs}[$ind]->name).$this->{IndCounts}[$ind];
305             } else {
306 10         37 "__inc_".$this->{Name}."_".($this->{IndObjs}[$ind]->name);
307             }
308             }
309              
310             sub get_incdecls {
311 1     1 0 3 my($this) = @_;
312 1 50       1 if(scalar(@{$this->{IndObjs}}) == 0) {return "";}
  1         4  
  0         0  
313             (join '',map {
314 1         3 "PDL_Indx ".($this->get_incname($_)).";";
315 1         3 } (0..$#{$this->{IndObjs}}) ) . ";"
  1         3  
316             }
317              
318             sub get_incregisters {
319 3     3 0 6 my($this) = @_;
320 3 50       6 if(scalar(@{$this->{IndObjs}}) == 0) {return "";}
  3         13  
  0         0  
321             (join '',map {
322 3         11 "register PDL_Indx ".($this->get_incname($_))." = \$PRIV(".
323             ($this->get_incname($_)).");\n";
324 3         9 } (0..$#{$this->{IndObjs}}) )
  3         8  
325             }
326              
327             sub get_incdecl_copy {
328 1     1 0 3 my($this,$fromsub,$tosub) = @_;
329             PDL::PP::pp_line_numbers(__LINE__, join '',map {
330 1         2 my $iname = $this->get_incname($_);
331 1         2 &$fromsub($iname)."=".&$tosub($iname).";";
332 1         4 } (0..$#{$this->{IndObjs}}))
  1         3  
333             }
334              
335             sub get_incsets {
336 1     1 0 2 my($this,$str) = @_;
337 1         3 my $no=0;
338             PDL::PP::pp_line_numbers(__LINE__, join '',map {
339             "if($str->ndims <= $_ || $str->dims[$_] <= 1)
340             \$PRIV(".($this->get_incname($_)).") = 0; else
341             \$PRIV(".($this->get_incname($_)).
342             ") = ".($this->{FlagPhys}?
343 1 50       5 "$str->dimincs[$_];" :
344             "PDL_REPRINC($str,$_);");
345 1         2 } (0..$#{$this->{IndObjs}}) )
  1         3  
346             }
347              
348             # Print an access part.
349             sub do_access {
350 0     0 0 0 my($this,$inds,$context) = @_;
351 0         0 my $pdl = $this->{Name};
352             # Parse substitutions into hash
353             my %subst = map
354 0 0       0 {/^\s*(\w+)\s*=>\s*(\S*)\s*$/ or confess "Invalid subst $_\n"; ($1,$2)}
  0         0  
  0         0  
355             splitprotected ',',$inds;
356             # Generate the text
357 0         0 my $text;
358 0         0 $text = "(${pdl}_datap)"."[";
359             $text .= join '+','0',map {
360 0         0 $this->do_indterm($pdl,$_,\%subst,$context);
361 0         0 } (0..$#{$this->{IndObjs}});
  0         0  
362 0         0 $text .= "]";
363             # If not all substitutions made, the user probably made a spelling
364             # error. Barf.
365 0 0       0 if(scalar(keys %subst) != 0) {
366 0         0 confess("Substitutions left: ".(join ',',keys %subst)."\n");
367             }
368 0         0 return "$text PDL_COMMENT(\"ACCESS($access)\") ";
369             }
370              
371             sub has_dim {
372 0     0 0 0 my($this,$ind) = @_;
373 0         0 my $h = 0;
374 0         0 for(@{$this->{IndObjs}}) {
  0         0  
375 0 0       0 $h++ if $_->name eq $ind;
376             }
377 0         0 return $h;
378             }
379              
380             sub do_resize {
381 0     0 0 0 my($this,$ind,$size) = @_;
382 0         0 my @c;my $index = 0;
  0         0  
383 0         0 for(@{$this->{IndObjs}}) {
  0         0  
384 0 0       0 push @c,$index if $_->name eq $ind; $index ++;
  0         0  
385             }
386 0         0 my $pdl = $this->get_nname;
387 0         0 return PDL::PP::pp_line_numbers(__LINE__, (join '',map {"$pdl->dims[$_] = $size;\n"} @c).
  0         0  
388             "PDL->resize_defaultincs($pdl);PDL->allocdata($pdl);".
389             $this->get_xsdatapdecl(undef,1));
390             }
391              
392             sub do_pdlaccess {
393 0     0 0 0 my($this) = @_;
394 0         0 PDL::PP::pp_line_numbers(__LINE__, '$PRIV(pdls['.$this->{Number}.'])');
395              
396             }
397              
398             sub do_pointeraccess {
399 0     0 0 0 my($this) = @_;
400 0         0 return $this->{Name}."_datap";
401             }
402              
403             sub do_physpointeraccess {
404 0     0 0 0 my($this) = @_;
405 0         0 return $this->{Name}."_physdatap";
406             }
407              
408 0     0 0 0 sub do_indterm { my($this,$pdl,$ind,$subst,$context) = @_;
409             # Get informed
410 0         0 my $indname = $this->{IndObjs}[$ind]->name;
411 0         0 my $indno = $this->{IndCounts}[$ind];
412 0         0 my $indtot = $this->{IndTotCounts}[$ind];
413             # See if substitutions
414 0 0       0 my $substname = ($indtot>1 ? $indname.$indno : $indname);
415 0 0       0 my $incname = $indname.($indtot>1 ? $indno : "");
416 0         0 my $index;
417 0 0       0 if(defined $subst->{$substname}) {$index = delete $subst->{$substname};}
  0         0  
418             else {
419             # No => get the one from the nearest context.
420 0         0 for(reverse @$context) {
421 0 0       0 if($_->[0] eq $indname) {$index = $_->[1]; last;}
  0         0  
  0         0  
422             }
423             }
424 0 0       0 if(!defined $index) {confess "Access Index not found: $pdl, $ind, $indname
425 0         0 On stack:".(join ' ',map {"($_->[0],$_->[1])"} @$context)."\n" ;}
  0         0  
426             # return "\$PRIV(".($this->get_incname($ind))."*". $index .")";
427             # Now we have them in register variables -> no PRIV
428             return "(".($this->get_incname($ind))."*".
429 0         0 "PP_INDTERM(".$this->{IndObjs}[$ind]->get_size().", $index))";
430             }
431              
432             # XXX hacked to create a variable containing the bad value for
433             # this piddle.
434             # This is a HACK (Doug Burke 07/08/00)
435             # XXX
436             #
437             sub get_xsdatapdecl {
438 4     4 0 9 my($this,$genlooptype,$asgnonly) = @_;
439 4         5 my $type;
440 4         10 my $pdl = $this->get_nname;
441 4         9 my $flag = $this->get_nnflag;
442 4         9 my $name = $this->{Name};
443 4 50       13 $type = $this->ctype($genlooptype) if defined $genlooptype;
444 4 50       13 my $declini = ($asgnonly ? "" : "\t$type *");
445 4 50       11 my $cast = ($type ? "($type *)" : "");
446             # ThreadLoop does this for us.
447             # return "$declini ${name}_datap = ($cast((${_})->data)) + (${_})->offs;\n";
448            
449 4         23 my $str = PDL::PP::pp_line_numbers(__LINE__, "$declini ${name}_datap = ($cast(PDL_REPRP_TRANS($pdl,$flag)));\n" .
450             "$declini ${name}_physdatap = ($cast($pdl->data));\n");
451              
452             # assuming we always need this
453             # - may not be true - eg if $asgnonly ??
454             # - not needed for floating point types when using NaN as bad values
455 4 0 33     12 if ( $this->{BadFlag} and $type and
      0        
      33        
456             ( $usenan == 0 or $type !~ /^PDL_(Float|Double)$/ ) ) {
457 0         0 my $cname = $type; $cname =~ s/^PDL_//;
  0         0  
458 0         0 $str .= "\t$type ${name}_badval = 0;\n";
459 0         0 $str .= "\tPDL_Anyval ${name}_anyval_badval = PDL->get_pdl_badvalue($pdl);\n";
460 0         0 $str .= "\tANYVAL_TO_CTYPE(${name}_badval, ${type}, ${name}_anyval_badval);\n";
461             }
462              
463 4         17 return "$str\n";
464             }
465              
466             1;