File Coverage

blib/lib/Iterator/Flex/Flatten.pm
Criterion Covered Total %
statement 88 88 100.0
branch 26 28 92.8
condition 8 12 66.6
subroutine 16 16 100.0
pod 1 2 50.0
total 139 146 95.2


line stmt bran cond sub pod time code
1             package Iterator::Flex::Flatten;
2              
3             # ABSTRACT: Flatten Iterator Class
4              
5 3     3   171964 use v5.28;
  3         11  
6 3     3   32 use strict;
  3         5  
  3         93  
7 3     3   12 use warnings;
  3         5  
  3         157  
8 3     3   378 use experimental 'signatures';
  3         1165  
  3         15  
9              
10             our $VERSION = '0.34';
11              
12 3     3   920 use Iterator::Flex::Utils qw( STATE RETURN EXHAUSTION :IterAttrs :IterStates throw_failure);
  3         6  
  3         632  
13 3     3   469 use Iterator::Flex::Factory 'construct_from_iterable', 'to_iterator';
  3         8  
  3         186  
14 3     3   17 use Ref::Util 'is_plain_arrayref', 'is_plain_hashref', 'is_blessed_ref';
  3         4  
  3         145  
15 3     3   13 use parent 'Iterator::Flex::Base';
  3         5  
  3         22  
16              
17 3     3   232 use namespace::clean;
  3         5  
  3         43  
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 7     7 1 10 sub new ( $class, $iterable, $pars = {} ) {
  7         14  
  7         13  
  7         12  
  7         8  
68 7         33 $class->SUPER::new( { src => $iterable }, $pars );
69             }
70              
71             ## no critic( ExcessComplexity )
72 7     7 0 9 sub construct ( $class, $state ) {
  7         10  
  7         11  
  7         9  
73              
74 7 50       19 throw_failure( parameter => q{'state' parameter must be a HASH reference} )
75             unless Ref::Util::is_hashref( $state );
76              
77             my ( $prev, $current, $idx, $iter )
78 7         11 = @{$state}{qw[ prev current idx iter src ]};
  7         26  
79              
80 7         12 my $src = @{$state}{qw[ code src ]};
  7         12  
81              
82 7         27 $src = to_iterator( $src );
83              
84 7         14 my $self;
85             my $iterator_state;
86              
87 7         18 my $is_exhausted = $src->can( 'is_exhausted' );
88 7   33     19 my $iter_is_exhausted = is_blessed_ref( $iter )
89             && $iter->can( 'is_exhausted' );
90              
91 7         7 my $rewind = !!0;
92 7         10 my $reset = !!0;
93              
94             return {
95             ( +_NAME ) => 'iflatten',
96              
97             ( +_SELF ) => \$self,
98              
99             ( +STATE ) => \$iterator_state,
100              
101             ( +PREV ) => sub {
102 11     11   29 return $prev;
103             },
104              
105             ( +CURRENT ) => sub {
106 13     13   35 return $current;
107             },
108              
109             ( +NEXT ) => sub {
110 78 50   78   105 return $self->signal_exhaustion if $iterator_state == IterState_EXHAUSTED;
111              
112 78         71 my $value;
113              
114             LOOP:
115 78         70 while ( 1 ) {
116              
117 95 100       126 if ( !defined $iter ) {
118              
119 36         103 $value = $src->();
120 36 100 66     63 if ( !defined $value && $src->$is_exhausted ) {
121 5         7 $prev = $current;
122 5         7 $current = undef;
123 5         11 return $self->signal_exhaustion;
124             }
125              
126             # most likely
127             last LOOP
128 31 100 100     82 if !ref $value || is_plain_hashref( $value );
129              
130             # handle arrays directly; could use an iterator, but this is
131             # faster
132 20 100       33 if ( is_plain_arrayref( $value ) ) {
133 10         13 $iter = $value;
134 10         10 $idx = 0;
135             }
136             else {
137 10         40 $iter = construct_from_iterable(
138             $value,
139             {
140             +( EXHAUSTION ) => RETURN,
141             action_on_failure => RETURN,
142             } );
143 10 100       26 last LOOP if !defined $iter;
144              
145 9         31 $iter_is_exhausted = $iter->can( 'is_exhausted' );
146              
147 9 100       22 if ( $rewind ) {
    100          
148 3 100       17 throw_failure( Unsupported => 'unable to rewind element' )
149             unless $iter->can( 'rewind' );
150 2         6 $iter->rewind;
151             }
152             elsif ( $reset ) {
153 3 100       15 throw_failure( Unsupported => 'unable to reset element' )
154             unless $iter->can( 'reset' );
155 2         6 $iter->reset;
156             }
157             }
158             }
159              
160 76 100       105 if ( defined $idx ) {
161 36 100       51 if ( $idx < $iter->@* ) {
162 26         31 $value = $iter->[ $idx++ ];
163 26         35 last LOOP;
164             }
165 10         12 $iter = $idx = undef;
166 10         17 next;
167             }
168              
169 40         94 $value = $iter->();
170             last LOOP
171 40 100 66     72 if defined $value || !$iter->$iter_is_exhausted;
172              
173 7         9 $iter = undef;
174             }
175              
176 71         62 $prev = $current;
177 71         143 return $current = $value;
178             },
179              
180             ( +RESET ) => sub {
181 2     2   4 $iter = $idx = $prev = $current = undef;
182 2         4 $rewind = !!0;
183 2         3 $reset = !!1;
184             },
185             ( +REWIND ) => sub {
186 2     2   4 $iter = $idx = undef;
187 2         3 $reset = !!0;
188 2         3 $rewind = !!1;
189             },
190 7         135 ( +_DEPENDS ) => $src,
191             };
192             }
193              
194              
195             __PACKAGE__->_add_roles( qw[
196             Current::Closure
197             Next::ClosedSelf
198             Prev::Closure
199             Reset::Closure
200             Rewind::Closure
201             State::Closure
202             ] );
203              
204             1;
205              
206             #
207             # This file is part of Iterator-Flex
208             #
209             # This software is Copyright (c) 2018 by Smithsonian Astrophysical Observatory.
210             #
211             # This is free software, licensed under:
212             #
213             # The GNU General Public License, Version 3, June 2007
214             #
215              
216             __END__