File Coverage

blib/lib/Data/BitStream/Code/ARice.pm
Criterion Covered Total %
statement 80 85 94.1
branch 39 50 78.0
condition 12 12 100.0
subroutine 10 11 90.9
pod 2 2 100.0
total 143 160 89.3


line stmt bran cond sub pod time code
1             package Data::BitStream::Code::ARice;
2 28     28   25353 use strict;
  28         67  
  28         1077  
3 28     28   169 use warnings;
  28         57  
  28         1474  
4             BEGIN {
5 28     28   73 $Data::BitStream::Code::ARice::AUTHORITY = 'cpan:DANAJ';
6 28         2963 $Data::BitStream::Code::ARice::VERSION = '0.08';
7             }
8              
9             our $CODEINFO = { package => __PACKAGE__,
10             name => 'ARice',
11             universal => 1,
12             params => 1,
13             encodesub => sub {shift->put_arice(@_)},
14             decodesub => sub {shift->get_arice(@_)}, };
15              
16 28     28   178 use Moo::Role;
  28         405  
  28         255  
17             requires qw(read write write_close put_unary get_unary);
18              
19             sub _ceillog2_arice {
20 0     0   0 my $d = $_[0] - 1;
21 0         0 my $base = 1;
22 0         0 $base++ while ($d >>= 1);
23 0         0 $base;
24             }
25              
26 28     28   12320 use constant _QLOW => 0;
  28         65  
  28         2055  
27 28     28   189 use constant _QHIGH => 7;
  28         84  
  28         22375  
28              
29             sub _adjust_k {
30 8011     8011   18203 my ($k, $q) = @_;
31 8011 100 100     33118 return $k-1 if $q <= _QLOW && $k > 0;
32 5687 100 100     23799 return $k+1 if $q >= _QHIGH && $k < 60;
33 3280         12418 $k;
34             }
35              
36             sub put_arice {
37 1077     1077 1 61779 my $self = shift;
38 1077 50       3261 my $sub = shift if ref $_[0] eq 'CODE'; ## no critic
39 1077         1859 my $kref = \shift;
40 1077         1877 my $k = $$kref;
41 1077 50       4564 $self->error_code('param', 'k must be >= 0') unless $k >= 0;
42              
43             # If small values are common (k often 0) then this will reduce the number
44             # of method calls required, which makes us run a little faster.
45 1077         2707 my @q_list;
46              
47 1077         2186 foreach my $val (@_) {
48 4010 100 100     31449 $self->error_code('zeroval') unless defined $val and $val >= 0;
49 4008 100       10195 if ($k == 0) {
50 25         42 push @q_list, $val;
51 25 100       96 $k++ if $val >= _QHIGH; # _adjust_k shortcut
52             } else {
53 3983         6261 my $q = $val >> $k;
54 3983         12894 my $r = $val - ($q << $k);
55 3983 100       7969 if (@q_list) {
56 1         2 push @q_list, $q;
57 1 50       11 (defined $sub) ? $sub->($self, @q_list) : $self->put_gamma(@q_list);
58 1         2 @q_list = ();
59             } else {
60 3982 50       29232 (defined $sub) ? $sub->($self, $q) : $self->put_gamma($q);
61             }
62 3983         11531 $self->write($k, $r);
63 3983         12004 $k = _adjust_k($k, $q);
64             }
65             }
66 1075 100       3038 if (@q_list) {
67 14 50       77 (defined $sub) ? $sub->($self, @q_list) : $self->put_gamma(@q_list);
68             }
69 1075         2031 $$kref = $k;
70 1075         3207 1;
71             }
72             sub get_arice {
73 1229     1229 1 14849 my $self = shift;
74 1229 50       3878 my $sub = shift if ref $_[0] eq 'CODE'; ## no critic
75 1229         2063 my $kref = \shift;
76 1229         2101 my $k = $$kref;
77 1229 50       3123 $self->error_code('param', 'k must be >= 0') unless $k >= 0;
78              
79 1229         1679 my $count = shift;
80 1229 100       3199 if (!defined $count) { $count = 1; }
  1076 100       1443  
    50          
81 24         44 elsif ($count < 0) { $count = ~0; } # Get everything
82 0         0 elsif ($count == 0) { return; }
83              
84 1229         1514 my @vals;
85 1229         6122 $self->code_pos_start('ARice');
86 1229         38503 while ($count-- > 0) {
87 4048         13027 $self->code_pos_set;
88             # Optimization: if possible (k==0), read two values at once.
89 4048         255511 my($q, $q1);
90 4048 100 100     19812 if ( ($k == 0) && ($count > 0) ) {
91 13 50       71 ($q1, $q) = (defined $sub) ? $sub->($self, 2) : $self->get_gamma(2);
92 13 100       45 last unless defined $q1;
93 10         19 push @vals, $q1;
94 10         31 $k = _adjust_k($k, $q1);
95 10         23 $count--;
96 10         32 $self->code_pos_set;
97             } else {
98 4035 50       16404 $q = (defined $sub) ? $sub->($self) : $self->get_gamma();
99             }
100 4040 100       9295 last unless defined $q;
101 4018 100       7409 if ($k == 0) {
102 15         20 push @vals, $q;
103             } else {
104 4003         12283 my $remainder = $self->read($k);
105 4003 50       19340 $self->error_off_stream unless defined $remainder;
106 4003         7276 push @vals, (($q << $k) | $remainder);
107             }
108 4018         8793 $k = _adjust_k($k, $q);
109             }
110 1224         4006 $self->code_pos_end;
111 1224         40134 $$kref = $k;
112 1224 100       6400 wantarray ? @vals : $vals[-1];
113             }
114 28     28   193 no Moo::Role;
  28         61  
  28         195  
115             1;
116              
117             # ABSTRACT: A Role implementing Adaptive Rice codes
118              
119             =pod
120              
121             =head1 NAME
122              
123             Data::BitStream::Code::ARice - A Role implementing Adaptive Rice codes
124              
125             =head1 VERSION
126              
127             version 0.08
128              
129             =head1 DESCRIPTION
130              
131             A role written for L that provides get and set methods for
132             Adaptive Rice codes. The role applies to a stream object.
133              
134             The default method used is to store the values using Gamma-Rice codes (also
135             called Exponential-Golomb codes). The upper C bits are stored in Elias
136             Gamma form, and the lower C bits are stored in binary. When C this
137             becomes Gamma coding.
138              
139             As each value is read or written, C is adjusted. If the upper value is
140             zero and C 0>, C is reduced. If the upper value is greater than
141             six and C 60>, C is increased. This simple method does a fairly
142             good job of keeping C in a useful range as incoming values vary.
143              
144             =head1 METHODS
145              
146             =head2 Provided Object Methods
147              
148             =over 4
149              
150             =item B< put_arice($k, $value) >
151              
152             =item B< put_arice($k, @values) >
153              
154             Insert one or more values as Rice codes with parameter C. The value of
155             C will change as values are inserted. Returns 1.
156              
157             The parameter C<$k> will be modified. Do not attempt to use a read-only value.
158              
159             =item B< put_arice(sub { ... }, $m, @values) >
160              
161             Insert one or more values as Rice codes using the user provided subroutine
162             instead of the Gamma code for the base. Traditional Rice codes:
163              
164             sub { shift->put_unary(@_); }
165              
166             Note that since the adaptive codes would be used when the input data is
167             changing, care should be taken with the code used for the upper bits. A
168             universal code is almost always recommended, which Unary is not. Something
169             like Gamma, Delta, Omega, Fibonacci, etc. will typically be a good choice.
170              
171             =item B< get_arice($k) >
172              
173             =item B< get_arice($k, $count) >
174              
175             Decode one or more Rice codes from the stream with adaptive C.
176             If count is omitted, one value will be read. If count is negative, values
177             will be read until the end of the stream is reached. In scalar context it
178             returns the last code read; in array context it returns an array of all
179             codes read.
180              
181             The parameter C<$k> will be modified. Do not attempt to use a read-only value.
182              
183             =item B< get_arice(sub { ... }, $k) >
184              
185             Similar to the regular get method except using the user provided subroutine
186             instead of Gamma encoding the base.
187              
188             =back
189              
190             =head2 Parameters
191              
192             The parameter C must be an integer greater than or equal to 0. It will
193             be modified by the routine, so do not use a read-only parameter.
194              
195             The quotient of CE k> is encoded using an Elias Gamma code
196             (or via the user supplied subroutine), followed by the lower C bits.
197              
198             The value of C is modified as values are read or written to keep the
199             number of upper bits reasonably low as the data changes.
200              
201             =head2 Required Methods
202              
203             =over 4
204              
205             =item B< read >
206              
207             =item B< write >
208              
209             =item B< get_gamma >
210              
211             =item B< put_gamma >
212              
213             These methods are required for the role.
214              
215             =back
216              
217             =head1 SEE ALSO
218              
219             =over 4
220              
221             =item L
222              
223             =item L
224              
225             =item L
226              
227             =item L
228              
229             =item L
230              
231             =back
232              
233             =head1 AUTHORS
234              
235             Dana Jacobsen
236              
237             =head1 COPYRIGHT
238              
239             Copyright 2011-2012 by Dana Jacobsen
240              
241             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
242              
243             =cut