File Coverage

blib/lib/Data/BitStream/Code/Gamma.pm
Criterion Covered Total %
statement 55 56 98.2
branch 31 34 91.1
condition 1 3 33.3
subroutine 7 7 100.0
pod 2 2 100.0
total 96 102 94.1


line stmt bran cond sub pod time code
1             package Data::BitStream::Code::Gamma;
2 28     28   32916 use strict;
  28         69  
  28         1193  
3 28     28   171 use warnings;
  28         58  
  28         1641  
4             BEGIN {
5 28     28   86 $Data::BitStream::Code::Gamma::AUTHORITY = 'cpan:DANAJ';
6 28         3036 $Data::BitStream::Code::Gamma::VERSION = '0.08';
7             }
8              
9             our $CODEINFO = { package => __PACKAGE__,
10             name => 'Gamma',
11             universal => 1,
12             params => 0,
13             encodesub => sub {shift->put_gamma(@_)},
14             decodesub => sub {shift->get_gamma(@_)}, };
15              
16 28     28   183 use Moo::Role;
  28         70  
  28         265  
17             requires qw(maxbits read write put_unary get_unary);
18              
19             # Elias Gamma code.
20             #
21             # Store the number of binary bits in Unary code, then the value in binary
22             # excepting the top bit which is known from the unary code.
23             #
24             # Like Unary, this encoding is used as a component of many other codes.
25             # Hence it is not unreasonable for a base Bitstream class to code this
26             # if it can make a substantially faster implementation. Also this class
27             # is assumed to be part of the base class, so no 'with Gamma' needs or should
28             # be done. It is done by the base classes if needed.
29              
30             # To calculate the length of gamma($n):
31             # my $gammalen = 1; $gammalen += 2 while ( $n >= ((2 << ($gammalen>>1))-1) );
32              
33             sub put_gamma {
34 11064     11064 1 39506 my $self = shift;
35 11064 50       31448 $self->error_stream_mode('write') unless $self->writing;
36 11064         30541 my $maxval = $self->maxval;
37              
38 11064         21712 foreach my $val (@_) {
39 14413 50 33     67421 $self->error_code('zeroval') unless defined $val and $val >= 0;
40             # Simple:
41             #
42             # my $base = 0;
43             # { my $v = $val+1; $base++ while ($v >>= 1); }
44             # $self->put_unary($base);
45             # $self->write($base, $val+1) if $base > 0;
46             #
47             # More optimized, and handles encoding 0 - ~0
48 14413 100       47418 if ($val == 0) { $self->write(1, 1); }
  2030 100       6374  
    100          
    100          
49 824         2506 elsif ($val == 1) { $self->write(3, 2); } # optimization
50 575         1756 elsif ($val == 2) { $self->write(3, 3); } # optimization
51 2         8 elsif ($val == $maxval) { $self->put_unary($self->maxbits); }
52             else {
53 10982         13346 my $base = 0;
54 10982         13086 { my $v = $val+1; $base++ while ($v >>= 1); }
  10982         13671  
  10982         119069  
55 10982 100       31188 if ($base < 16) {
56 9494         64890 $self->write( $base+1+$base, (1<<$base) | ($val+1) );
57             } else {
58 1488         4473 $self->put_unary($base); # Unary code the base
59 1488         4751 $self->write($base, $val+1);
60             }
61             }
62             }
63 11064         29854 1;
64             }
65              
66             sub get_gamma {
67 25131     25131 1 97296 my $self = shift;
68 25131 100       80520 $self->error_stream_mode('read') if $self->writing;
69 25130         34577 my $count = shift;
70 25130 100       64890 if (!defined $count) { $count = 1; }
  22190 100       28106  
    50          
71 22         49 elsif ($count < 0) { $count = ~0; } # Get everything
72 0         0 elsif ($count == 0) { return; }
73              
74 25130         80860 my $maxbits = $self->maxbits;
75 25130         31940 my @vals;
76 25130         64519 $self->code_pos_start('Gamma');
77 25130         789291 while ($count-- > 0) {
78 35756         104550 $self->code_pos_set;
79 35756         1215245 my $base = $self->get_unary();
80 35741 100       82768 last unless defined $base;
81 35543 100       125259 if ($base == 0) { push @vals, 0; }
  4671 100       13726  
    100          
82 4         16 elsif ($base == $maxbits) { push @vals, $self->maxval; }
83 5         23 elsif ($base > $maxbits) { $self->error_code('base', $base); }
84             else {
85 30863         107727 my $remainder = $self->read($base);
86 30863 100       67386 $self->error_off_stream unless defined $remainder;
87 30858         116787 push @vals, ((1 << $base) | $remainder)-1;
88             }
89             }
90 25105         76789 $self->code_pos_end;
91 25105 100       1737290 wantarray ? @vals : $vals[-1];
92             }
93 28     28   26917 no Moo::Role;
  28         60  
  28         207  
94             1;
95              
96             # ABSTRACT: A Role implementing Elias Gamma codes
97              
98             =pod
99              
100             =head1 NAME
101              
102             Data::BitStream::Code::Gamma - A Role implementing Elias Gamma codes
103              
104             =head1 VERSION
105              
106             version 0.08
107              
108             =head1 DESCRIPTION
109              
110             A role written for L that provides get and set methods for
111             the Elias Gamma codes. The role applies to a stream object.
112              
113             This is a very common and very useful code, and is used to create some other
114             codes (e.g. Elias Delta, Gamma-Golomb, and Exponential-Golomb).
115              
116             =head1 METHODS
117              
118             =head2 Provided Object Methods
119              
120             =over 4
121              
122             =item B< put_gamma($value) >
123              
124             =item B< put_gamma(@values) >
125              
126             Insert one or more values as Gamma codes. Returns 1.
127              
128             =item B< get_gamma() >
129              
130             =item B< get_gamma($count) >
131              
132             Decode one or more Gamma codes from the stream. If count is omitted,
133             one value will be read. If count is negative, values will be read until
134             the end of the stream is reached. In scalar context it returns the last
135             code read; in array context it returns an array of all codes read.
136              
137             =back
138              
139             =head2 Required Methods
140              
141             =over 4
142              
143             =item B< maxbits >
144              
145             =item B< read >
146              
147             =item B< write >
148              
149             =item B< put_unary >
150              
151             =item B< get_unary >
152              
153             These methods are required for the role.
154              
155             =back
156              
157             =head1 SEE ALSO
158              
159             =over 4
160              
161             =item Peter Elias, "Universal codeword sets and representations of the integers", IEEE Trans. Information Theory 21(2), pp. 194-203, Mar 1975.
162              
163             =item Peter Fenwick, "Punctured Elias Codes for variable-length coding of the integers", Technical Report 137, Department of Computer Science, University of Auckland, December 1996
164              
165             =back
166              
167             =head1 AUTHORS
168              
169             Dana Jacobsen
170              
171             =head1 COPYRIGHT
172              
173             Copyright 2011 by Dana Jacobsen
174              
175             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
176              
177             =cut