File Coverage

/usr/local/lib/perl5/site_perl/5.26.1/x86_64-linux/PDL/PP/PdlParObj.pm
Criterion Covered Total %
statement 13 22 59.0
branch 7 88 7.9
condition n/a
subroutine n/a
pod n/a
total 20 110 18.1


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