File Coverage

blib/lib/Iterator/Flex/Flatten.pm
Criterion Covered Total %
statement 88 88 100.0
branch 25 28 89.2
condition 8 12 66.6
subroutine 16 16 100.0
pod 1 2 50.0
total 138 146 94.5


line stmt bran cond sub pod time code
1             package Iterator::Flex::Flatten;
2              
3             # ABSTRACT: Flatten Iterator Class
4              
5 3     3   190978 use v5.28;
  3         11  
6 3     3   18 use strict;
  3         7  
  3         106  
7 3     3   32 use warnings;
  3         6  
  3         192  
8 3     3   371 use experimental 'signatures';
  3         1121  
  3         18  
9              
10             our $VERSION = '0.33';
11              
12 3     3   1036 use Iterator::Flex::Utils qw( STATE RETURN EXHAUSTION :IterAttrs :IterStates throw_failure);
  3         8  
  3         779  
13 3     3   490 use Iterator::Flex::Factory 'construct_from_iterable', 'to_iterator';
  3         12  
  3         249  
14 3     3   22 use Ref::Util 'is_plain_arrayref', 'is_plain_hashref', 'is_blessed_ref';
  3         7  
  3         185  
15 3     3   19 use parent 'Iterator::Flex::Base';
  3         5  
  3         52  
16              
17 3     3   245 use namespace::clean;
  3         7  
  3         17  
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 6     6 1 16 sub new ( $class, $iterable, $pars = {} ) {
  6         16  
  6         12  
  6         12  
  6         13  
68 6         65 $class->SUPER::new( { src => $iterable }, $pars );
69             }
70              
71             ## no critic( ExcessComplexity )
72 6     6 0 15 sub construct ( $class, $state ) {
  6         13  
  6         14  
  6         13  
73              
74 6 50       26 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 6         16 = @{$state}{qw[ prev current idx iter src ]};
  6         29  
79              
80 6         13 my $src = @{$state}{qw[ code src ]};
  6         15  
81              
82 6         30 $src = to_iterator( $src );
83              
84 6         22 my $self;
85             my $iterator_state;
86              
87 6         31 my $is_exhausted = $src->can( 'is_exhausted' );
88 6   33     24 my $iter_is_exhausted = is_blessed_ref( $iter )
89             && $iter->can( 'is_exhausted' );
90              
91 6         13 my $rewind = !!0;
92 6         12 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   51 return $prev;
103             },
104              
105             ( +CURRENT ) => sub {
106 13     13   70 return $current;
107             },
108              
109             ( +NEXT ) => sub {
110 74 50   74   169 return $self->signal_exhaustion if $iterator_state == IterState_EXHAUSTED;
111              
112 74         112 my $value;
113              
114             LOOP:
115 74         118 while ( 1 ) {
116              
117 91 100       199 if ( !defined $iter ) {
118              
119 32         177 $value = $src->();
120 32 100 66     103 if ( !defined $value && $src->$is_exhausted ) {
121 4         8 $prev = $current;
122 4         11 $current = undef;
123 4         14 return $self->signal_exhaustion;
124             }
125              
126             # most likely
127             last LOOP
128 28 100 100     132 if !ref $value || is_plain_hashref( $value );
129              
130             # handle arrays directly; could use an iterator, but this is
131             # faster
132 19 100       52 if ( is_plain_arrayref( $value ) ) {
133 10         22 $iter = $value;
134 10         22 $idx = 0;
135             }
136             else {
137 9         74 $iter = construct_from_iterable(
138             $value,
139             {
140             +( EXHAUSTION ) => RETURN,
141             action_on_failure => RETURN,
142             } );
143 9 50       38 last LOOP if !defined $iter;
144              
145 9         50 $iter_is_exhausted = $iter->can( 'is_exhausted' );
146              
147 9 100       34 if ( $rewind ) {
    100          
148 3 100       27 throw_failure( Unsupported => 'unable to rewind element' )
149             unless $iter->can( 'rewind' );
150 2         10 $iter->rewind;
151             }
152             elsif ( $reset ) {
153 3 100       29 throw_failure( Unsupported => 'unable to reset element' )
154             unless $iter->can( 'reset' );
155 2         10 $iter->reset;
156             }
157             }
158             }
159              
160 76 100       156 if ( defined $idx ) {
161 36 100       88 if ( $idx < $iter->@* ) {
162 26         54 $value = $iter->[ $idx++ ];
163 26         59 last LOOP;
164             }
165 10         22 $iter = $idx = undef;
166 10         19 next;
167             }
168              
169 40         155 $value = $iter->();
170             last LOOP
171 40 100 66     133 if defined $value || !$iter->$iter_is_exhausted;
172              
173 7         20 $iter = undef;
174             }
175              
176 68         100 $prev = $current;
177 68         240 return $current = $value;
178             },
179              
180             ( +RESET ) => sub {
181 2     2   6 $iter = $idx = $prev = $current = undef;
182 2         5 $rewind = !!0;
183 2         6 $reset = !!1;
184             },
185             ( +REWIND ) => sub {
186 2     2   5 $iter = $idx = undef;
187 2         5 $reset = !!0;
188 2         5 $rewind = !!1;
189             },
190 6         159 ( +_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__