File Coverage

blib/lib/ArrayDataRole/Source/Iterator.pm
Criterion Covered Total %
statement 45 48 93.7
branch 23 28 82.1
condition 1 2 50.0
subroutine 9 10 90.0
pod 0 6 0.0
total 78 94 82.9


line stmt bran cond sub pod time code
1             package ArrayDataRole::Source::Iterator;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2021-05-03'; # DATE
5             our $DIST = 'ArrayDataRoles-Standard'; # DIST
6             our $VERSION = '0.005'; # VERSION
7              
8 1     1   770 use 5.010001;
  1         4  
9 1     1   6 use Role::Tiny;
  1         2  
  1         7  
10 1     1   187 use Role::Tiny::With;
  1         2  
  1         585  
11             with 'ArrayDataRole::Spec::Basic';
12              
13             sub _new {
14 1     1   19 my ($class, %args) = @_;
15              
16 1 50       6 my $gen_iterator = delete $args{gen_iterator} or die "Please specify 'gen_iterator' argument";
17 1   50     7 my $gen_iterator_params = delete $args{gen_iterator_params} // {};
18              
19 1 50       4 die "Unknown argument(s): ". join(", ", sort keys %args)
20             if keys %args;
21              
22 1         9 bless {
23             gen_iterator => $gen_iterator,
24             gen_iterator_params => $gen_iterator_params,
25             iterator => undef,
26             pos => 0,
27             # buf => '', # exists when there is a buffer
28             }, $class;
29             }
30              
31             sub get_next_item {
32 14     14 0 80 my $self = shift;
33 14 50       30 $self->reset_iterator unless $self->{iterator};
34 14 100       28 if (exists $self->{buf}) {
35 9         14 $self->{pos}++;
36 9         19 return delete $self->{buf};
37             } else {
38 5         12 my $elem = $self->{iterator}->();
39 5 100       24 die "StopIteration" unless defined $elem;
40 4         8 $self->{pos}++;
41 4         21 return $elem;
42             }
43             }
44              
45             sub has_next_item {
46 12     12 0 30 my $self = shift;
47 12 50       27 if (exists $self->{buf}) {
48 0         0 return 1;
49             }
50 12 50       28 $self->reset_iterator unless $self->{iterator};
51 12         24 my $elem = $self->{iterator}->();
52 12 100       45 return 0 unless defined $elem;
53 9         16 $self->{buf} = $elem;
54 9         20 1;
55             }
56              
57             sub reset_iterator {
58 5     5 0 21 my $self = shift;
59 5         10 $self->{iterator} = $self->{gen_iterator}->(%{ $self->{gen_iterator_params} });
  5         24  
60 5         14 $self->{pos} = 0;
61             }
62              
63             sub get_iterator_pos {
64 0     0 0 0 my $self = shift;
65 0         0 $self->{pos};
66             }
67              
68             sub get_item_at_pos {
69 3     3 0 57 my ($self, $pos) = @_;
70 3 100       55 $self->reset_iterator if $self->{pos} > $pos;
71 3         7 while (1) {
72 5 100       12 die "Out of range" unless $self->has_next_item;
73 4         8 my $item = $self->get_next_item;
74 4 100       16 return $item if $self->{pos} > $pos;
75             }
76             }
77              
78             sub has_item_at_pos {
79 3     3 0 550 my ($self, $pos) = @_;
80 3 100       16 return 1 if $self->{pos} > $pos;
81 2         3 while (1) {
82 3 100       9 return 0 unless $self->has_next_item;
83 2         6 $self->get_next_item;
84 2 100       8 return 1 if $self->{pos} > $pos;
85             }
86             }
87              
88             1;
89             # ABSTRACT: Get array data from an iterator
90              
91             __END__