File Coverage

blib/lib/Iterator/Simple/Util.pm
Criterion Covered Total %
statement 165 168 98.2
branch 57 60 95.0
condition 4 6 66.6
subroutine 44 44 100.0
pod 21 21 100.0
total 291 299 97.3


line stmt bran cond sub pod time code
1             package Iterator::Simple::Util;
2             {
3             $Iterator::Simple::Util::VERSION = '0.002';
4             }
5              
6             # ABSTRACT: Port of List::Util and List::MoreUtils to Iterator::Simple
7              
8 1     1   94025 use strict;
  1         3  
  1         33  
9 1     1   5 use warnings FATAL => 'all';
  1         1  
  1         66  
10              
11 1         13 use Sub::Exporter -setup => {
12             exports => [ qw( igroup ireduce isum
13             imax imin imaxstr iminstr imax_by imin_by imaxstr_by iminstr_by
14             iany inone inotall
15             ifirstval ilastval
16             ibefore ibefore_incl iafter iafter_incl
17             inatatime
18             )
19             ]
20 1     1   1033 };
  1         12345  
21              
22 1     1   604 use Const::Fast;
  1         2  
  1         8  
23 1     1   75 use Iterator::Simple qw( iter iterator ichain );
  1         3  
  1         280  
24              
25             const my $TRUE => !0;
26             const my $FALSE => !1;
27              
28             sub _ensure_coderef {
29 35 50   35   109 unless( ref( shift ) eq 'CODE' ) {
30 0         0 require Carp;
31 0         0 Carp::croak("Not a subroutine reference");
32             }
33             }
34              
35             sub _wrap_code {
36 5     5   8 my $code = shift;
37              
38             return sub {
39 60     60   150 $_ = shift;
40 60         121 $code->();
41 5         18 };
42             }
43              
44              
45             sub igroup (&$) {
46 2     2 1 7298 my ( $is_same_group, $base_iter ) = @_;
47              
48 2         10 _ensure_coderef( $is_same_group );
49              
50 2         11 $base_iter = iter $base_iter;
51              
52 2         64 my $next_record = $base_iter->next;
53              
54             # Localize caller's $a and $b
55 2         13 my ( $caller_a, $caller_b ) = do {
56 2         16 require B;
57 2         36 my $caller = B::svref_2object( $is_same_group )->STASH->NAME;
58 1     1   6 no strict 'refs';
  1         2  
  1         296  
59 2         41 map \*{$caller.'::'.$_}, qw( a b );
  4         16  
60             };
61 2         7 local ( *$caller_a, *$caller_b );
62            
63             return iterator {
64 6 100   6   3212 defined( my $base_record = $next_record )
65             or return;
66              
67             return iterator {
68 13 100       2314 return unless defined $next_record;
69 12         27 ( *$caller_a, *$caller_b ) = \( $base_record, $next_record );
70 12 100       31 return unless $is_same_group->();
71 9         222 my $res = $next_record;
72 9         28 $next_record = $base_iter->next;
73 9         59 return $res;
74 4         23 };
75 2         22 };
76             }
77              
78              
79             sub ireduce (&$;$) {
80              
81 16     16 1 1465 my ( $code, $init_val, $iter );
82            
83 16 100       35 if ( @_ == 2 ) {
84 13         25 ( $code, $iter ) = @_;
85             }
86             else {
87 3         6 ( $code, $init_val, $iter ) = @_;
88             }
89              
90 16         30 _ensure_coderef( $code );
91 16         39 $iter = iter $iter;
92            
93             # Localize caller's $a and $b
94 16         158 my ( $caller_a, $caller_b ) = do {
95 16         80 require B;
96 16         106 my $caller = B::svref_2object( $code )->STASH->NAME;
97 1     1   5 no strict 'refs';
  1         3  
  1         1836  
98 16         33 map \*{$caller.'::'.$_}, qw( a b );
  32         112  
99             };
100 16         39 local ( *$caller_a, *$caller_b ) = \my ( $x, $y );
101              
102 16 100       61 $x = @_ == 3 ? $init_val : $iter->next;
103            
104 16 100       113 defined( $x )
105             or return;
106              
107 15 100       39 defined( $y = $iter->next )
108             or return $x;
109            
110 14   66     136 while( defined $x and defined $y ) {
111 100         705 $x = $code->();
112 100         387 $y = $iter->next;
113             }
114            
115 14         159 return $x;
116             }
117              
118              
119             sub isum ($;$) {
120 2     2 1 460 my ( $init_val, $iter );
121              
122 2 100       7 if ( @_ == 1 ) {
123 1         1 $init_val = 0;
124 1         3 $iter = $_[0];
125             }
126             else {
127 1         4 ( $init_val, $iter ) = @_;
128             }
129              
130 2     20   9 ireduce { $a + $b } $init_val, $iter;
  20         29  
131             }
132              
133              
134             sub imax ($) {
135 8 100   8 1 20 ireduce { $a > $b ? $a : $b } shift;
  1     1   23  
136             }
137              
138              
139             sub imin ($) {
140 8 100   8 1 19 ireduce { $a < $b ? $a : $b } shift;
  1     1   21  
141             }
142              
143              
144             sub imax_by (&$) {
145 1     1 1 878 my ( $code, $iter ) = @_;
146              
147 1         4 _ensure_coderef( $code );
148 1         4 $code = _wrap_code( $code );
149            
150 1 100   8   5 ireduce { $code->($a) > $code->($b) ? $a : $b } $iter;
  8         13  
151             }
152              
153              
154             sub imin_by (&$) {
155 2     2 1 37 my ( $code, $iter ) = @_;
156            
157 2         5 _ensure_coderef( $code );
158 2         5 $code = _wrap_code( $code );
159            
160 2 100   16   9 ireduce { $code->($a) < $code->($b) ? $a : $b } $iter;
  16         26  
161             }
162              
163              
164             sub imaxstr ($) {
165 3 100   3 1 11 ireduce { $a gt $b ? $a : $b } shift;
  1     1   616  
166             }
167              
168              
169             sub iminstr ($) {
170 3 100   3 1 10 ireduce { $a lt $b ? $a : $b } shift;
  1     1   6  
171             }
172              
173              
174             sub imaxstr_by (&$) {
175 1     1 1 474 my ( $code, $iter ) = @_;
176              
177 1         5 _ensure_coderef( $code );
178 1         3 $code = _wrap_code( $code );
179            
180 1 100   3   6 ireduce { $code->($a) gt $code->($b) ? $a : $b } $iter;
  3         7  
181             }
182              
183              
184             sub iminstr_by (&$) {
185 1     1 1 24 my ( $code, $iter ) = @_;
186              
187 1         3 _ensure_coderef( $code );
188 1         7 $code = _wrap_code( $code );
189            
190 1 50   3   6 ireduce { $code->($a) lt $code->($b) ? $a : $b } $iter;
  3         7  
191             }
192              
193              
194             sub iany (&$) {
195 2     2 1 480 my ( $code, $iter ) = @_;
196              
197 2         6 _ensure_coderef( $code );
198 2         5 $iter = iter $iter;
199            
200 2         24 while( defined( $_ = $iter->next ) ) {
201 15 100       151 $code->() and return $TRUE;
202             }
203              
204 1         12 return $FALSE;
205             }
206              
207              
208             sub inone (&$) {
209 2     2 1 37 my ( $code, $iter ) = @_;
210              
211 2         6 _ensure_coderef( $code );
212 2         5 $iter = iter $iter;
213              
214 2         21 while( defined( $_ = $iter->next ) ) {
215 15 100       177 $code->() and return $FALSE;
216             }
217              
218 1         13 return $TRUE;
219             }
220              
221              
222             sub inotall (&$) {
223 2     2 1 35 my ( $code, $iter ) = @_;
224              
225 2         6 _ensure_coderef( $code );
226 2         5 $iter = iter $iter;
227              
228 2         21 while( defined( $_ = $iter->next ) ) {
229 12 100       129 return $TRUE if ! $code->();
230             }
231              
232 1         13 return $FALSE;
233             }
234              
235              
236             sub ifirstval (&$) {
237 1     1 1 20 my ( $code, $iter ) = @_;
238 1         3 _ensure_coderef( $code );
239 1         3 $iter = iter $iter;
240            
241 1         12 while( defined( $_ = $iter->next ) ) {
242 4 100       40 $code->() and return $_;
243             }
244              
245 0         0 return;
246             }
247              
248              
249             sub ilastval (&$) {
250 1     1 1 428 my ( $code, $iter ) = @_;
251              
252 1         3 _ensure_coderef( $code );
253 1         6 $iter = iter $iter;
254            
255 1         9 my $val;
256 1         11 while( defined( $_ = $iter->next ) ) {
257 11 100       109 $val = $_ if $code->();
258             }
259              
260 1         10 return $val;
261             }
262              
263              
264             sub ibefore (&$) {
265 1     1 1 431 my ( $code, $iter ) = @_;
266              
267 1         4 _ensure_coderef( $code );
268 1         3 $iter = iter $iter;
269              
270             return iterator {
271 4 50   4   615 defined( $_ = $iter->next )
272             or return;
273 4 100       34 $code->()
274             and return;
275 3         17 return $_;
276 1         15 };
277             }
278              
279              
280             sub ibefore_incl (&$) {
281 1     1 1 695 my ( $code, $iter ) = @_;
282              
283 1         4 _ensure_coderef( $code );
284 1         4 $iter = iter $iter;
285              
286 1         40 my $done = $FALSE;
287            
288             return iterator {
289 5 100 66 5   601 not( $done ) and defined( $_ = $iter->next )
290             or return;
291 4 100       37 $code->() and $done = $TRUE;
292 4         22 return $_;
293 1         7 };
294             }
295              
296              
297             sub iafter (&$) {
298 1     1 1 809 my ( $code, $iter ) = @_;
299              
300 1         3 _ensure_coderef( $code );
301 1         3 $iter = iter $iter;
302              
303 1         11 while( defined( $_ = $iter->next ) ) {
304 4 100       39 last if $code->();
305             }
306              
307 1         8 return $iter;
308             }
309              
310              
311             sub iafter_incl (&$) {
312 1     1 1 632 my ( $code, $iter ) = @_;
313              
314 1         5 _ensure_coderef( $code );
315 1         4 $iter = iter $iter;
316              
317 1         58 while( defined( $_ = $iter->next ) ) {
318 4 100       43 last if $code->();
319             }
320              
321 1         8 return ichain iter( [$_] ), $iter;
322             }
323              
324              
325             sub inatatime ($$) {
326 1     1 1 1348 my ($kicks, $iter) = @_;
327              
328 1         4 $iter = iter $iter;
329              
330             return iterator {
331 5     5   622 my @vals;
332              
333 5         10 for (1 .. $kicks) {
334 13         34 my $val = $iter->next;
335 13 100       79 last unless defined $val;
336 11         24 push @vals, $val;
337             }
338 5 100       18 return @vals ? \@vals : undef;
339 1         15 };
340             }
341              
342              
343             1;
344              
345              
346              
347             =pod
348              
349             =head1 NAME
350              
351             Iterator::Simple::Util - Port of List::Util and List::MoreUtils to Iterator::Simple
352              
353             =head1 VERSION
354              
355             version 0.002
356              
357             =head1 SYNOPSIS
358              
359             use Iterator::Simple::Util qw( igroup ireduce isum
360             imax imin imaxstr iminstr imax_by imin_by imaxstr_by iminstr_by
361             iany inone inotall
362             ifirstval ilastval
363             ibefore ibefore_incl iafter iafter_incl
364             inatatime );
365              
366             =head1 DESCRIPTION
367              
368             B implements many of the functions from
369             L and L for iterators generated by
370             L.
371              
372             =head1 EXPORTS
373              
374             All of these functions call C on the
375             I> argument; this detects what I> is and turns it
376             into an iterator. See L for details.
377              
378             Functions taking a I expect a code block that operates on
379             C<$_> or, in the case of B and B, on C<$a> and C<$b>.
380              
381             =over 4
382              
383             =item igroup I I
384              
385             =item ireduce I [I] I
386              
387             Reduces I by calling I, in a scalar context, multiple times,
388             setting C<$a> and C<$b> each time. The first call will be with C<$a>
389             and C<$b> set to the first two elements of the list, subsequent
390             calls will be done by setting C<$a> to the result of the previous
391             call and C<$b> to the next element in the list.
392              
393             Returns the result of the last call to I. If the iterator is
394             empty then C is returned. If the iterator only contains one
395             element then that element is returned and I is not executed.
396              
397             $foo = ireduce { $a < $b ? $a : $b } $iterator # min
398             $foo = ireduce { $a lt $b ? $a : $b } $iterator # minstr
399             $foo = ireduce { $a + $b } $iterator # sum
400             $foo = ireduce { $a . $b } $iterator # concat
401              
402             If your algorithm requires that C produce an identity value, then
403             make sure that you always pass that identity value as the first argument to prevent
404             C being returned. For example:
405              
406             $foo = ireduce { $a + $b } 0, $iterator
407              
408             will return 0 (rather than C) when C<$iterator> is empty.
409              
410             =item isum [I] I
411              
412             Returns the sum of the elements of I, which should return
413             numeric values. Returns 0 if the iterator is empty.
414              
415             =item imax I
416              
417             Returns the maximum value of I, which should produce numeric
418             values. Retruns C if the iterator is empty.
419              
420             =item imin I
421              
422             Returns the minimum value of I, which should produce numeric
423             values. Returns C if the iterator is empty.
424              
425             =item imax_by I I
426              
427             Return the value of I for which I produces the maximum value.
428             For example:
429              
430             imax_by { $_ * $_ } iter( [ -5 -2 -1 0 1 2 ] )
431              
432             will return C<-5>.
433              
434             =item imin_by I I
435              
436             Similar to B, but returns the value of I for which
437             I produces the minimum value.
438              
439             =item imaxstr I
440              
441             Similar to B, but expects I to return string values.
442              
443             =item iminstr I
444              
445             Similar to B, but expects I to return string values.
446              
447             =item imaxstr_by I I
448              
449             Similar to B, but expects I to return string values.
450              
451             =item iminstr_by I I
452              
453             Similar to B, but expects I to return string values.
454              
455             =item iany I I
456              
457             Returns a true value if any item produced by I meets the
458             criterion given through I. Sets C<$_> for each item in turn:
459              
460             print "At least one value greater than 10"
461             if iany { $_ > 10 } $iterator;
462              
463             Returns false otherwise, or if the iterator is empty.
464              
465             =item inone I I
466              
467             Returns a true value if no item produced by I meets the
468             criterion given through I, or if the iterator is empty. Sets
469             C<$_> for each item in turn:
470              
471             print "No values greater than 10"
472             if inone { $_ > 10 } $iterator;
473              
474             Returns false otherwise.
475              
476             =item inotall I I
477              
478             Logically the negation of I. Returns true if I returns
479             false for some value of I:
480              
481             print "Not all even"
482             if inotall { $_ % 2 == 0 } $iterator;
483              
484             Returns false if the iterator is empty, or all values of I
485             produces a true value for every item produced by I.
486              
487             =item ifirstval I I
488              
489             Returns the first element produced by I for which I
490             evaluates to true. Each element produced by I is set to
491             C<$_> in turn. Returns C if no such element has been found.
492              
493             =item ilastval I I
494              
495             Returns the last element produced by I for which I
496             evaluates to true. Each element of I is set to C<$_> in
497             turn. Returns C if no such element has been found.
498              
499             =item ibefore I I
500              
501             Returns an iterator that will produce all values of I upto
502             (and not including) the point where I returns a true
503             value. Sets C<$_> for each element in turn.
504              
505             =item ibefore_incl I I
506              
507             Returns an iterator that will produce all values of I upto
508             (and including) the point where I returns a true value. Sets
509             C<$_> for each element in turn.
510              
511             =item iafter I I
512              
513             Returns an iterator that will produce all values of I after
514             (and not including) the point where I returns a true
515             value. Sets C<$_> for each element in turn.
516              
517             $it = iafter { $_ % 5 == 0 } [1..9]; # $it returns 6, 7, 8, 9
518              
519             =item iafter_incl I I
520              
521             Returns an iterator that will produce all values of I after
522             (and including) the point where I returns a true value. Sets
523             C<$_> for each element in turn.
524              
525             $it = iafter_incl { $_ % 5 == 0 } [1..9]; # $it returns 5, 6, 7, 8, 9
526              
527             =item inatatime I I
528              
529             Creates an array iterator that returns array refs of elements from
530             I, I items at a time. For example:
531              
532             my $it = inatatime 3, iter( [ 'a' .. 'g' ] );
533             while( my $vals = $it->next ) {
534             print join( ' ', @{$vals} ) . "\n";
535             }
536              
537             This prints:
538              
539             a b c
540             d e f
541             g
542              
543             =back
544              
545             =head1 AUTHOR
546              
547             Ray Miller
548              
549             =head1 COPYRIGHT AND LICENSE
550              
551             This software is copyright (c) 2012 by Ray Miller.
552              
553             This is free software; you can redistribute it and/or modify it under
554             the same terms as the Perl 5 programming language system itself.
555              
556             =cut
557              
558              
559             __END__