File Coverage

blib/lib/Types/PDL.pm
Criterion Covered Total %
statement 51 51 100.0
branch 17 18 94.4
condition 4 4 100.0
subroutine 10 10 100.0
pod n/a
total 82 83 98.8


line stmt bran cond sub pod time code
1             package Types::PDL;
2              
3             # ABSTRACT: PDL types using Type::Tiny
4              
5 18     18   3712412 use v5.10;
  18         68  
6              
7 18     18   100 use strict;
  18         123  
  18         1002  
8 18     18   85 use warnings;
  18         41  
  18         1817  
9              
10             our $VERSION = '0.04';
11              
12 18         261 use Type::Library -base,
13             -declare => qw[
14             NDArray
15             NDArray0D
16             NDArray1D
17             NDArray2D
18             NDArray3D
19             NDArrayFromAny
20             ],
21              
22             # eventually will be deprecated
23             qw[
24             Piddle
25             Piddle0D
26             Piddle1D
27             Piddle2D
28             Piddle3D
29             PiddleFromAny
30 18     18   9287 ];
  18         803822  
31              
32              
33 18     18   68477 use Types::Standard -types, 'is_Int';
  18         1604417  
  18         192  
34 18     18   205739 use Type::Utils;
  18         197358  
  18         240  
35 18     18   44590 use Type::TinyX::Facets;
  18         61783  
  18         227  
36 18     18   8798 use B qw(perlstring);
  18         51  
  18         33277  
37              
38             sub _croak {
39 27     27   189 require Carp;
40 27         4749 goto \&Carp::croak;
41             }
42              
43              
44             facet 'empty', sub {
45             my ( $o, $var ) = @_;
46             return unless exists $o->{empty};
47             sprintf( '%s%s->isempty', !!delete( $o->{empty} ) ? '' : '!', $var );
48             };
49              
50             facet 'null', sub {
51             my ( $o, $var ) = @_;
52             return unless exists $o->{null};
53             sprintf( '%s%s->isnull', !!delete( $o->{null} ) ? '' : '!', $var );
54             };
55              
56             facet ndims => sub {
57             my ( $o, $var ) = @_;
58              
59             my %o = map { ( $_ => delete $o->{$_} ) }
60             grep { exists $o->{$_} } qw[ ndims ndims_min ndims_max ];
61              
62             return unless keys %o;
63              
64             _croak( "'$_' must be an integer\n" )
65             for grep { !is_Int( $o{$_} ) } keys %o;
66              
67              
68             if ( exists $o{ndims_max} and exists $o{ndims_min} ) {
69              
70             if ( $o{ndims_max} < $o{ndims_min} ) {
71             _croak( "'ndims_min' must be <= 'ndims_max'\n" );
72             }
73              
74             elsif ( $o{ndims_min} == $o{ndims_max} ) {
75              
76             _croak(
77             "cannot mix 'ndims' facet with either 'ndims_min' or 'ndims_max'\n"
78             ) if exists $o{ndims};
79              
80             $o{ndims} = delete $o{ndims_min};
81             delete $o{ndims_max};
82             }
83             }
84              
85             my @code;
86              
87             if ( exists $o{ndims_max} or exists $o{ndims_min} ) {
88              
89             if ( exists $o{ndims_min} ) {
90             push @code, sprintf( '%s->ndims >= %d', $var, delete $o{ndims_min} );
91             }
92              
93             if ( exists $o{ndims_max} ) {
94             push @code, sprintf ( '%s->ndims <= %d', $var, delete $o{ndims_max} );
95             }
96             }
97              
98             elsif ( exists $o{ndims} ) {
99             push @code, sprintf( '%s->ndims == %d', $var, delete $o{ndims} );
100             }
101              
102             else {
103             return;
104             }
105              
106             _croak( "cannot mix 'ndims' facet with either 'ndims_min' or 'ndims_max'\n" )
107             if keys %o;
108              
109             return join( ' and ', @code );
110             };
111              
112              
113             facet 'type', sub {
114             my ( $o, $var ) = @_;
115             return unless exists $o->{type};
116             my $type = eval { PDL::Type->new( delete $o->{type} )->ioname };
117             _croak( "type must be a valid type name or a PDL::Type object: $@\n" )
118             if $@;
119              
120             sprintf ( '%s->type->ioname eq q[%s]', $var, $type );
121             };
122              
123             facet 'shape', sub {
124             my ( $o, $var ) = @_;
125             return unless exists $o->{shape};
126              
127             my $shape = delete $o->{shape};
128              
129             _croak( "shape must be a string or an arrayref of specifications" )
130             unless 'ARRAY' eq ref $shape or ! ref $shape;
131              
132             sprintf( q|join( ',', %s->dims) =~ qr/%s/x|, $var, _mk_shape_regexp( $shape ) );
133             };
134              
135             # --------------------------------------------------------------------------#
136             # eventually will be deprecated
137              
138             facetize qw[ empty null ndims type shape ], class_type Piddle, { class => 'PDL' };
139              
140             facetize qw[ null type ], declare Piddle0D, as Piddle [ ndims => 0 ];
141              
142             facetize qw[ empty null type shape ], declare Piddle1D, as Piddle [ ndims => 1 ];
143              
144             facetize qw[ empty null type shape ], declare Piddle2D, as Piddle [ ndims => 2 ];
145              
146             facetize qw[ empty null type shape ], declare Piddle3D, as Piddle [ ndims => 3 ];
147              
148             declare_coercion PiddleFromAny, to_type Piddle, from Any, q[ do { local $@;
149             require PDL::Core;
150             my $new = eval { PDL::Core::topdl( $_ ) };
151             $@ ? $_ : $new
152             }
153             ];
154              
155              
156             # --------------------------------------------------------------------------#
157              
158             facetize qw[ empty null ndims type shape ], class_type NDArray, { class => 'PDL' };
159              
160             facetize qw[ null type ], declare NDArray0D, as NDArray [ ndims => 0 ];
161              
162             facetize qw[ empty null type shape ], declare NDArray1D, as NDArray [ ndims => 1 ];
163              
164             facetize qw[ empty null type shape ], declare NDArray2D, as NDArray [ ndims => 2 ];
165              
166             facetize qw[ empty null type shape ], declare NDArray3D, as NDArray [ ndims => 3 ];
167              
168             declare_coercion NDArrayFromAny, to_type NDArray, from Any, q[ do { local $@;
169             require PDL::Core;
170             my $new = eval { PDL::Core::topdl( $_ ) };
171             $@ ? $_ : $new
172             }
173             ];
174              
175              
176             # --------------------------------------------------------------------------#
177              
178              
179             sub _mk_shape_regexp {
180              
181 63     63   392155 my $spec = shift;
182              
183             # positive integer
184 63         108 my $int = q/(?:[0123456789]+)/;
185              
186 63         1076 my $re = qr/
187             \s*(?:
188             (?:
189             (? $int )
190             |
191             (? X | : ) )
192             (?:
193             (?[*+?])
194             | (?:\{
195             (?$int)
196             (?:(?,) (?$int)? )?
197             \}
198             )
199             )?
200             )
201             \s*
202             /x;
203              
204 63         124 my @spec;
205              
206 63 100       150 if ( !ref $spec ) {
207 47         2075 push @spec, { %+ } while $spec =~ /\G$re,?/gc;
208 47 100 100     218 _croak( "error in spec starting HERE ==>",
      100        
209             substr( $spec, pos( $spec ) || 0 ), "<\n" )
210             if ( pos( $spec ) || 0 ) != length( $spec );
211             }
212             else {
213              
214             @spec = map {
215 16 50       50 _croak( "error parsing spec: >$_<\n" )
  58         788  
216             unless /^$re$/;
217 58         694 +{ %+ }
218             } @$spec;
219             }
220              
221              
222 57         93 my @shape;
223              
224 57         131 for my $spec ( @spec ) {
225              
226 165         209 my $extent;
227              
228 165 100       367 if ( defined $spec->{int} ) {
229 143         243 $extent = $spec->{int};
230 143 100       317 _croak( "extent cannot be zero" )
231             if ( $extent += 0 ) == 0;
232             }
233             else {
234 22         42 $extent = $int;
235             }
236              
237 164         279 my $res = "(?:${extent},?)";
238              
239              
240 164 100       400 if ( defined $spec->{quant} ) {
    100          
241 16         33 $res .= $spec->{quant};
242             }
243             elsif ( defined $spec->{min} ) {
244              
245 10         25 $res .= '{' . $spec->{min};
246              
247 10 100       32 $res .= ',' if defined $spec->{comma};
248 10 100       43 $res .= $spec->{max} if defined $spec->{max};
249 10         22 $res .= '}';
250             }
251              
252 164         353 push @shape, $res;
253             }
254              
255             # this must be a string!
256 56         546 return '^' . join( '', @shape ) . '$';
257             }
258              
259              
260              
261             1;
262              
263             #
264             # This file is part of Types-PDL
265             #
266             # This software is Copyright (c) 2017 by Smithsonian Astrophysical Observatory.
267             #
268             # This is free software, licensed under:
269             #
270             # The GNU General Public License, Version 3, June 2007
271             #
272              
273             __END__