File Coverage

blib/lib/ArrayDataRole/Source/Iterator.pm
Criterion Covered Total %
statement 48 51 94.1
branch 23 28 82.1
condition 1 2 50.0
subroutine 10 11 90.9
pod 0 6 0.0
total 82 98 83.6


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