File Coverage

blib/lib/List/Util/PP.pm
Criterion Covered Total %
statement 252 277 90.9
branch 88 116 75.8
condition 38 64 59.3
subroutine 47 47 100.0
pod 33 33 100.0
total 458 537 85.2


line stmt bran cond sub pod time code
1             package List::Util::PP;
2 24     24   2199911 use strict;
  24         48  
  24         924  
3 24     24   121 use warnings;
  24         52  
  24         1494  
4 24     24   147 use Exporter ();
  24         45  
  24         3201  
5              
6             our $VERSION = '1.500015';
7             $VERSION =~ tr/_//d;
8              
9             our @EXPORT_OK;
10             BEGIN {
11 24     24   2594 @EXPORT_OK = qw(
12             all any first none notall
13             min max minstr maxstr
14             product reductions reduce sum sum0
15             sample shuffle
16             uniq uniqnum uniqint uniqstr
17             pairs unpairs pairkeys pairvalues pairmap pairgrep pairfirst
18             head tail
19             zip zip_longest zip_shortest
20             mesh mesh_longest mesh_shortest
21             );
22             }
23              
24             my $rand = do { our $RAND };
25             *RAND = *List::Util::RAND;
26             our $RAND;
27             $RAND = $rand
28             if !defined $RAND;
29              
30             sub import {
31 25     25   310 my $pkg = caller;
32              
33             # (RT88848) Touch the caller's $a and $b, to avoid the warning of
34             # Name "main::a" used only once: possible typo" warning
35 24     24   882 no strict 'refs';
  24         86  
  24         7366  
36 25         52 ${"${pkg}::a"} = ${"${pkg}::a"};
  25         210  
  25         141  
37 25         73 ${"${pkg}::b"} = ${"${pkg}::b"};
  25         66  
  25         133  
38              
39             # May be imported by List::Util if very old version is installed, which
40             # expects default exports
41 25 50 33     115 if ($pkg eq 'List::Util' && @_ < 2) {
42             package #hide from PAUSE
43             List::Util;
44 0         0 return __PACKAGE__->import(qw(first min max minstr maxstr reduce sum shuffle));
45             }
46              
47 25         19900 goto &Exporter::import;
48             }
49              
50             sub reduce (&@) {
51 32     32 1 541874 my $f = shift;
52 32 100 100     159 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  28         103  
  25         118  
53 7         85 require Carp;
54 7         1016 Carp::croak("Not a subroutine reference");
55             }
56              
57 25 100       75 return shift unless @_ > 1;
58              
59 23         76 my $pkg = caller;
60 23         44 my $a = shift;
61              
62 24     24   216 no strict 'refs';
  24         77  
  24         5914  
63 23         39 local *{"${pkg}::a"} = \$a;
  23         93  
64 23         55 my $glob_b = \*{"${pkg}::b"};
  23         86  
65              
66 23         69 foreach my $b (@_) {
67 92         425 local *$glob_b = \$b;
68 92         182 $a = $f->();
69             }
70              
71 21         167 $a;
72             }
73              
74             sub reductions (&@) {
75 5     5 1 191161 my $f = shift;
76 5 50 33     21 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  5         10  
  5         16  
77 0         0 require Carp;
78 0         0 Carp::croak("Not a subroutine reference");
79             }
80              
81 5 100       22 return unless @_;
82 4 50       8 return shift unless @_ > 1;
83              
84 4         8 my $pkg = caller;
85 4         5 my $a = shift;
86              
87 24     24   157 no strict 'refs';
  24         51  
  24         39328  
88 4         5 local *{"${pkg}::a"} = \$a;
  4         12  
89 4         5 my $glob_b = \*{"${pkg}::b"};
  4         9  
90              
91 4         7 my @o = $a;
92              
93 4         6 foreach my $b (@_) {
94 13         17 local *$glob_b = \$b;
95 13         17 $a = $f->();
96 12         29 push @o, $a;
97             }
98              
99 3         9 @o;
100             }
101              
102             sub first (&@) {
103 23     23 1 639131 my $f = shift;
104 23 100 100     82 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  20         45  
  18         63  
105 5         21 require Carp;
106 5         436 Carp::croak("Not a subroutine reference");
107             }
108              
109             $f->() and return $_
110 18   100     61 foreach @_;
111              
112 5         30 undef;
113             }
114              
115             sub sum (@) {
116 22 100   22 1 378308 return undef unless @_;
117 21         50 my $s = 0;
118 21         163 $s += $_ foreach @_;
119 21         1644 return $s;
120             }
121              
122             sub min (@) {
123 18 50   18 1 363259 return undef unless @_;
124 18         43 my $min = shift;
125             $_ < $min and $min = $_
126 18   66     159 foreach @_;
127 18         778 return $min;
128             }
129              
130             sub max (@) {
131 21 50   21 1 332327 return undef unless @_;
132 21         46 my $max = shift;
133             $_ > $max and $max = $_
134 21   66     130 foreach @_;
135 21         780 return $max;
136             }
137              
138             sub minstr (@) {
139 4 50   4 1 233580 return undef unless @_;
140 4         20 my $min = shift;
141             $_ lt $min and $min = $_
142 4   66     61 foreach @_;
143 4         13 return $min;
144             }
145              
146             sub maxstr (@) {
147 4 50   4 1 179595 return undef unless @_;
148 4         10 my $max = shift;
149             $_ gt $max and $max = $_
150 4   66     34 foreach @_;
151 4         27 return $max;
152             }
153              
154             sub shuffle (@) {
155 6     6 1 203896 sample(scalar @_, @_);
156             }
157              
158             sub sample ($@) {
159 16     16 1 208353 my $num = shift;
160 16         48 my @i = (0 .. $#_);
161 16 100       45 $num = @_ if $num > @_;
162 16 100       241 my @o = defined $RAND ? (map +(splice @i, $RAND->(scalar @i), 1), 1 .. $num)
163             : (map +(splice @i, rand(scalar @i), 1), 1 .. $num);
164 16         157 @_[@o];
165             }
166              
167             sub all (&@) {
168 4     4 1 1428 my $f = shift;
169 4 50 33     16 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  4         10  
  4         18  
170 0         0 require Carp;
171 0         0 Carp::croak("Not a subroutine reference");
172             }
173              
174             $f->() or return !!0
175 4   100     13 foreach @_;
176 3         29 return !!1;
177             }
178              
179             sub any (&@) {
180 5     5 1 319541 my $f = shift;
181 5 50 33     28 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  5         11  
  5         27  
182 0         0 require Carp;
183 0         0 Carp::croak("Not a subroutine reference");
184             }
185              
186             $f->() and return !!1
187 5   100     21 foreach @_;
188 2         13 return !!0;
189             }
190              
191             sub none (&@) {
192 4     4 1 976 my $f = shift;
193 4 50 33     15 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  4         9  
  4         18  
194 0         0 require Carp;
195 0         0 Carp::croak("Not a subroutine reference");
196             }
197              
198             $f->() and return !!0
199 4   100     12 foreach @_;
200 2         11 return !!1;
201             }
202              
203             sub notall (&@) {
204 4     4 1 976 my $f = shift;
205 4 50 33     15 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  4         7  
  4         18  
206 0         0 require Carp;
207 0         0 Carp::croak("Not a subroutine reference");
208             }
209              
210             $f->() or return !!1
211 4   100     13 foreach @_;
212 3         28 return !!0;
213             }
214              
215             sub product (@) {
216 25     25 1 266393 my $p = 1;
217 25         202 $p *= $_ foreach @_;
218 25         1604 return $p;
219             }
220              
221             sub sum0 (@) {
222 3     3 1 224003 my $s = 0;
223 3         16 $s += $_ foreach @_;
224 3         6 return $s;
225             }
226              
227             sub pairs (@) {
228 3 100   3 1 23634 if (@_ % 2) {
229 1         96 warnings::warnif('misc', 'Odd number of elements in pairs');
230             }
231              
232             return
233 3         23 map { bless [ @_[$_, $_ + 1] ], 'List::Util::PP::_Pair' }
  7         48  
234             map $_*2,
235             0 .. int($#_/2);
236             }
237              
238             sub unpairs (@) {
239 3     3 1 952 map @{$_}[0,1], @_;
  7         36  
240             }
241              
242             sub pairkeys (@) {
243 1 50   1 1 7 if (@_ % 2) {
244 0         0 warnings::warnif('misc', 'Odd number of elements in pairkeys');
245             }
246              
247             return
248 1         14 map $_[$_*2],
249             0 .. int($#_/2);
250             }
251              
252             sub pairvalues (@) {
253 1 50   1 1 6 if (@_ % 2) {
254 0         0 require Carp;
255 0         0 warnings::warnif('misc', 'Odd number of elements in pairvalues');
256             }
257              
258             return
259 1         12 map $_[$_*2 + 1],
260             0 .. int($#_/2);
261             }
262              
263             sub pairmap (&@) {
264 11     11 1 5945 my $f = shift;
265 11 50 33     55 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  11         26  
  11         55  
266 0         0 require Carp;
267 0         0 Carp::croak("Not a subroutine reference");
268             }
269              
270 11 100       38 if (@_ % 2) {
271 1         69 warnings::warnif('misc', 'Odd number of elements in pairmap');
272             }
273              
274 11         28 my $pkg = caller;
275 24     24   209 no strict 'refs';
  24         66  
  24         6712  
276 11         21 my $glob_a = \*{"${pkg}::a"};
  11         45  
277 11         18 my $glob_b = \*{"${pkg}::b"};
  11         32  
278              
279             return
280             map {
281 11         65 local (*$glob_a, *$glob_b) = \( @_[$_,$_+1] );
  30         648  
282 30         90 $f->();
283             }
284             map $_*2,
285             0 .. int($#_/2);
286             }
287              
288             sub pairgrep (&@) {
289 7     7 1 188924 my $f = shift;
290 7 50 33     43 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  7         17  
  7         41  
291 0         0 require Carp;
292 0         0 Carp::croak("Not a subroutine reference");
293             }
294              
295 7 100       26 if (@_ % 2) {
296 2         353 warnings::warnif('misc', 'Odd number of elements in pairgrep');
297             }
298              
299 7         51 my $pkg = caller;
300 24     24   213 no strict 'refs';
  24         61  
  24         7258  
301 7         14 my $glob_a = \*{"${pkg}::a"};
  7         32  
302 7         13 my $glob_b = \*{"${pkg}::b"};
  7         21  
303              
304             return
305             map {
306 7         65 local (*$glob_a, *$glob_b) = \( @_[$_,$_+1] );
  18         122  
307 18 100       46 $f->() ? (wantarray ? @_[$_,$_+1] : 1) : ();
    100          
308             }
309             map $_*2,
310             0 .. int ($#_/2);
311             }
312              
313             sub pairfirst (&@) {
314 5     5 1 1789 my $f = shift;
315 5 50 33     28 unless ( length ref $f && eval { $f = \&$f; 1 } ) {
  5         42  
  5         59  
316 0         0 require Carp;
317 0         0 Carp::croak("Not a subroutine reference");
318             }
319              
320 5 50       21 if (@_ % 2) {
321 0         0 warnings::warnif('misc', 'Odd number of elements in pairfirst');
322             }
323              
324 5         16 my $pkg = caller;
325 24     24   174 no strict 'refs';
  24         50  
  24         39172  
326 5         9 my $glob_a = \*{"${pkg}::a"};
  5         23  
327 5         10 my $glob_b = \*{"${pkg}::b"};
  5         16  
328              
329 5         36 foreach my $i (map $_*2, 0 .. int($#_/2)) {
330 13         84 local (*$glob_a, *$glob_b) = \( @_[$i,$i+1] );
331 13 100       36 return wantarray ? @_[$i,$i+1] : 1
    100          
332             if $f->();
333             }
334 2         25 return ();
335             }
336              
337 1     1   11 sub List::Util::PP::_Pair::key { $_[0][0] }
338 1     1   7 sub List::Util::PP::_Pair::value { $_[0][1] }
339 2     2   7 sub List::Util::PP::_Pair::TO_JSON { [ @{$_[0]} ] }
  2         16  
340              
341             sub uniq (@) {
342 5     5 1 196463 my %seen;
343             my $undef;
344 5 100       67 my @uniq = grep defined($_) ? !$seen{$_}++ : !$undef++, @_;
345 5         363 @uniq;
346             }
347              
348             sub uniqnum (@) {
349 838     838 1 6837669 my %seen;
350             my $sv;
351 838         19818 require B;
352 838         6894 my $b = B::svref_2object(\$sv);
353             my @uniq =
354             grep {
355 333453         450701 my $nv = $_;
356 333453         415245 my $k;
357 333453 50 66     616780 if (ref $nv && defined &overload::ov_method && defined &overload::mycan) {
      66        
358 3         7 my $package = ref $nv;
359             # also covers Math::BigInt and Math::BigFloat
360 3 50 33     27 if (UNIVERSAL::isa($nv, 'Math::BigInt')) {
    50          
    0          
361 0         0 $k = $nv->bstr;
362             }
363             elsif(my $method
364             = overload::ov_method(overload::mycan($package, '(0+'), $package)
365             || overload::ov_method(overload::mycan($package, '""'), $package)
366             || overload::ov_method(overload::mycan($package, 'bool'), $package)
367             ) {
368 3         135 $nv = $nv->$method(undef, !!0);
369             }
370             elsif (
371             my $nomethod = overload::ov_method(overload::mycan($package, '(nomethod'), $package)
372             ) {
373 0         0 $nv = $nv->$nomethod(undef, undef, '0+');
374             }
375             }
376              
377 333453 50       903718 if (defined $k) {
    50          
    100          
    100          
    100          
378             }
379             elsif (ref $nv) {
380 0         0 $k = 'R' . 0+$nv;
381             }
382             elsif ($nv == 0) {
383 29788         40122 $k = '0';
384             }
385             elsif ($nv*0 != $nv*0) {
386 309         618 $k = sprintf '%f', $nv;
387             }
388             elsif (int($nv) != $nv) {
389 93167         169142 $k = 'N' . pack('F', $nv);
390             }
391             else {
392 210189         273072 $sv = $nv + 0;
393 210189         347945 my $flags = $b->FLAGS;
394 210189 100       397618 if ($flags & B::SVf_IVisUV()) {
    100          
    50          
395 1094         2712 $k = sprintf '%u', $nv;
396             }
397             elsif ($flags & B::SVf_IOK()) {
398 192756         336199 $k = sprintf '%d', $nv;
399             }
400             elsif ($flags & B::SVf_NOK()) {
401 16339         171331 $k = sprintf '%.0f', $nv;
402             }
403             else {
404 0         0 $k = $nv;
405             }
406             }
407 333453         675174 !$seen{$k}++;
408             }
409             map +(defined($_) ? $_
410 838 100       178252 : do { warnings::warnif('uninitialized', 'Use of uninitialized value in subroutine entry'); 0 }),
  2         426  
  2         22  
411             @_;
412 838         37852 @uniq;
413             }
414              
415             sub uniqint (@) {
416 9     9 1 3544 my %seen;
417             my @uniq =
418             map +(
419             ref $_ ? $_ : int($_)
420             ),
421             grep {
422             !$seen{
423 18 50       204 /\A[0-9]+\z/ ? $_
    100          
424             : $_ > 0 ? sprintf '%u', $_
425             : sprintf '%d', $_
426             }++;
427             }
428             map +(defined($_) ? $_
429 9 100       48 : do { warnings::warnif('uninitialized', 'Use of uninitialized value in subroutine entry'); 0 }),
  2 100       356  
  2         25  
430             @_;
431 9         98 @uniq;
432             }
433              
434             sub uniqstr (@) {
435 13     13 1 247333 my %seen;
436             my @uniq =
437             grep !$seen{$_}++,
438             map +(defined($_) ? $_
439 13 100       173 : do { warnings::warnif('uninitialized', 'Use of uninitialized value in subroutine entry'); '' }),
  2         450  
  2         31  
440             @_;
441 13         117 @uniq;
442             }
443              
444             sub head ($@) {
445 11     11 1 377217 my $size = shift;
446             return @_
447 11 100       47 if $size > @_;
448 8 100       41 @_[ 0 .. ( $size >= 0 ? $size - 1 : $#_ + $size ) ];
449             }
450              
451             sub tail ($@) {
452 9     9 1 15511 my $size = shift;
453             return @_
454 9 100       36 if $size > @_;
455 8 100       46 @_[ ( $size >= 0 ? ($#_ - ($size-1) ) : 0 - $size ) .. $#_ ];
456             }
457              
458             sub zip_longest {
459 7 100   7 1 200975 return unless @_;
460             map {
461 6         55 my $idx = $_;
  9         36  
462 9         78 [ map $_->[$idx], @_ ];
463             } ( 0 .. max(map $#$_, @_) );
464             }
465              
466             sub zip_shortest {
467 2 50   2 1 10 return unless @_;
468             map {
469 2         13 my $idx = $_;
  3         5  
470 3         25 [ map $_->[$idx], @_ ];
471             } ( 0 .. min(map $#$_, @_) );
472             }
473              
474             *zip = \&zip_longest;
475              
476             sub mesh_longest {
477 7 100   7 1 230707 return unless @_;
478             map {
479 6         85 my $idx = $_;
  9         13  
480 9         48 map $_->[$idx], @_;
481             } ( 0 .. max(map $#$_, @_) );
482             }
483              
484             sub mesh_shortest {
485 2 50   2 1 10 return unless @_;
486             map {
487 2         16 my $idx = $_;
  3         5  
488 3         22 map $_->[$idx], @_;
489             } ( 0 .. min(map $#$_, @_) );
490             }
491              
492             *mesh = \&mesh_longest;
493              
494             1;
495              
496             __END__