File Coverage

blib/lib/PDL/Types.pm
Criterion Covered Total %
statement 52 72 72.2
branch 16 32 50.0
condition 3 6 50.0
subroutine 25 32 78.1
pod 5 9 55.5
total 101 151 66.8


line stmt bran cond sub pod time code
1             package PDL::Types;
2 74     74   157494 use strict;
  74         142  
  74         2773  
3 74     74   376 use warnings;
  74         153  
  74         4239  
4             require Exporter;
5 74     74   471 use Carp;
  74         241  
  74         6104  
6 74     74   475 use Config;
  74         172  
  74         134228  
7              
8             our @ISA = qw( Exporter );
9              
10             my @TYPE_CHECK = qw/
11             realctype ppforcetype usenan real unsigned integer identifier ctype
12             /;
13             my @TYPE_VERBATIM = (@TYPE_CHECK, qw(
14             ioname convertfunc defbval shortctype ppsym numval sym floatsuffix
15             ));
16             my @TYPE_MODIFIED = qw(realversion complexversion isnan isfinite);
17              
18             sub packtypeof_PDL_Indx {
19 74 50   74 0 13493 return 'q*' if $Config{ptrsize} == 8;
20 0 0       0 return 'l*' if $Config{ptrsize} == 4;
21 0         0 die "PDL::Types: packtype for ptrsize==$Config{ptrsize} not handled\n";
22             }
23              
24             # Data types *must* be listed in order of complexity!!
25             # this is critical for type conversions!!!
26             #
27             my @HASHES = (
28             {
29             identifier => 'SB',
30             onecharident => 'A', # only needed if different from identifier
31             ctype => 'PDL_SByte',# to be defined in pdl.h
32             realctype => 'signed char', # CORE21 change to int8_t
33             ppforcetype => 'sbyte', # for some types different from ctype
34             usenan => 0, # do we need NaN handling for this type?
35             packtype => 'c*', # the perl pack type
36             defbval => 'SCHAR_MIN',
37             real=>1,
38             integer=>1,
39             unsigned=>0,
40             },
41             {
42             identifier => 'B',
43             ctype => 'PDL_Byte',# to be defined in pdl.h
44             realctype => 'unsigned char',
45             ppforcetype => 'byte', # for some types different from ctype
46             usenan => 0, # do we need NaN handling for this type?
47             packtype => 'C*', # the perl pack type
48             defbval => 'UCHAR_MAX',
49             real=>1,
50             integer=>1,
51             unsigned=>1,
52             },
53             {
54             identifier => 'S',
55             ctype => 'PDL_Short',
56             realctype => 'short',
57             ppforcetype => 'short',
58             usenan => 0,
59             packtype => 's*',
60             defbval => 'SHRT_MIN',
61             real=>1,
62             integer=>1,
63             unsigned=>0,
64             },
65             {
66             identifier => 'US',
67             onecharident => 'U', # only needed if different from identifier
68             ctype => 'PDL_Ushort',
69             realctype => 'unsigned short',
70             ppforcetype => 'ushort',
71             usenan => 0,
72             packtype => 'S*',
73             defbval => 'USHRT_MAX',
74             real=>1,
75             integer=>1,
76             unsigned=>1,
77             },
78             {
79             identifier => 'L',
80             ctype => 'PDL_Long',
81             realctype => 'int32_t',
82             ppforcetype => 'int',
83             usenan => 0,
84             packtype => 'l*',
85             defbval => 'INT32_MIN',
86             real=>1,
87             integer=>1,
88             unsigned=>0,
89             },
90             {
91             identifier => 'UL',
92             onecharident => 'K', # only needed if different from identifier
93             ctype => 'PDL_ULong',
94             realctype => 'uint32_t',
95             ppforcetype => 'uint',
96             usenan => 0,
97             packtype => 'L*',
98             defbval => 'UINT32_MAX',
99             real=>1,
100             integer=>1,
101             unsigned=>1,
102             },
103             {
104             identifier => 'IND',
105             onecharident => 'N', # only needed if different from identifier
106             ctype => 'PDL_Indx',
107             realctype => 'ptrdiff_t',
108             ppforcetype => 'indx',
109             usenan => 0,
110             packtype => &packtypeof_PDL_Indx,
111             defbval => 'PTRDIFF_MIN',
112             real=>1,
113             integer=>1,
114             unsigned=>0,
115             },
116             # note that the I/O routines have *not* been updated to be aware of
117             # such a type yet
118             { # this one before LL so last integer is signed, to avoid default-type (last in list) changing to unsigned
119             identifier => 'ULL',
120             onecharident => 'P', # only needed if different from identifier
121             ctype => 'PDL_ULongLong',
122             realctype => 'uint64_t',
123             ppforcetype => 'ulonglong',
124             usenan => 0,
125             packtype => 'Q*',
126             defbval => 'UINT64_MAX',
127             real=>1,
128             integer=>1,
129             unsigned=>1,
130             },
131             {
132             identifier => 'LL',
133             onecharident => 'Q', # only needed if different from identifier
134             ctype => 'PDL_LongLong',
135             realctype => 'int64_t',
136             ppforcetype => 'longlong',
137             usenan => 0,
138             packtype => 'q*',
139             defbval => 'INT64_MIN',
140             real=>1,
141             integer=>1,
142             unsigned=>0,
143             },
144             # IMPORTANT:
145             # PDL_F *must* be the first non-integer type in this list
146             # as there are many places in the code (.c/.xs/.pm/.pd)
147             # with tests like this:
148             # if (ndarraytype < PDL_F) { ... }
149             {
150             identifier => 'F',
151             ctype => 'PDL_Float',
152             realctype => 'float',
153             ppforcetype => 'float',
154             usenan => 1,
155             packtype => 'f*',
156             defbval => '-FLT_MAX',
157             real=>1,
158             complexversion=> 'G',
159             integer=>0,
160             unsigned=>0,
161             isnan=>'isnan(%1$s)',
162             isfinite=>'isfinite(%1$s)',
163             floatsuffix=>'f',
164             },
165             {
166             identifier => 'D',
167             ctype => 'PDL_Double',
168             realctype => 'double',
169             ppforcetype => 'double',
170             usenan => 1,
171             packtype => 'd*',
172             defbval => '-DBL_MAX',
173             real=>1,
174             complexversion=> 'C',
175             integer=>0,
176             unsigned=>0,
177             isnan=>'isnan(%1$s)',
178             isfinite=>'isfinite(%1$s)',
179             floatsuffix=>'',
180             },
181             {
182             identifier => 'LD',
183             onecharident => 'E', # only needed if different from identifier
184             ctype => 'PDL_LDouble',
185             realctype => 'long double',
186             ppforcetype => 'ldouble',
187             usenan => 1,
188             packtype => 'D*',
189             defbval => '-LDBL_MAX',
190             real=>1,
191             complexversion=> 'CLD',
192             integer=>0,
193             unsigned=>0,
194             isnan=>'isnan(%1$s)',
195             isfinite=>'isfinite(%1$s)',
196             floatsuffix=>'l',
197             },
198             # the complex types need to be in the same order as their real
199             # counterparts, because the "real" ppforcetype relies on a fixed interval
200             # between each real and complex version
201             # they also need to occur at the end of the types, as a < PDL_CF
202             # comparison is done at C level to see if a type is real, analogous to
203             # the < PDL_F above
204             {
205             identifier => 'CF',
206             onecharident => 'G', # only needed if different from identifier
207             ctype => 'PDL_CFloat',
208             realctype => 'complex float',
209             ppforcetype => 'cfloat',
210             usenan => 1,
211             packtype => '(ff)*',
212             defbval => '(-FLT_MAX - I*FLT_MAX)',
213             real=>0,
214             realversion=>'F',
215             integer=>0,
216             unsigned=>0,
217             isnan=>'(isnan(crealf(%1$s)) || isnan(cimagf(%1$s)))',
218             isfinite=>'(isfinite(crealf(%1$s)) && isfinite(cimagf(%1$s)))',
219             floatsuffix=>'f',
220             },
221             {
222             identifier => 'CD',
223             onecharident => 'C', # only needed if different from identifier
224             ctype => 'PDL_CDouble',
225             realctype => 'complex double',
226             ppforcetype => 'cdouble',
227             usenan => 1,
228             packtype => '(dd)*',
229             defbval => '(-DBL_MAX - I*DBL_MAX)',
230             real=>0,
231             realversion=>'D',
232             integer=>0,
233             unsigned=>0,
234             isnan=>'(isnan(creal(%1$s)) || isnan(cimag(%1$s)))',
235             isfinite=>'(isfinite(creal(%1$s)) && isfinite(cimag(%1$s)))',
236             floatsuffix=>'',
237             },
238             {
239             identifier => 'CLD',
240             onecharident => 'H', # only needed if different from identifier
241             ctype => 'PDL_CLDouble',
242             realctype => 'complex long double',
243             ppforcetype => 'cldouble',
244             usenan => 1,
245             packtype => '(DD)*',
246             defbval => '(-LDBL_MAX - I*LDBL_MAX)',
247             real=>0,
248             realversion=>'LD',
249             integer=>0,
250             unsigned=>0,
251             isnan=>'(isnan(creall(%1$s)) || isnan(cimagl(%1$s)))',
252             isfinite=>'(isfinite(creall(%1$s)) && isfinite(cimagl(%1$s)))',
253             floatsuffix=>'l',
254             },
255             );
256              
257             my $i = 0;
258             my @check_keys = (@TYPE_CHECK, qw(
259             identifier packtype defbval
260             ));
261             for my $type (@HASHES) {
262             die "type is not a HASH ref but ".ref($type) unless ref $type eq 'HASH';
263             my @missing_keys = grep !exists $type->{$_}, @check_keys;
264             die "type hash missing (@missing_keys)" if @missing_keys;
265             $type->{shortctype} = $type->{ctype} =~ s/PDL_//r;
266             $type->{ioname} = $type->{convertfunc} = lc $type->{shortctype};
267             $type->{ppsym} = $type->{onecharident} || $type->{identifier};
268             $type->{numval} = $i++;
269             $type->{sym} = "PDL_$type->{identifier}";
270             $type->{realversion} ||= $type->{ppsym};
271             $type->{complexversion} ||= !$type->{real} ? $type->{ppsym} : 'G';
272             $type->{floatsuffix} //= 'INVALID';
273              
274             }
275              
276             our @EXPORT = (qw(@pack %typehash), my @typevars = map "\$$_->{sym}", @HASHES);
277             our @EXPORT_OK = (@EXPORT,
278             qw/types typesrtkeys mapfld typefld
279             ppdefs ppdefs_complex ppdefs_all
280             /
281             );
282             our %EXPORT_TAGS = (
283             All=>\@EXPORT_OK,
284             );
285              
286             eval "our ( @{[ join ',', @typevars ]} ) = (0..$#HASHES)";
287             die if $@;
288             # Corresponding pack types
289             our @pack= map $_->{packtype}, @HASHES;
290             our @names= map $_->{sym}, @HASHES;
291              
292             our %typehash = map {
293             my $type = $_;
294             $type->{sym} => +{
295             (map +($_ => $type->{$_}), @TYPE_VERBATIM, @TYPE_MODIFIED),
296             };
297             } @HASHES;
298              
299             # Cross-reference by common names
300             our %typenames;
301             for my $h (@HASHES) {
302             my $n = $h->{numval};
303             $typenames{$_} = $n for $n, @$h{qw(sym ioname ctype ppforcetype ppsym identifier)};
304             }
305              
306             =head1 NAME
307              
308             PDL::Types - define fundamental PDL Datatypes
309              
310             =head1 SYNOPSIS
311              
312             use PDL::Types;
313              
314             $pdl = ushort( 2.0, 3.0 );
315             print "The actual c type used to store ushort's is '" .
316             $pdl->type->realctype() . "'\n";
317             The actual c type used to store ushort's is 'unsigned short'
318              
319             =head1 DESCRIPTION
320              
321             Internal module - holds all the PDL Type info. The type info can be
322             accessed easily using the C object returned by
323             the L method as shown in the synopsis.
324              
325             Skip to the end of this document to find out how to change
326             the set of types supported by PDL.
327              
328             =head1 FUNCTIONS
329              
330             A number of functions are available for module writers
331             to get/process type information. These are used in various
332             places (e.g. C, C) to generate the
333             appropriate type loops, etc.
334              
335             =head2 typesrtkeys
336              
337             =for ref
338              
339             Returns an array of keys of typehash sorted in order of type complexity
340              
341             =for example
342              
343             pdl> @typelist = PDL::Types::typesrtkeys;
344             pdl> print @typelist;
345             PDL_SB PDL_B PDL_S PDL_US PDL_L PDL_UL PDL_IND PDL_ULL PDL_LL PDL_F PDL_D PDL_LD PDL_CF PDL_CD PDL_CLD
346             =cut
347              
348 0     0 1 0 sub typesrtkeys { @names }
349              
350             =head2 ppdefs
351              
352             =for ref
353              
354             Returns an array of pp symbols for all real types. This informs the
355             default C for C functions, making support for
356             complex types require an "opt-in".
357              
358             =for example
359              
360             pdl> print PDL::Types::ppdefs
361             A B S U L K N P Q F D E
362              
363             =cut
364              
365             my @PPDEFS = map $_->{ppsym}, grep $_->{real}, @HASHES;
366 36     36 1 89180 sub ppdefs { @PPDEFS }
367              
368             =head2 ppdefs_complex
369              
370             =for ref
371              
372             Returns an array of pp symbols for all complex types.
373              
374             =for example
375              
376             pdl> print PDL::Types::ppdefs_complex
377             G C H
378              
379             =cut
380              
381             my @PPDEFS_CPLX = map $_->{ppsym}, grep !$_->{real}, @HASHES;
382 1     1 1 10 sub ppdefs_complex { @PPDEFS_CPLX }
383              
384             =head2 ppdefs_all
385              
386             =for ref
387              
388             Returns an array of pp symbols for all types including complex.
389              
390             =for example
391              
392             pdl> print PDL::Types::ppdefs_all
393             A B S U L K N P Q F D E G C H
394              
395             =cut
396              
397             my @PPDEFS_ALL = map $_->{ppsym}, @HASHES;
398 7     7 1 88 sub ppdefs_all { @PPDEFS_ALL }
399              
400             sub typefld {
401 0     0 0 0 my ($type,$fld) = @_;
402 0 0       0 croak "unknown type $type" unless exists $typehash{$type};
403             croak "unknown field $fld in type $type"
404 0 0       0 unless exists $typehash{$type}->{$fld};
405 0         0 return $typehash{$type}->{$fld};
406             }
407              
408             sub mapfld {
409 0     0 0 0 my ($type,$src,$trg) = @_;
410 0         0 my @keys = grep {$typehash{$_}->{$src} eq $type} typesrtkeys;
  0         0  
411 0 0       0 return @keys > 0 ? $typehash{$keys[0]}->{$trg} : undef;
412             }
413              
414             =head2 typesynonyms
415              
416             =for ref
417              
418             return type related synonym definitions to be included in pdl.h .
419             This routine must be updated to include new types as required.
420             Mostly the automatic updating should take care of the vital
421             things.
422              
423             =cut
424              
425             sub typesynonyms {
426             my $add = join "\n",
427 0         0 map {"#define PDL_".typefld($_,'ppsym')." ".typefld($_,'sym')}
428 0     0 1 0 grep {"PDL_".typefld($_,'ppsym') ne typefld($_,'sym')} typesrtkeys;
  0         0  
429 0         0 return "$add\n";
430             }
431              
432             =head1 PDL TYPES OVERVIEW
433              
434             As of 2.065, PDL supports these types:
435              
436             =over
437              
438             =item SByte
439              
440             Signed 8-bit value.
441              
442             =item Byte
443              
444             Unsigned 8-bit value.
445              
446             =item Short
447              
448             Signed 16-bit value.
449              
450             =item UShort
451              
452             Unsigned 16-bit value.
453              
454             =item Long
455              
456             Signed 32-bit value.
457              
458             =item ULong
459              
460             Unsigned 32-bit value.
461              
462             =item Indx
463              
464             Signed value, same size as a pointer on the system in use.
465              
466             =item ULongLong
467              
468             Unsigned 64-bit value.
469              
470             =item LongLong
471              
472             Signed 64-bit value.
473              
474             =item Float
475              
476             L single-precision real
477             floating-point value.
478              
479             =item Double
480              
481             IEEE 754 double-precision real value.
482              
483             =item LDouble
484              
485             A C99 "long double", defined as "at least as precise as a double",
486             but often more precise.
487              
488             =item CFloat
489              
490             A C99 complex single-precision floating-point value.
491              
492             =item CDouble
493              
494             A C99 complex double-precision floating-point value.
495              
496             =item CLDouble
497              
498             A C99 complex "long double" - see above for description.
499              
500             =back
501              
502             As of 2.099, documentation for L is separate. See there for more.
503              
504             =cut
505              
506             my @CACHED_TYPES = map bless([$_->{numval}, $_], 'PDL::Type'), @HASHES;
507             # return all known types as type objects
508 294     294 0 924111 sub types { @CACHED_TYPES }
509              
510             {
511             package PDL::Type;
512              
513 74     74   648 use Carp;
  74         130  
  74         62575  
514             sub new {
515 13969     13969   31039 my ($type,$val) = @_;
516 13969 100       36166 return $val if "PDL::Type" eq ref $val;
517 13715 50 33     31860 if (ref $val and UNIVERSAL::isa($val, 'PDL')) {
518 0 0       0 PDL::Core::barf("Can't make a type out of non-scalar ndarray $val!")
519             if $val->getndims != 0;
520 0         0 $val = $val->at;
521             }
522 13715 50       27027 confess "Can't make a type out of non-scalar $val (".
523             (ref $val).")!" if ref $val;
524             confess "Unknown type string '$val' (should be one of ".
525             join(",",map $PDL::Types::typehash{$_}{ioname}, @names).
526             ")\n"
527 13715 100       40126 if !defined $PDL::Types::typenames{$val};
528 13714         51987 $CACHED_TYPES[$PDL::Types::typenames{$val}];
529             }
530              
531 10299     10299   34313 sub enum { $_[0][0] }
532             *symbol = \&sym;
533              
534             sub realversion {
535 0     0   0 $CACHED_TYPES[$PDL::Types::typenames{ $_[0][1]{realversion} }];
536             }
537             sub complexversion {
538 70     70   474 $CACHED_TYPES[$PDL::Types::typenames{ $_[0][1]{complexversion} }];
539             }
540 0     0   0 sub isnan { sprintf $_[0][1]{isnan}, $_[1] }
541 0     0   0 sub isfinite { sprintf $_[0][1]{isfinite}, $_[1] }
542              
543             my (%bswap_cache, %howbig_cache);
544             sub bswap {
545 7930 50   7930   23163 PDL::Core::barf('Usage: $type->bswap with no args') if @_ > 1;
546 7930 100       121224 return $bswap_cache{$_[0][0]} if $bswap_cache{$_[0][0]};
547 39         205 my $size = $_[0]->howbig;
548 39 100   1975   198 return $bswap_cache{$_[0][0]} = sub {} if $size < 2;
549 33         927 require PDL::IO::Misc;
550 33         286 my $swapper = PDL->can("bswap$size");
551 33 50       109 PDL::Core::barf("Type::bswap couldn't find swap function for $_[0][1]{shortctype}, size was '$size'") if !defined $swapper;
552 33         9297 $bswap_cache{$_[0][0]} = $swapper;
553             }
554              
555             sub howbig {
556 61   66 61   439 $howbig_cache{$_[0][0]} ||= PDL::Core::howbig($_[0][0]);
557             }
558              
559             foreach my $name (@TYPE_VERBATIM) {
560 74     74   630 no strict 'refs';
  74         143  
  74         26318  
561 6181     6181   38513 *$name = sub { $_[0][1]{$name}; };
562             }
563              
564             sub badvalue {
565 114     114   1340 PDL::Bad::_badvalue_int( $_[1], $_[0][0] );
566             }
567             sub orig_badvalue {
568 5     5   76 PDL::Bad::_default_badvalue_int($_[0][0]);
569             }
570              
571             # make life a bit easier
572             use overload (
573 985     985   166303 '""' => sub { lc $_[0]->shortctype },
574 180     180   48159 "eq" => sub { my ($self, $other, $swap) = @_; ("$self" eq $other); },
  180         569  
575 2     2   8 "cmp" => sub { my ($self, $other, $swap) = @_;
576 2 100       10 $swap ? $other cmp "$self" : "$self" cmp $other;
577             },
578 1823 50   1823   10109 "<=>" => sub { $_[2] ? $_[1][0] <=> $_[0][0] : $_[0][0] <=> $_[1][0] },
579 74     74   47328 );
  74         148767  
  74         1167  
580             } # package: PDL::Type
581             # Return
582             1;
583              
584             __END__