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