File Coverage

blib/lib/Range/HashIter.pm
Criterion Covered Total %
statement 46 46 100.0
branch 19 20 95.0
condition 4 5 80.0
subroutine 10 10 100.0
pod 1 1 100.0
total 80 82 97.5


line stmt bran cond sub pod time code
1             package Range::HashIter;
2              
3             our $DATE = '2019-05-12'; # DATE
4             our $VERSION = '0.001'; # VERSION
5              
6 1     1   67362 use strict;
  1         11  
  1         30  
7 1     1   5 use warnings;
  1         2  
  1         27  
8              
9 1     1   5 use Exporter qw(import);
  1         2  
  1         127  
10             our @EXPORT_OK = qw(range_hashiter);
11              
12             sub range_hashiter($$;$) {
13 7     7 1 3407 my ($start, $end, $step) = @_;
14              
15 7         29 tie my %hash, 'Range::HashIter::Tie', $start, $end, $step;
16 7         33 \%hash;
17             }
18              
19             package # hide from PAUSE
20             Range::HashIter::Tie;
21              
22 1     1   7 use Scalar::Util qw(looks_like_number);
  1         2  
  1         397  
23              
24             sub TIEHASH {
25 7     7   12 my $class = shift;
26 7         14 my ($start, $end, $step) = @_;
27 7   100     33 $step //= 1;
28              
29 7         27 my $self = {
30             start => $start,
31             end => $end,
32             step => $step,
33              
34             _ended => 0,
35             _len => 0,
36             _cur => $start,
37             _buf => [],
38             };
39              
40 7 100 66     36 if (looks_like_number($start) && looks_like_number($end)) {
41 4         13 $self->{_num} = 1;
42 4 100       11 $self->{_ended}++ if $start > $end;
43             } else {
44 3 50       8 die "Cannot specify step != 1 for non-numeric range" if $step != 1;
45 3 100       10 $self->{_ended}++ if $start gt $end;
46             }
47 7         21 bless $self, $class;
48             }
49              
50             sub _next {
51 43     43   52 my $self = shift;
52              
53 43 100       79 if ($self->{_num}) {
54 13 100       26 $self->{_ended}++ if $self->{_cur} > $self->{end};
55 13 100       26 return if $self->{_ended};
56 9         11 push @{ $self->{_buf} }, $self->{_cur};
  9         27  
57 9         15 $self->{_cur} += $self->{step};
58             } else {
59 30 100       53 return if $self->{_ended};
60 27 100       49 $self->{_ended}++ if $self->{_cur} ge $self->{end};
61 27         32 push @{ $self->{_buf} }, $self->{_cur}++;
  27         58  
62             }
63             }
64              
65             sub FIRSTKEY {
66 43     43   101 my $self = shift;
67 43         84 $self->_next;
68 43 100       59 if (@{ $self->{_buf} }) {
  43         72  
69 36         45 $self->{_len}++;
70 36         44 shift @{ $self->{_buf} };
  36         113  
71             } else {
72 7         19 undef;
73             }
74             }
75              
76             sub NEXTKEY {
77 36     36   176 goto &FIRSTKEY;
78             }
79              
80             sub FETCH {
81 36     36   82 undef;
82             }
83              
84             1;
85             # ABSTRACT: Generate a tied-hash iterator for range
86              
87             __END__