File Coverage

blib/lib/Iterator/Flex/Take.pm
Criterion Covered Total %
statement 106 111 95.5
branch 18 28 64.2
condition 14 26 53.8
subroutine 21 22 95.4
pod 1 2 50.0
total 160 189 84.6


line stmt bran cond sub pod time code
1             package Iterator::Flex::Take;
2              
3             # ABSTRACT: Take Iterator Class
4              
5 3     3   318875 use v5.28;
  3         13  
6 3     3   21 use strict;
  3         6  
  3         90  
7 3     3   14 use warnings;
  3         6  
  3         308  
8              
9             our $VERSION = '0.33';
10              
11 3     3   453 use Iterator::Flex::Utils ':IterAttrs', ':IterStates', ':SignalParameters', ':ExhaustionActions';
  3         8  
  3         887  
12              
13 3     3   580 use Iterator::Flex::Factory 'to_iterator';
  3         7  
  3         235  
14              
15 3     3   22 use Ref::Util;
  3         87  
  3         178  
16 3     3   19 use namespace::clean;
  3         6  
  3         20  
17 3     3   1534 use experimental 'signatures';
  3         7  
  3         22  
18              
19 3     3   721 use parent 'Iterator::Flex::Base';
  3         7  
  3         69  
20              
21              
22              
23              
24              
25              
26              
27              
28              
29              
30              
31              
32              
33              
34              
35              
36              
37              
38              
39              
40              
41              
42              
43              
44              
45              
46              
47              
48              
49              
50              
51              
52              
53              
54              
55              
56              
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67 13     13 1 25 sub new ( $class, $iterable, $n, $pars = {} ) {
  13         32  
  13         43  
  13         24  
  13         26  
  13         22  
68              
69 13         41 my %pars = $pars->%*;
70              
71 13 50 33     150 defined $n && Scalar::Util::looks_like_number( $n ) && int( $n ) == $n && $n >= 0
      33        
      33        
72             || throw_failure( parameter => 'parameter "n" is not a positive integer' );
73              
74 13   100     73 my $lazy = delete $pars{lazy} // !!1;
75              
76 13         100 $class->SUPER::new( {
77             n => $n,
78             lazy => $lazy,
79             src => $iterable,
80             },
81             \%pars,
82             );
83             }
84              
85 13     13 0 21 sub construct ( $class, $state ) {
  13         23  
  13         29  
  13         20  
86              
87 13 50       43 throw_failure( parameter => q{'state' parameter must be a HASH reference} )
88             unless Ref::Util::is_hashref( $state );
89              
90             my ( $src, $prev, $current, $next, $array, $n, $lazy )
91 13         31 = @{$state}{qw[ src prev current next array n lazy ]};
  13         61  
92              
93 13         87 $src
94             = to_iterator( $src, { ( +EXHAUSTION ) => RETURN } );
95              
96 13         59 my $len;
97 13 50       38 $len = $array->@* if defined $array;
98 13   50     67 $current //= undef;
99 13   50     54 $prev //= undef;
100 13   50     51 $next //= 0;
101 13         21 my $took = 0;
102              
103 13         22 my $self;
104 13         76 my $is_exhausted = $src->can( 'is_exhausted' );
105 13         19 my $iterator_state;
106              
107             my %params = (
108              
109             ( +_NAME ) => 'itake',
110              
111             ( +_SELF ) => \$self,
112              
113             ( +STATE ) => \$iterator_state,
114              
115             # this iterator only depends on $src if it hasn't drained it.
116             # currently _DEPENDS must be a list of iterators, not a
117             # coderef, so a dynamic dependency is no tpossible
118             ( +_DEPENDS ) => $src,
119             ( +FREEZE ) => sub {
120             return [
121 0     0   0 $class,
122             {
123             src => $src,
124             prev => $prev,
125             current => $current,
126             next => $next,
127             array => $array,
128             n => $n,
129             lazy => $lazy,
130             },
131             ];
132             },
133 13         124 );
134              
135 13 100       38 if ( $lazy ) {
136              
137             $params{ +RESET } = sub {
138 4     4   9 $prev = $current = undef;
139 4         7 $next = 0;
140 4         9 $took = 0;
141 7         39 };
142              
143             $params{ +REWIND } = sub {
144 4     4   9 $next = 0;
145 4         8 $took = 0;
146 7         28 };
147              
148              
149             $params{ +PREV } = sub {
150 20     20   83 return $prev;
151 7         41 };
152              
153             $params{ +CURRENT } = sub {
154 20     20   86 return $current;
155 7         29 };
156              
157             $params{ +NEXT } = sub {
158              
159 111 100 100 111   503 return $self->signal_exhaustion
160             if $iterator_state == IterState_EXHAUSTED
161             || $took == $n;
162              
163 95         306 my $value = $src->();
164              
165 95 100 100     271 return $self->signal_exhaustion
166             if !$value && $src->$is_exhausted;
167              
168 90         140 $took++;
169              
170 90         173 $prev = $current;
171 90         119 $current = $value;
172 90         287 return $current;
173 7         33 };
174             }
175              
176             else {
177              
178             $params{ +RESET } = sub {
179 4     4   9 $array = $prev = $current = undef;
180 4         10 $len = undef;
181 4         7 $next = 0;
182 6         31 };
183              
184             $params{ +REWIND } = sub {
185 4 50   4   12 $prev = $array->[$current] if defined $current;
186 4         9 $array = $current = undef;
187 4         6 $len = undef;
188 4         6 $next = 0;
189 6         26 };
190              
191             $params{ +PREV } = sub {
192 20     20   90 return $prev;
193 6         19 };
194              
195             $params{ +CURRENT } = sub {
196 20 50   20   127 return defined $current ? $array->[$current] : undef;
197 6         22 };
198              
199             $params{ +NEXT } = sub {
200              
201 112 100   112   244 return $self->signal_exhaustion
202             if $iterator_state == IterState_EXHAUSTED;
203              
204 102 100       166 if ( !defined $array ) {
205             eval {
206 14         21 $array = [];
207              
208             # preload $array
209 14         40 push( $array->@*, $src->next );
210              
211             # postfix until/while check conditional first,
212             # which would be a problem if $array->@* and
213             # n == 0, in which case it would never
214             # call $src->next
215 14         44 push( $array->@*, $src->next ) until $array->@* == $n;
216 14         41 1;
217 14 50       24 } or do {
218 0 0 0     0 die $@
219             unless Ref::Util::is_blessed_ref( $@ )
220             && $@->isa( 'Iterator::Flex::Failure::Exhausted' );
221              
222 0 0       0 if ( !$array->@* ) {
223 0         0 $current = undef;
224 0         0 return $self->signal_exhaustion;
225             }
226             };
227              
228 14         23 $current = 0;
229 14         19 $next = 1;
230 14         22 $len = $array->@*;
231 14         61 return $array->[$current];
232             }
233              
234 88 100       152 if ( $next == $len ) {
235 10         19 $prev = $array->[$current];
236 10         43 return $self->signal_exhaustion;
237             }
238              
239 78         127 $prev = $array->[$current];
240 78         114 $current = $next++;
241 78         175 return $array->[$current];
242 6         26 };
243              
244             }
245              
246 13         74 return \%params;
247              
248             }
249              
250              
251             __PACKAGE__->_add_roles( qw[
252             State::Closure
253             Next::ClosedSelf
254             Rewind::Closure
255             Reset::Closure
256             Prev::Closure
257             Current::Closure
258             Freeze
259             ] );
260              
261             1;
262              
263             #
264             # This file is part of Iterator-Flex
265             #
266             # This software is Copyright (c) 2018 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__