File Coverage

blib/lib/Iterator/Flex/Stack.pm
Criterion Covered Total %
statement 76 80 95.0
branch 11 16 68.7
condition 2 3 66.6
subroutine 20 20 100.0
pod 1 1 100.0
total 110 120 91.6


line stmt bran cond sub pod time code
1             package Iterator::Flex::Stack;
2              
3             # ABSTRACT: An iterator which concatenates a set of iterators
4              
5 2     2   275485 use v5.28;
  2         7  
6 2     2   9 use strict;
  2         2  
  2         36  
7 2     2   5 use warnings;
  2         7  
  2         92  
8 2     2   439 use experimental qw( signatures declared_refs refaliasing );
  2         1138  
  2         13  
9              
10             our $VERSION = '0.33';
11              
12 2     2   843 use Iterator::Flex::Utils qw( RETURN STATE EXHAUSTION :IterAttrs :IterStates );
  2         4  
  2         428  
13 2     2   463 use Iterator::Flex::Factory 'to_iterator';
  2         4  
  2         108  
14 2     2   10 use parent 'Iterator::Flex::Base';
  2         3  
  2         14  
15 2     2   120 use List::Util 'all';
  2         3  
  2         139  
16              
17 2     2   9 use namespace::clean;
  2         2  
  2         11  
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              
57              
58              
59              
60              
61              
62              
63              
64              
65              
66              
67 3     3 1 5 sub new ( $class, @args ) {
  3         6  
  3         5  
  3         4  
68 3 50       12 my $pars = Ref::Util::is_hashref( $args[-1] ) ? pop @args : {};
69              
70 3         21 $class->SUPER::new( {
71             depends => \@args,
72             current_iterator_index => undef,
73             },
74             $pars,
75             );
76             }
77              
78             sub construct ( $class, $state ) {
79             throw_failure( parameter => q{state must be a HASH reference} )
80             unless Ref::Util::is_hashref( $state );
81              
82             $state->{value} //= [];
83              
84             my ( \@depends, $prev, $current, undef, undef )
85             = @{$state}{ 'depends', 'prev', 'current', 'next', 'thaw' };
86              
87             # transform into iterators if required.
88             my @stack
89             = map { to_iterator( $_, { ( +EXHAUSTION ) => RETURN } ) } @depends;
90             my @snapshot = @stack;
91              
92             # --- cargo cult??
93             # my $value;
94             # $value = $current
95             # if $thaw;
96              
97             my $self;
98              
99             my $iter;
100             my $is_exhausted;
101             my $iterator_state;
102              
103             my sub init {
104             $iterator_state = IterState_EXHAUSTED;
105             if ( @stack ) {
106             $iter = $stack[0];
107             $is_exhausted = $iter->can( 'is_exhausted' );
108             $iterator_state = IterState_CLEAR;
109             }
110             }
111             init();
112              
113             my %params = (
114              
115             ( +_NAME ) => 'istack',
116              
117             ( +_SELF ) => \$self,
118              
119             ( +RESET ) => sub {
120 3     3   4 $prev = $current = undef;
121 3         6 @stack = @snapshot;
122 3         5 init();
123             },
124              
125             ( +REWIND ) => sub {
126 3     3   8 @stack = @snapshot;
127 3         10 init();
128             },
129              
130             ( +STATE ) => \$iterator_state,
131              
132             ( +NEXT ) => sub {
133 70 50   70   127 return $self->signal_exhaustion if $iterator_state == IterState_EXHAUSTED;
134              
135 70         84 while ( 1 ) {
136 92         267 my $value = $iter->();
137              
138 92 100 66     227 if ( defined( $value ) || !$iter->$is_exhausted ) {
139 59         73 $prev = $current;
140 59         197 return $current = $value;
141             }
142              
143 33 100       85 last unless defined( $iter = shift @stack );
144 22         67 $is_exhausted = $iter->can( 'is_exhausted' );
145             }
146              
147 11         18 $prev = $current;
148 11         22 return $current = $self->signal_exhaustion;
149             },
150              
151             ( +PREV ) => sub {
152 7     7   36 return $prev;
153             },
154              
155             ( +CURRENT ) => sub {
156 3 50   3   14 return $self->signal_exhaustion if !@stack;
157 3         14 return $current;
158             },
159              
160 6         11 ( +_ROLES ) => [],
161              
162             ( +_DEPENDS ) => \@snapshot,
163              
164             ( +METHODS ) => {
165 6     6   12 push => sub ( $, @iters ) {
  6         9  
166 6         12 push @stack, map { to_iterator( $_, { ( +EXHAUSTION ) => RETURN } ) } @iters;
  6         33  
167 6         49 $self->_clear_state;
168 6 100       24 init() if @stack == 1;
169             },
170              
171 1     1   3 pop => sub ($) {
  1         3  
172 1 50       21 if ( @stack == 1 ) {
173 0         0 $iterator_state = IterState_EXHAUSTED;
174 0         0 $iter = $is_exhausted = undef;
175             }
176 1         5 return CORE::pop( @stack );
177             },
178              
179 2     2   4 unshift => sub ( $, @iters ) {
  2         6  
  2         23  
180 2         6 unshift @stack, map { to_iterator( $_, { ( +EXHAUSTION ) => RETURN } ) } @iters;
  2         14  
181 2         7 init();
182             },
183              
184 1     1   3 shift => sub ($) {
  1         3  
185 1 50       24 if ( @stack == 1 ) {
186 0         0 $iterator_state = IterState_EXHAUSTED;
187 0         0 $iter = $is_exhausted = undef;
188             }
189 1         3 my $ret = CORE::shift( @stack );
190 1         5 init();
191 1         4 return $ret;
192             },
193              
194 2     2   4 snapshot => sub ($) {
  2         3  
195 2         4 @snapshot = @stack;
196             },
197             },
198              
199             );
200              
201             return \%params;
202             }
203              
204              
205             __PACKAGE__->_add_roles( qw[
206             State::Closure
207             Next::ClosedSelf
208             Rewind::Closure
209             Reset::Closure
210             Current::Closure
211             Prev::Closure
212             ] );
213              
214             1;
215              
216             #
217             # This file is part of Iterator-Flex
218             #
219             # This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
220             #
221             # This is free software, licensed under:
222             #
223             # The GNU General Public License, Version 3, June 2007
224             #
225              
226             __END__