File Coverage

blib/lib/Algorithm/SlidingWindow/Dynamic.pm
Criterion Covered Total %
statement 45 105 42.8
branch 9 38 23.6
condition n/a
subroutine 10 18 55.5
pod 12 12 100.0
total 76 173 43.9


line stmt bran cond sub pod time code
1             package Algorithm::SlidingWindow::Dynamic;
2              
3 2     2   495547 use strict;
  2         5  
  2         96  
4 2     2   13 use warnings;
  2         4  
  2         166  
5 2     2   16 use Carp qw(croak);
  2         2  
  2         3808  
6              
7             our $VERSION = '0.900';
8              
9             sub new {
10 3     3 1 228431 my ($class, %args) = @_;
11              
12 3 50       16 my $alloc = exists $args{alloc} ? $args{alloc} : 8;
13 3         11 _check_alloc($alloc);
14 3         6 $alloc = int($alloc);
15              
16 3         20 my $self = bless {
17             buf => [ (undef) x $alloc ],
18             head => 0,
19             size => 0,
20             }, $class;
21              
22 3 50       11 if (exists $args{values}) {
23 0 0       0 croak "values must be an arrayref" if ref($args{values}) ne 'ARRAY';
24 0         0 $self->push(@{ $args{values} });
  0         0  
25             }
26              
27 3         10 return $self;
28             }
29              
30 23     23 1 110 sub size { $_[0]->{size} }
31              
32 0 0   0 1 0 sub is_empty { $_[0]->{size} == 0 ? 1 : 0 }
33              
34             sub oldest {
35 0     0 1 0 my ($self) = @_;
36 0 0       0 return undef if $self->{size} == 0;
37 0         0 return $self->{buf}[ $self->{head} ];
38             }
39              
40             sub newest {
41 0     0 1 0 my ($self) = @_;
42 0 0       0 return undef if $self->{size} == 0;
43              
44 0         0 my $cap = _cap($self);
45 0         0 my $idx = ($self->{head} + $self->{size} - 1) % $cap;
46 0         0 return $self->{buf}[$idx];
47             }
48              
49             sub get {
50 0     0 1 0 my ($self, $index) = @_;
51 0 0       0 return undef if !defined $index;
52 0 0       0 return undef if $index !~ /\A\d+\z/;
53 0 0       0 return undef if $index >= $self->{size};
54              
55 0         0 my $idx = ($self->{head} + $index) % _cap($self);
56 0         0 return $self->{buf}[$idx];
57             }
58              
59             sub values {
60 0     0 1 0 my ($self) = @_;
61 0         0 my $n = $self->{size};
62 0 0       0 return () if $n == 0;
63              
64 0         0 my $cap = _cap($self);
65 0         0 my $head = $self->{head};
66 0         0 my $buf = $self->{buf};
67              
68 0         0 return map { $buf->[ ($head + $_) % $cap ] } (0 .. $n - 1);
  0         0  
69             }
70              
71             sub clear {
72 0     0 1 0 my ($self) = @_;
73 0         0 my $cap = _cap($self);
74              
75 0         0 for (my $i = 0; $i < $cap; $i++) {
76 0         0 $self->{buf}[$i] = undef;
77             }
78              
79 0         0 $self->{head} = 0;
80 0         0 $self->{size} = 0;
81 0         0 return $self;
82             }
83              
84             sub push {
85 11     11 1 89 my ($self, @items) = @_;
86 11 50       28 return $self if !@items;
87              
88 11         24 for my $item (@items) {
89 11         34 $self->_ensure_capacity_for(1);
90              
91 11         23 my $cap = _cap($self);
92 11         26 my $tail = ($self->{head} + $self->{size}) % $cap;
93              
94 11         22 $self->{buf}[$tail] = $item;
95 11         53 $self->{size}++;
96             }
97              
98 11         27 return $self;
99             }
100              
101             sub shift {
102 6     6 1 38 my ($self) = @_;
103 6 50       18 return undef if $self->{size} == 0;
104              
105 6         12 my $idx = $self->{head};
106 6         13 my $val = $self->{buf}[$idx];
107              
108 6         14 $self->{buf}[$idx] = undef;
109 6         17 $self->{head} = ($self->{head} + 1) % _cap($self);
110 6         11 $self->{size}--;
111              
112 6 100       17 $self->{head} = 0 if $self->{size} == 0;
113 6         13 return $val;
114             }
115              
116             sub pop {
117 0     0 1 0 my ($self) = @_;
118 0 0       0 return undef if $self->{size} == 0;
119              
120 0         0 my $cap = _cap($self);
121 0         0 my $idx = ($self->{head} + $self->{size} - 1) % $cap;
122 0         0 my $val = $self->{buf}[$idx];
123              
124 0         0 $self->{buf}[$idx] = undef;
125 0         0 $self->{size}--;
126              
127 0 0       0 $self->{head} = 0 if $self->{size} == 0;
128 0         0 return $val;
129             }
130              
131             sub slide {
132 0     0 1 0 my ($self, $item) = @_;
133              
134 0 0       0 if ($self->{size} == 0) {
135 0         0 $self->push($item);
136 0         0 return undef;
137             }
138              
139 0         0 my $cap = _cap($self);
140              
141 0         0 my $idx = $self->{head};
142 0         0 my $old = $self->{buf}[$idx];
143              
144 0         0 $self->{buf}[$idx] = $item;
145 0         0 $self->{head} = ($self->{head} + 1) % $cap;
146              
147 0         0 return $old;
148             }
149              
150 28     28   48 sub _cap { scalar @{ $_[0]->{buf} } }
  28         64  
151              
152             sub _ensure_capacity_for {
153 11     11   23 my ($self, $add) = @_;
154              
155 11         27 my $need = $self->{size} + $add;
156 11         26 my $cap = _cap($self);
157 11 50       33 return if $need <= $cap;
158              
159 0         0 my $new_cap = $cap * 2;
160 0         0 $new_cap *= 2 while $new_cap < $need;
161              
162 0         0 my @new = (undef) x $new_cap;
163 0         0 for (my $i = 0; $i < $self->{size}; $i++) {
164 0         0 $new[$i] = $self->{buf}[ ($self->{head} + $i) % $cap ];
165             }
166              
167 0         0 $self->{buf} = \@new;
168 0         0 $self->{head} = 0;
169              
170 0         0 return;
171             }
172              
173             sub _check_alloc {
174 3     3   10 my ($n) = @_;
175 3 50       40 croak "alloc must be defined" if !defined $n;
176 3 50       23 croak "alloc must be an integer >= 1" if $n !~ /\A[1-9]\d*\z/;
177 3         7 return 1;
178             }
179              
180             1;
181              
182             __END__