File Coverage

blib/lib/Iterator/Flex/Buffer.pm
Criterion Covered Total %
statement 82 83 98.8
branch 18 24 75.0
condition 7 15 46.6
subroutine 16 17 94.1
pod 1 2 50.0
total 124 141 87.9


line stmt bran cond sub pod time code
1             package Iterator::Flex::Buffer;
2              
3             # ABSTRACT: Buffer Iterator Class
4              
5 3     3   179415 use v5.28;
  3         8  
6 3     3   11 use strict;
  3         6  
  3         49  
7 3     3   8 use warnings;
  3         6  
  3         183  
8              
9             our $VERSION = '0.34';
10              
11 3         689 use Iterator::Flex::Utils ':IterAttrs', ':IterStates', ':SignalParameters', ':ExhaustionActions',
12 3     3   338 'throw_failure';
  3         5  
13 3     3   569 use Iterator::Flex::Factory 'to_iterator';
  3         4  
  3         177  
14 3     3   15 use Ref::Util;
  3         3  
  3         73  
15 3     3   11 use namespace::clean;
  3         13  
  3         12  
16 3     3   924 use experimental 'signatures';
  3         4  
  3         14  
17              
18 3     3   316 use parent 'Iterator::Flex::Base';
  3         5  
  3         33  
19              
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 8     8 1 11 sub new ( $class, $iterable, $capacity = 0, $pars = {} ) {
  8         11  
  8         10  
  8         10  
  8         11  
  8         7  
58              
59 8         15 my %pars = $pars->%*;
60 8   50     18 $capacity //= 0;
61              
62 8 50 33     61 Scalar::Util::looks_like_number( $capacity ) && int( $capacity ) == $capacity && $capacity >= 0
      33        
63             or throw_failure(
64             parameter => "parameter 'capacity' ($capacity) is not a positive or zero integer" );
65              
66 8         31 $class->SUPER::new( {
67             capacity => $capacity,
68             src => $iterable,
69             },
70             \%pars,
71             );
72             }
73              
74 8     8 0 9 sub construct ( $class, $state ) {
  8         11  
  8         9  
  8         11  
75              
76 8 50       13 throw_failure( parameter => q{'state' parameter must be a HASH reference} )
77             unless Ref::Util::is_hashref( $state );
78              
79             my ( $src, $prev, $current, $next, $array, $capacity )
80 8         13 = @{$state}{qw[ src prev current next array capacity ]};
  8         20  
81              
82 8         31 $src
83             = to_iterator( $src, { ( +EXHAUSTION ) => THROW } );
84              
85 8 50       23 my $nread = defined $array ? $array->@* - 1 : 0;
86 8   50     29 $next //= 1;
87 8         10 my $self;
88              
89             my $iterator_state;
90 8         9 my $src_is_exhausted = !!0;
91              
92             return {
93              
94             ( +_NAME ) => 'ibuffer',
95              
96             ( +_SELF ) => \$self,
97              
98             ( +STATE ) => \$iterator_state,
99              
100             ( +RESET ) => sub {
101 4     4   6 $src_is_exhausted = !!0;
102 4         5 $prev = $current = undef;
103 4         6 $next = 1;
104 4         6 $nread = 0;
105             },
106              
107             ( +REWIND ) => sub {
108 4     4   5 $src_is_exhausted = !!0;
109 4         5 $next = 1;
110 4         6 $nread = 0;
111             },
112              
113             ( +PREV ) => sub {
114 50 50   50   165 return defined $prev ? $array->[$prev] : undef;
115             },
116              
117             ( +CURRENT ) => sub {
118 40 50   40   138 return defined $current ? $array->[$current] : undef;
119             },
120              
121             ( +NEXT ) => sub {
122              
123 166 100   166   312 return $self->signal_exhaustion
124             if $iterator_state == IterState_EXHAUSTED;
125              
126             # load buffer; need to handle both initial and recurrent loads,
127             # keeping track of the previous value.
128 156 100       233 if ( $next > $nread ) {
129              
130 50 100       66 if ( $src_is_exhausted ) {
131 7         10 $prev = $current;
132 7         17 return $self->signal_exhaustion;
133             }
134              
135 43   100     76 $array //= [];
136 43 100       92 my $prev_value = defined $current ? $array->[$current] : undef;
137              
138             # $array has one more element than $capacity to
139             # ensure there's room for the previous value when
140             # we load the next buffer.
141 43         66 $array->@* = ( $prev_value );
142              
143             eval {
144             # preload $array
145 43         136 push $array->@*, $src->next;
146              
147             # postfix until/while check conditional first,
148             # which would be a problem if $array->@* and
149             # capacity == 0, in which case it would never
150             # call $src->next
151 38         99 push( $array->@*, $src->next ) until $array->@* == $capacity + 1;
152 31         56 1;
153 43 100       42 } or do {
154 12 50 33     445 die $@
155             unless Ref::Util::is_blessed_ref( $@ )
156             && $@->isa( 'Iterator::Flex::Failure::Exhausted' );
157 12         19 $src_is_exhausted = !!1;
158 12 100       22 if ( $array->@* == 1 ) {
159 5         7 $current = $prev = 0; # setup for rewind
160 5         9 return $self->signal_exhaustion;
161             }
162             };
163              
164 38         44 $nread = $array->@* - 1;
165 38         34 $current = 0;
166 38         49 $next = 1;
167             }
168              
169 144         149 $prev = $current;
170 144         120 $current = $next;
171 144         127 $next++;
172 144         269 return $array->[$current];
173             },
174              
175             # this iterator only depends on $src if it hasn't drained it.
176             # currently _DEPENDS must be a list of iterators, not a
177             # coderef, so a dynamic dependency is not possible
178             ( +_DEPENDS ) => $src,
179             ( +FREEZE ) => sub {
180             return [
181 0     0     $class,
182             {
183             src => $src,
184             prev => $prev,
185             current => $current,
186             next => $next,
187             array => $array,
188             capacity => $capacity,
189             },
190             ];
191             },
192 8         127 };
193             }
194              
195              
196             __PACKAGE__->_add_roles( qw[
197             State::Closure
198             Next::ClosedSelf
199             Rewind::Closure
200             Reset::Closure
201             Prev::Closure
202             Current::Closure
203             Freeze
204             ] );
205              
206             1;
207              
208             #
209             # This file is part of Iterator-Flex
210             #
211             # This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
212             #
213             # This is free software, licensed under:
214             #
215             # The GNU General Public License, Version 3, June 2007
216             #
217              
218             __END__