File Coverage

blib/lib/Data/BitStream/Code/Baer.pm
Criterion Covered Total %
statement 74 75 98.6
branch 43 48 89.5
condition 10 12 83.3
subroutine 7 7 100.0
pod 2 2 100.0
total 136 144 94.4


line stmt bran cond sub pod time code
1             package Data::BitStream::Code::Baer;
2 28     28   30535 use strict;
  28         104  
  28         1221  
3 28     28   159 use warnings;
  28         53  
  28         1304  
4             BEGIN {
5 28     28   69 $Data::BitStream::Code::Baer::AUTHORITY = 'cpan:DANAJ';
6 28         2750 $Data::BitStream::Code::Baer::VERSION = '0.08';
7             }
8              
9             our $CODEINFO = { package => __PACKAGE__,
10             name => 'Baer',
11             universal => 1,
12             params => 1,
13             encodesub => sub {shift->put_baer(@_)},
14             decodesub => sub {shift->get_baer(@_)}, };
15              
16 28     28   157 use Moo::Role;
  28         52  
  28         188  
17             requires 'read', 'write', 'put_unary', 'get_unary';
18              
19             # Baer codes.
20             #
21             # Used for efficiently encoding data with a power law distribution.
22             #
23             # See: Michael B. Baer, "Prefix Codes for Power Laws," in IEEE International Symposium on Information Theory 2008 (ISIT 2008), pp 2464-2468, Toronto ON.
24             # https://hkn.eecs.berkeley.edu/~calbear/research/ISITuni.pdf
25              
26             sub put_baer {
27 2461     2461 1 50255 my $self = shift;
28 2461         3684 my $k = shift;
29 2461 50 33     16027 $self->error_code('param', 'k must be between -32 and 32') if $k > 32 || $k < -32;
30 2461 100       6224 my $mk = ($k < 0) ? int(-$k) : 0;
31              
32 2461         5652 foreach my $v (@_) {
33 10489 100 100     50959 $self->error_code('zeroval') unless defined $v and $v >= 0;
34 10483 100       21602 if ($v < $mk) {
35 264         891 $self->put_unary1($v);
36 264         550 next;
37             }
38 10219 100       26453 my $val = ($k==0) ? $v+1 : ($k < 0) ? $v-$mk+1 : 1+($v>>$k);
    100          
39 10219         10859 my $C = 0;
40 10219         10802 my $postword = 0;
41              
42             # This fixes range issues with k=0 and v=~0. Run one cycle using v.
43 10219 100 100     34173 if ( ($k == 0) && ($v >= 3) ) {
44 3205 100       6428 if (($v & 1) == 0) { $val = ($v - 2) >> 1; $postword = 1; }
  1068         1416  
  1068         1311  
45 2137         3409 else { $val = ($v - 1) >> 1; }
46 3205         3827 $C = 1;
47             }
48              
49 10219         39824 while ($val >= 4) {
50 130414 100       227872 if (($val & 1) == 0) { $val = ($val - 2) >> 1; }
  92816         97177  
51 37598         35934 else { $val = ($val - 3) >> 1; $postword |= (1 << $C); }
  37598         40920  
52 130414         226987 $C++;
53             }
54              
55 10219         42716 $self->put_unary1($C + $mk);
56 10219 100       24218 if ($val == 1) { $self->write(1, 0); }
  3798         10636  
57 6421         18882 else { $self->write(2, $val); }
58 10219 100       56328 $self->write($C, $postword) if $C > 0;
59 10219 100       31708 $self->write($k, $v) if $k > 0;
60             }
61 2455         15690 1;
62             }
63              
64             sub get_baer {
65 2523     2523 1 42573 my $self = shift;
66 2523         3722 my $k = shift;
67 2523 100 100     13401 $self->error_code('param', 'k must be between -32 and 32') if $k > 32 || $k < -32;
68 2521 100       7141 my $mk = ($k < 0) ? int(-$k) : 0;
69              
70 2521         3222 my $count = shift;
71 2521 100       5229 if (!defined $count) { $count = 1; }
  2449 50       5325  
    0          
72 72         138 elsif ($count < 0) { $count = ~0; } # Get everything
73 0         0 elsif ($count == 0) { return; }
74              
75 2521         3189 my @vals;
76 2521         8155 my $maxbits = $self->maxbits;
77 2521         7983 $self->code_pos_start('Baer');
78 2521         99665 while ($count-- > 0) {
79 10621         31153 $self->code_pos_set;
80 10621         1518959 my $C = $self->get_unary1;
81 10618 100       24966 last unless defined $C;
82 10543 100       22343 if ($C < $mk) {
83 276         456 push @vals, $C;
84 276         998 next;
85             }
86 10267         11372 $C -= $mk;
87 10267 50       19446 $self->error_code('overflow') if $C > $maxbits;
88 10267 100       40876 my $val = ($self->read(1) == 0) ? 1 : 2 + $self->read(1);
89              
90             # Code following the logic in the paper:
91             #
92             # while ($C-- > 0) { $val = 2 * $val + 2 + $self->read(1); }
93             # $val += $mk;
94             # if ($k > 0) { $val = ( (($val-1) << $k) | $self->read($k) ); }
95             # $val -= 1; # to get back to 0-base from paper's 1-base;
96             #
97             # We can unroll the while loop, and be careful with overflow of ~0
98              
99 10267         16743 $val = ($val << $C) + $mk - 1;
100 10267 100       20741 if ($C > 0) { $val += ((1 << ($C+1)) - 2) + $self->read($C); }
  9438         28357  
101 10267 100       27549 if ($k > 0) { $val = ( ($val << $k) | $self->read($k) ); }
  3515         10586  
102              
103 10267         28895 push @vals, $val;
104             }
105 2518         7502 $self->code_pos_end;
106 2518 100       108209 wantarray ? @vals : $vals[-1];
107             }
108 28     28   29750 no Moo::Role;
  28         75  
  28         304  
109             1;
110              
111             # ABSTRACT: A Role implementing Michael B. Baer's power law codes
112              
113             =pod
114              
115             =head1 NAME
116              
117             Data::BitStream::Code::Baer - A Role implementing Baer codes
118              
119             =head1 VERSION
120              
121             version 0.08
122              
123             =head1 DESCRIPTION
124              
125             A role written for L that provides get and set methods for
126             the power law codes of Michael B. Baer. The role applies to a stream object.
127              
128             =head1 METHODS
129              
130             =head2 Provided Object Methods
131              
132             =over 4
133              
134             =item B< put_baer($k, $value) >
135              
136             =item B< put_baer($k, @values) >
137              
138             Insert one or more values as Baer c_k codes. Returns 1.
139              
140             =item B< get_baer($k) >
141              
142             =item B< get_baer($k, $count) >
143              
144             Decode one or more Baer c_k codes from the stream. If count is omitted,
145             one value will be read. If count is negative, values will be read until
146             the end of the stream is reached. In scalar context it returns the last
147             code read; in array context it returns an array of all codes read.
148              
149             =back
150              
151             =head2 Parameters
152              
153             The parameter k cannot be more than 32.
154              
155             C is the base c_0 code.
156              
157             C0> performs unary (1-based) coding of small values followed
158             by c_0 coding the remainder (C) for large values. This works well
159             when the probability of small values is much higher than larger values.
160              
161             C0> is similar to a Rice(k) code in that we encode
162             CEk)> followed by encoding the bottom k bits of value.
163             This works well when most values are medium-sized.
164              
165             Typical k values are between -6 and 6.
166              
167             =head2 Required Methods
168              
169             =over 4
170              
171             =item B< read >
172              
173             =item B< write >
174              
175             =item B< get_unary1 >
176              
177             =item B< put_unary1 >
178              
179             These methods are required for the role.
180              
181             =back
182              
183             =head1 SEE ALSO
184              
185             =over 4
186              
187             =item Michael B. Baer, "Prefix Codes for Power Laws," in IEEE International Symposium on Information Theory 2008 (ISIT 2008), pp 2464-2468, Toronto ON.
188              
189             =item L
190              
191             =back
192              
193             =head1 AUTHORS
194              
195             Dana Jacobsen
196              
197             =head1 COPYRIGHT
198              
199             Copyright 2011 by Dana Jacobsen
200              
201             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
202              
203             =cut