line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::BitStream::Code::Taboo; |
2
|
28
|
|
|
28
|
|
26266
|
use strict; |
|
28
|
|
|
|
|
73
|
|
|
28
|
|
|
|
|
1324
|
|
3
|
28
|
|
|
28
|
|
162
|
use warnings; |
|
28
|
|
|
|
|
59
|
|
|
28
|
|
|
|
|
1470
|
|
4
|
|
|
|
|
|
|
BEGIN { |
5
|
28
|
|
|
28
|
|
76
|
$Data::BitStream::Code::Taboo::AUTHORITY = 'cpan:DANAJ'; |
6
|
28
|
|
|
|
|
3130
|
$Data::BitStream::Code::Taboo::VERSION = '0.08'; |
7
|
|
|
|
|
|
|
} |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
our $CODEINFO = { package => __PACKAGE__, |
10
|
|
|
|
|
|
|
name => 'BlockTaboo', |
11
|
|
|
|
|
|
|
universal => 1, |
12
|
|
|
|
|
|
|
params => 1, |
13
|
|
|
|
|
|
|
encodesub => sub {shift->put_blocktaboo(@_)}, |
14
|
|
|
|
|
|
|
decodesub => sub {shift->get_blocktaboo(@_)}, }; |
15
|
|
|
|
|
|
|
|
16
|
28
|
|
|
28
|
|
172
|
use Moo::Role; |
|
28
|
|
|
|
|
93
|
|
|
28
|
|
|
|
|
210
|
|
17
|
|
|
|
|
|
|
requires qw(read write); |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub put_blocktaboo { |
20
|
1632
|
|
|
1632
|
1
|
32505
|
my $self = shift; |
21
|
1632
|
50
|
|
|
|
5020
|
$self->error_stream_mode('write') unless $self->writing; |
22
|
1632
|
|
|
|
|
2493
|
my $taboostr = shift; |
23
|
1632
|
50
|
|
|
|
4483
|
$self->error_code('param', 'taboo must be a binary string') if $taboostr =~ tr/01//c; |
24
|
1632
|
|
|
|
|
2955
|
my $bits = length($taboostr); |
25
|
1632
|
50
|
33
|
|
|
8645
|
$self->error_code('param', 'taboo length must be in range 1-16') unless $bits >= 1 && $bits <= 16; |
26
|
1632
|
|
|
|
|
4133
|
my $taboo = oct("0b$taboostr"); |
27
|
|
|
|
|
|
|
|
28
|
1632
|
50
|
|
|
|
3582
|
if ($bits == 1) { |
29
|
0
|
0
|
|
|
|
0
|
return ($taboo == 1) ? $self->put_unary(@_) : $self->put_unary1(@_); |
30
|
|
|
|
|
|
|
} |
31
|
|
|
|
|
|
|
|
32
|
1632
|
|
|
|
|
3484
|
my $base = 2**$bits - 1; # The base of the digits we're writing |
33
|
|
|
|
|
|
|
|
34
|
1632
|
|
|
|
|
3394
|
foreach my $val (@_) { |
35
|
4686
|
100
|
100
|
|
|
45631
|
$self->error_code('zeroval') unless defined $val and $val >= 0; |
36
|
|
|
|
|
|
|
|
37
|
4682
|
100
|
|
|
|
10743
|
if ($val == 0) { $self->write($bits, $taboo); next; } |
|
153
|
|
|
|
|
1017
|
|
|
153
|
|
|
|
|
406
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# val code |
40
|
|
|
|
|
|
|
# 0 00 |
41
|
|
|
|
|
|
|
# 1 0100 base^0 |
42
|
|
|
|
|
|
|
# 2 1000 |
43
|
|
|
|
|
|
|
# 3 1100 |
44
|
|
|
|
|
|
|
# 4 010100 base^1+base^0 |
45
|
|
|
|
|
|
|
# 12 111100 |
46
|
|
|
|
|
|
|
# 13 01010100 base^2+base^1+base^0 |
47
|
|
|
|
|
|
|
# 39 11111100 |
48
|
|
|
|
|
|
|
# 40 0101010100 base^3+base^2+base^1+base^0 |
49
|
|
|
|
|
|
|
# 121 010101010100 base^4+base^3+base^2+base^1+base^0 |
50
|
|
|
|
|
|
|
|
51
|
4529
|
|
|
|
|
5620
|
my $lbase = 0; |
52
|
4529
|
|
|
|
|
5198
|
my $baseval = 1; # $base**0 |
53
|
4529
|
|
|
|
|
12925
|
while ($val >= ($baseval + $base**($lbase+1))) { |
54
|
9443
|
|
|
|
|
9948
|
$lbase++; |
55
|
9443
|
|
|
|
|
21123
|
$baseval += $base**$lbase; |
56
|
|
|
|
|
|
|
} |
57
|
4529
|
|
|
|
|
6310
|
my $v = $val - $baseval; |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# block-at-a-time way: |
60
|
|
|
|
|
|
|
# foreach my $i (reverse 0 .. $lbase) { |
61
|
|
|
|
|
|
|
# my $factor = $base ** $i; |
62
|
|
|
|
|
|
|
# my $digit = int($v / $factor); |
63
|
|
|
|
|
|
|
# $v -= $digit * $factor; |
64
|
|
|
|
|
|
|
# $digit++ if $digit >= $taboo; # Make room for the taboo chunk |
65
|
|
|
|
|
|
|
# $self->write($bits, $digit); |
66
|
|
|
|
|
|
|
# } |
67
|
|
|
|
|
|
|
# $self->write($bits, $taboo); |
68
|
|
|
|
|
|
|
# combine blocks into 32-bit writes: |
69
|
4529
|
|
|
|
|
9892
|
my @stack = ($taboo); |
70
|
4529
|
|
|
|
|
11349
|
foreach my $i (0 .. $lbase) { |
71
|
13972
|
|
|
|
|
20772
|
my $digit = $v % $base; |
72
|
13972
|
100
|
|
|
|
27609
|
$digit++ if $digit >= $taboo; # Make room for the taboo chunk |
73
|
13972
|
|
|
|
|
22064
|
push @stack, $digit; |
74
|
13972
|
|
|
|
|
38339
|
$v = int($v / $base); |
75
|
|
|
|
|
|
|
} |
76
|
4529
|
|
|
|
|
7939
|
my $cword = 0; |
77
|
4529
|
|
|
|
|
4941
|
my $cbits = 0; |
78
|
4529
|
|
|
|
|
10050
|
while (@stack) { |
79
|
18501
|
|
|
|
|
33436
|
$cword = ($cword << $bits) | pop @stack; |
80
|
18501
|
|
|
|
|
22098
|
$cbits += $bits; |
81
|
18501
|
50
|
|
|
|
59380
|
if (($cbits + $bits) > 32) { |
82
|
0
|
|
|
|
|
0
|
$self->write($cbits, $cword); |
83
|
0
|
|
|
|
|
0
|
$cword = 0; |
84
|
0
|
|
|
|
|
0
|
$cbits = 0; |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
} |
87
|
4529
|
50
|
|
|
|
21482
|
$self->write($cbits, $cword) if $cbits; |
88
|
|
|
|
|
|
|
} |
89
|
1628
|
|
|
|
|
4780
|
1; |
90
|
|
|
|
|
|
|
} |
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
sub get_blocktaboo { |
93
|
1673
|
|
|
1673
|
1
|
27830
|
my $self = shift; |
94
|
1673
|
50
|
|
|
|
5848
|
$self->error_stream_mode('read') if $self->writing; |
95
|
1673
|
|
|
|
|
2533
|
my $taboostr = shift; |
96
|
1673
|
50
|
|
|
|
8661
|
$self->error_code('param', 'taboo must be a binary string') if $taboostr =~ tr/01//c; |
97
|
1673
|
|
|
|
|
2945
|
my $bits = length($taboostr); |
98
|
1673
|
50
|
33
|
|
|
8552
|
$self->error_code('param', 'taboo length must be in range 1-16') unless $bits >= 1 && $bits <= 16; |
99
|
1673
|
|
|
|
|
3914
|
my $taboo = oct("0b$taboostr"); |
100
|
|
|
|
|
|
|
|
101
|
1673
|
50
|
|
|
|
3596
|
if ($bits == 1) { |
102
|
0
|
0
|
|
|
|
0
|
return ($taboo == 1) ? $self->get_unary(@_) : $self->get_unary1(@_); |
103
|
|
|
|
|
|
|
} |
104
|
1673
|
|
|
|
|
3115
|
my $base = 2**$bits - 1; # The base of the digits we're writing |
105
|
|
|
|
|
|
|
|
106
|
1673
|
|
|
|
|
2432
|
my $count = shift; |
107
|
1673
|
100
|
|
|
|
3754
|
if (!defined $count) { $count = 1; } |
|
1631
|
50
|
|
|
|
2654
|
|
|
|
0
|
|
|
|
|
|
108
|
42
|
|
|
|
|
72
|
elsif ($count < 0) { $count = ~0; } # Get everything |
109
|
0
|
|
|
|
|
0
|
elsif ($count == 0) { return; } |
110
|
|
|
|
|
|
|
|
111
|
1673
|
|
|
|
|
1910
|
my @vals; |
112
|
1673
|
|
|
|
|
5317
|
$self->code_pos_start('Block Taboo'); |
113
|
1673
|
|
|
|
|
54009
|
while ($count-- > 0) { |
114
|
4769
|
|
|
|
|
20477
|
$self->code_pos_set; |
115
|
4769
|
|
|
|
|
217835
|
my $tval = $self->read($bits); |
116
|
4769
|
100
|
|
|
|
12319
|
last unless defined $tval; |
117
|
|
|
|
|
|
|
|
118
|
4725
|
|
|
|
|
15368
|
my $val = 0; |
119
|
4725
|
|
|
|
|
6029
|
my $baseval = 0; |
120
|
4725
|
|
|
|
|
5984
|
my $n = 0; |
121
|
4725
|
|
|
|
|
19837
|
while ($tval != $taboo) { |
122
|
14271
|
100
|
|
|
|
41051
|
my $digit = ($tval > $taboo) ? $tval-1 : $tval; |
123
|
14271
|
|
|
|
|
46796
|
$val = $base * $val + $digit; |
124
|
14271
|
|
|
|
|
26808
|
$baseval += $base**$n; |
125
|
14271
|
|
|
|
|
14757
|
$n++; |
126
|
14271
|
100
|
|
|
|
31582
|
$self->error_code('overflow') if ($val+$baseval) > ~0; |
127
|
14259
|
|
|
|
|
42208
|
$tval = $self->read($bits); |
128
|
14258
|
100
|
|
|
|
50923
|
$self->error_off_stream unless defined $tval; |
129
|
|
|
|
|
|
|
} |
130
|
4711
|
|
|
|
|
17896
|
push @vals, $val+$baseval; |
131
|
|
|
|
|
|
|
} |
132
|
1659
|
|
|
|
|
4573
|
$self->code_pos_end; |
133
|
1659
|
100
|
|
|
|
58556
|
wantarray ? @vals : $vals[-1]; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
28
|
|
|
28
|
|
35571
|
no Moo::Role; |
|
28
|
|
|
|
|
90
|
|
|
28
|
|
|
|
|
169
|
|
137
|
|
|
|
|
|
|
1; |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
# ABSTRACT: A Role implementing Taboo codes |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=pod |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
=head1 NAME |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
Data::BitStream::Code::Taboo - A Role implementing Taboo codes |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 VERSION |
148
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
version 0.08 |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=head1 DESCRIPTION |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
A role written for L that provides get and set methods for |
154
|
|
|
|
|
|
|
Taboo codes. The role applies to a stream object. |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Taboo codes are described in Steven Pigeon's 2001 PhD Thesis as well as his |
157
|
|
|
|
|
|
|
paper "Taboo Codes: New Classes of Universal Codes." |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
The block methods implement a slight modification of the taboo codes, wherein |
160
|
|
|
|
|
|
|
zero is encoded as the taboo pattern with no preceding bits. This causes no |
161
|
|
|
|
|
|
|
loss of generality and lowers the bit count for small values. |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
An example using '11' as the taboo pattern (chunk size C): |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
value code binary bits |
166
|
|
|
|
|
|
|
0 t 11 2 |
167
|
|
|
|
|
|
|
1 0t 0011 4 |
168
|
|
|
|
|
|
|
2 1t 0111 4 |
169
|
|
|
|
|
|
|
3 2t 1011 4 |
170
|
|
|
|
|
|
|
4 00t 000011 6 |
171
|
|
|
|
|
|
|
.. 12 22t 101011 6 |
172
|
|
|
|
|
|
|
13 000t 00000011 8 |
173
|
|
|
|
|
|
|
.. 64 0220t 0010100011 10 |
174
|
|
|
|
|
|
|
.. 10000 000012220t 00000000011010100011 20 |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
These codes are a more efficient version of comma codes, as they allow leading |
177
|
|
|
|
|
|
|
zeros. |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
The unconstrained taboo codes are not implemented yet. However, the |
180
|
|
|
|
|
|
|
generalized Fibonacci codes are a special case of taboo codes (using a taboo |
181
|
|
|
|
|
|
|
pattern of all ones and a different bit ordering). The lengths of the codes |
182
|
|
|
|
|
|
|
will be identical in all cases, so it is recommended to use them if possible. |
183
|
|
|
|
|
|
|
What unconstrained taboo codes offer over generalized Fibonacci codes is the |
184
|
|
|
|
|
|
|
ability to have any ending pattern and having the prefix be lexicographically |
185
|
|
|
|
|
|
|
ordered. For most purposes these are not important. |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 METHODS |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head2 Provided Object Methods |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
=over 4 |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=item B< put_blocktaboo($taboo, $value) > |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item B< put_blocktaboo($taboo, @values) > |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
Insert one or more values as block taboo codes using the binary string |
198
|
|
|
|
|
|
|
C<$taboo> as the terminator. Returns 1. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
=item B< get_blocktaboo($taboo) > |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item B< get_blocktaboo($taboo, $count) > |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
Decode one or more block taboo codes from the stream. If count is omitted, |
205
|
|
|
|
|
|
|
one value will be read. If count is negative, values will be read until |
206
|
|
|
|
|
|
|
the end of the stream is reached. In scalar context it returns the last |
207
|
|
|
|
|
|
|
code read; in array context it returns an array of all codes read. |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=back |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
=head2 Parameters |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
The parameter C is a binary string, meaning it is a string comprised |
214
|
|
|
|
|
|
|
exclusively of C<'0'> and C<'1'> characters. The length is the chunk size in |
215
|
|
|
|
|
|
|
bits, and must be between 1 and 16. Using C<'00'> gives the codes from |
216
|
|
|
|
|
|
|
table 2 of Pigeon's paper (where the chunk size C and the taboo pattern |
217
|
|
|
|
|
|
|
is the two-bits C<'00'>). |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
If C is C<'0'> then one-based unary coding is used (e.g. a string of |
220
|
|
|
|
|
|
|
C<1> bits followed by a C<0>). |
221
|
|
|
|
|
|
|
If C is C<'1'> then zero-based unary coding is used (e.g. a string of |
222
|
|
|
|
|
|
|
C<0> bits followed by a C<1>). |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
=head2 Required Methods |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
=over 4 |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=item B< read > |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
=item B< write > |
231
|
|
|
|
|
|
|
|
232
|
|
|
|
|
|
|
These methods are required for the role. |
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
=back |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
=head1 SEE ALSO |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
=over 4 |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
=item Steven Pigeon, "Taboo Codes: New Classes of Universal Codes", 2001. |
241
|
|
|
|
|
|
|
|
242
|
|
|
|
|
|
|
=item L |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=back |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
=head1 AUTHORS |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
Dana Jacobsen |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
=head1 COPYRIGHT |
251
|
|
|
|
|
|
|
|
252
|
|
|
|
|
|
|
Copyright 2012 by Dana Jacobsen |
253
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
=cut |