File Coverage

blib/lib/Data/BitStream/Code/Escape.pm
Criterion Covered Total %
statement 14 72 19.4
branch 0 46 0.0
condition 0 15 0.0
subroutine 5 7 71.4
pod 2 2 100.0
total 21 142 14.7


line stmt bran cond sub pod time code
1             package Data::BitStream::Code::Escape;
2 1     1   2788 use strict;
  1         3  
  1         45  
3 1     1   5 use warnings;
  1         2  
  1         54  
4             BEGIN {
5 1     1   4 $Data::BitStream::Code::Escape::AUTHORITY = 'cpan:DANAJ';
6 1         136 $Data::BitStream::Code::Escape::VERSION = '0.08';
7             }
8              
9             our $CODEINFO = { package => __PACKAGE__,
10             name => 'Escape',
11             universal => 1,
12             params => 1,
13             encodesub => sub {put_escape(shift,[split('-',shift)], @_)},
14             decodesub => sub {get_escape(shift,[split('-',shift)], @_)}, };
15              
16 1     1   13 use Moo::Role;
  1         2  
  1         11  
17             requires qw(read write maxbits);
18              
19             # Escape code. Similar to Start/Stop codes, but rather than encoding the
20             # prefix in unary, a maximum value in a block (binary all 1's) indicates we
21             # move to the next block.
22             #
23             # The parameter comes in as an array. Hence:
24             #
25             # $stream->put_escape( [3,5,9,32], $value );
26             #
27             # $stream->get_escape( [3,5,9,32], $value );
28             #
29             # A parameter of undef means maxbits.
30              
31             sub put_escape {
32 0     0 1   my $self = shift;
33 0 0         $self->error_stream_mode('write') unless $self->writing;
34 0           my $p = shift;
35 0 0 0       $self->error_code('param', 'p must be an array') unless (ref $p eq 'ARRAY') && scalar @$p >= 1;
36              
37 0           my $maxbits = $self->maxbits;
38 0 0 0       my @parray = map { (defined $_ && $_ <= $maxbits) ? $_ : $maxbits } @$p;
  0            
39 0           foreach my $p (@parray) {
40 0 0         $self->error_code('param', 'p entries must be > 0') if $p <= 0;
41             }
42              
43 0           foreach my $val (@_) {
44 0 0 0       $self->error_code('zeroval') unless defined $val and $val >= 0;
45 0           my @bitarray = @parray;
46 0           my $bits = shift @bitarray;
47 0           my $min = 0;
48 0 0         my $maxval = ($bits < $maxbits) ? (1<<$bits)-2 : ~0-1;
49 0           my $onebits = 0;
50              
51             #print "[$onebits]: $bits bits range $min - ", $min+$maxval, "\n";
52 0           while ( ($val-$min) > $maxval ) {
53 0           $onebits += $bits;
54 0           $min += $maxval+1;
55 0 0         $self->error_code('range', $val, 0, $maxval) if scalar @bitarray == 0;
56 0           $bits = shift @bitarray;
57 0 0         $maxval = ($bits < $maxbits) ? (1<<$bits)-2 : ~0-1;
58 0 0         $maxval++ if scalar @bitarray == 0;
59             #print "[$onebits]: $bits bits range $min - ", $min+$maxval, "\n";
60             }
61 0           while ($onebits > 32) { $self->write(32, 0xFFFFFFFF); $onebits -= 32; }
  0            
  0            
62 0 0         if ($onebits > 0) { $self->write($onebits, 0xFFFFFFFF); }
  0            
63 0 0         $self->write($bits, $val-$min) if $bits > 0;
64             }
65 0           1;
66             }
67              
68             sub get_escape {
69 0     0 1   my $self = shift;
70 0 0         $self->error_stream_mode('read') if $self->writing;
71 0           my $p = shift;
72 0 0 0       $self->error_code('param', 'p must be an array') unless (ref $p eq 'ARRAY') && scalar @$p >= 1;
73 0           my $count = shift;
74 0 0         if (!defined $count) { $count = 1; }
  0 0          
    0          
75 0           elsif ($count < 0) { $count = ~0; } # Get everything
76 0           elsif ($count == 0) { return; }
77              
78 0           my $maxbits = $self->maxbits;
79 0 0 0       my @parray = map { (defined $_ && $_ <= $maxbits) ? $_ : $maxbits } @$p;
  0            
80 0           foreach my $p (@parray) {
81 0 0         $self->error_code('param', 'p entries must be > 0') if $p <= 0;
82             }
83              
84 0           my @vals;
85 0           while ($count-- > 0) {
86 0           my @bitarray = @parray;
87 0           my($min,$maxval,$bits,$v) = (-1,0,0,0);
88 0           do {
89 0           $min += $maxval+1;
90 0 0         $self->error_code('overflow') if scalar @bitarray == 0;
91 0           $bits = shift @bitarray;
92 0 0         $maxval = ($bits < $maxbits) ? (1<<$bits)-2 : ~0-1;
93 0 0         $maxval++ if scalar @bitarray == 0;
94 0           $v = $self->read($bits);
95 0 0         last unless defined $v;
96             #print "read $bits bits, maxval = $maxval, v = $v, val = ", $v+$min, "\n";
97             } while ($v == ($maxval+1));
98 0           push @vals, $min+$v;
99             }
100 0 0         wantarray ? @vals : $vals[-1];
101             }
102 1     1   1084 no Moo::Role;
  1         2  
  1         7  
103             1;
104              
105             # ABSTRACT: A Role implementing Escape codes
106              
107             =pod
108              
109             =head1 NAME
110              
111             Data::BitStream::Code::Escape - A Role implementing Escape codes
112              
113             =head1 VERSION
114              
115             version 0.08
116              
117             =head1 DESCRIPTION
118              
119             A role written for L that provides get and set methods for
120             Escape codes. The role applies to a stream object.
121              
122             An Escape code is a code where a binary value is read using C bits
123             (C= 1>), and if the read value is equal to C<2^m-1>,
124             then another C bits is read (C= 1>), etc. They are somewhat similar
125             to Start/Stop codes, though use an escape value inside each block instead of
126             a unary indicator. For example a 3-7 code would look like:
127              
128             0 000
129             1 001
130             2 010
131             ...
132             6 110
133             7 1110000000
134             8 1110000001
135             ...
136             134 1111111111
137              
138             These codes are not uncommon in a variety of applications where extremely
139             simple variable length coding is desired, but for various reasons none of
140             the more sophisticated methods are used. These codes can be quite useful
141             for some cases such as a 8-32 code which encodes 0-254 in one byte and
142             values greater than 254 in five bytes. Based on the frequencies and
143             implementation, this may be more desirable than other methods such as a
144             startstop(7-25) code which encodes 0-127 in one byte and values greater
145             than 127 in four bytes.
146              
147             For many cases, and almost all where more than two parameters are used,
148             Start/Stop codes will be more space efficient.
149              
150              
151             =head1 EXAMPLES
152              
153             use Data::BitStream;
154             my $stream = Data::BitStream->new;
155             my @array = (4, 2, 0, 3, 7, 72, 0, 1, 13);
156              
157             $stream->put_escape( [3,7], @array );
158             $stream->rewind_for_read;
159             my @array2 = $stream->get_escape( [3,7], -1);
160              
161             # @array equals @array2
162              
163             =head1 METHODS
164              
165             =head2 Provided Object Methods
166              
167             =over 4
168              
169             =item B< put_escape([@m], $value) >
170              
171             =item B< put_escape([@m], @values) >
172              
173             Insert one or more values as Escape codes. Returns 1.
174              
175             =item B< get_escape([@m]) >
176              
177             =item B< get_escape([@m], $count) >
178              
179             Decode one or more Escape codes from the stream. If count is omitted,
180             one value will be read. If count is negative, values will be read until
181             the end of the stream is reached. In scalar context it returns the last
182             code read; in array context it returns an array of all codes read.
183              
184             =back
185              
186             =head2 Parameters
187              
188             The Escape parameters are passed as a array reference.
189              
190             There must be at least one parameter. Each parameter must be greater than
191             or equal to zero. Each value is the number of bits in the block.
192              
193             =head2 Required Methods
194              
195             =over 4
196              
197             =item B< maxbits >
198              
199             =item B< read >
200              
201             =item B< write >
202              
203             These methods are required for the role.
204              
205             =back
206              
207             =head1 SEE ALSO
208              
209             =over 4
210              
211             =item L
212              
213             =back
214              
215             =head1 AUTHORS
216              
217             Dana Jacobsen
218              
219             =head1 COPYRIGHT
220              
221             Copyright 2011 by Dana Jacobsen
222              
223             This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
224              
225             =cut