File Coverage

blib/lib/Iterator/Flex/Take.pm
Criterion Covered Total %
statement 107 112 95.5
branch 19 28 67.8
condition 18 25 72.0
subroutine 21 22 95.4
pod 1 2 50.0
total 166 189 87.8


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