line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::BitStream::WordVec; |
2
|
28
|
|
|
28
|
|
27824
|
use strict; |
|
28
|
|
|
|
|
71
|
|
|
28
|
|
|
|
|
1213
|
|
3
|
28
|
|
|
28
|
|
170
|
use warnings; |
|
28
|
|
|
|
|
51
|
|
|
28
|
|
|
|
|
1515
|
|
4
|
|
|
|
|
|
|
BEGIN { |
5
|
28
|
|
|
28
|
|
658
|
$Data::BitStream::WordVec::AUTHORITY = 'cpan:DANAJ'; |
6
|
|
|
|
|
|
|
} |
7
|
|
|
|
|
|
|
BEGIN { |
8
|
28
|
|
|
28
|
|
442
|
$Data::BitStream::WordVec::VERSION = '0.08'; |
9
|
|
|
|
|
|
|
} |
10
|
|
|
|
|
|
|
|
11
|
28
|
|
|
28
|
|
148
|
use Moo; |
|
28
|
|
|
|
|
47
|
|
|
28
|
|
|
|
|
190
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
with 'Data::BitStream::Base', |
14
|
|
|
|
|
|
|
'Data::BitStream::Code::Gamma', |
15
|
|
|
|
|
|
|
'Data::BitStream::Code::Delta', |
16
|
|
|
|
|
|
|
'Data::BitStream::Code::Omega', |
17
|
|
|
|
|
|
|
'Data::BitStream::Code::Levenstein', |
18
|
|
|
|
|
|
|
'Data::BitStream::Code::EvenRodeh', |
19
|
|
|
|
|
|
|
'Data::BitStream::Code::Fibonacci', |
20
|
|
|
|
|
|
|
'Data::BitStream::Code::Golomb', |
21
|
|
|
|
|
|
|
'Data::BitStream::Code::Rice', |
22
|
|
|
|
|
|
|
'Data::BitStream::Code::GammaGolomb', |
23
|
|
|
|
|
|
|
'Data::BitStream::Code::ExponentialGolomb', |
24
|
|
|
|
|
|
|
'Data::BitStream::Code::Baer', |
25
|
|
|
|
|
|
|
'Data::BitStream::Code::BoldiVigna', |
26
|
|
|
|
|
|
|
'Data::BitStream::Code::ARice', |
27
|
|
|
|
|
|
|
'Data::BitStream::Code::Additive', |
28
|
|
|
|
|
|
|
'Data::BitStream::Code::Comma', |
29
|
|
|
|
|
|
|
'Data::BitStream::Code::Taboo', |
30
|
|
|
|
|
|
|
'Data::BitStream::Code::BER', |
31
|
|
|
|
|
|
|
'Data::BitStream::Code::Varint', |
32
|
|
|
|
|
|
|
'Data::BitStream::Code::StartStop'; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
has '_vec' => (is => 'rw', default => sub{''}); |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
# Access the raw vector. |
37
|
|
|
|
|
|
|
sub _vecref { |
38
|
228132
|
|
|
228132
|
|
318173
|
my $self = shift; |
39
|
228132
|
|
|
|
|
1169412
|
\$self->{_vec}; |
40
|
|
|
|
|
|
|
} |
41
|
|
|
|
|
|
|
after 'erase' => sub { |
42
|
|
|
|
|
|
|
my $self = shift; |
43
|
|
|
|
|
|
|
$self->_vec(''); |
44
|
|
|
|
|
|
|
1; |
45
|
|
|
|
|
|
|
}; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub read { |
49
|
112204
|
|
|
112204
|
1
|
153389
|
my $self = shift; |
50
|
112204
|
100
|
|
|
|
316580
|
$self->error_stream_mode('read') if $self->writing; |
51
|
112202
|
|
|
|
|
147275
|
my $bits = shift; |
52
|
112202
|
100
|
66
|
|
|
2099753
|
$self->error_code('param', 'bits must be in range 1-' . $self->maxbits) |
|
|
|
100
|
|
|
|
|
53
|
|
|
|
|
|
|
unless defined $bits && $bits > 0 && $bits <= $self->maxbits; |
54
|
112196
|
|
66
|
|
|
330911
|
my $peek = (defined $_[0]) && ($_[0] eq 'readahead'); |
55
|
|
|
|
|
|
|
|
56
|
112196
|
|
|
|
|
206649
|
my $pos = $self->pos; |
57
|
112196
|
|
|
|
|
164736
|
my $len = $self->len; |
58
|
112196
|
100
|
|
|
|
255285
|
return if $pos >= $len; |
59
|
112038
|
100
|
100
|
|
|
472678
|
$self->error_off_stream if !$peek && ($pos+$bits) > $len; |
60
|
|
|
|
|
|
|
|
61
|
112031
|
|
|
|
|
158904
|
my $wpos = $pos >> 5; # / 32 |
62
|
112031
|
|
|
|
|
129734
|
my $bpos = $pos & 0x1F; # % 32 |
63
|
112031
|
|
|
|
|
232830
|
my $rvec = $self->_vecref; |
64
|
112031
|
|
|
|
|
160739
|
my $val = 0; |
65
|
|
|
|
|
|
|
|
66
|
112031
|
100
|
|
|
|
231799
|
if ( $bpos <= (32-$bits) ) { # optimize single word read |
67
|
86644
|
|
|
|
|
179324
|
$val = (vec($$rvec, $wpos, 32) >> (32-$bpos-$bits)) |
68
|
|
|
|
|
|
|
& (0xFFFFFFFF >> (32-$bits)); |
69
|
|
|
|
|
|
|
} else { |
70
|
25387
|
|
|
|
|
29379
|
my $bits_left = $bits; |
71
|
25387
|
|
|
|
|
51212
|
while ($bits_left > 0) { |
72
|
62794
|
100
|
|
|
|
116794
|
my $epos = (($bpos+$bits_left) > 32) ? 32 : $bpos+$bits_left; |
73
|
62794
|
|
|
|
|
69472
|
my $bits_to_read = $epos - $bpos; # between 0 and 32 |
74
|
62794
|
|
|
|
|
78522
|
my $v = vec($$rvec, $wpos, 32); |
75
|
62794
|
|
|
|
|
78346
|
$v >>= (32-$epos); |
76
|
62794
|
|
|
|
|
69325
|
$v &= (0xFFFFFFFF >> (32-$bits_to_read)); |
77
|
|
|
|
|
|
|
|
78
|
62794
|
|
|
|
|
85735
|
$val = ($val << $bits_to_read) | $v; |
79
|
|
|
|
|
|
|
|
80
|
62794
|
|
|
|
|
76951
|
$wpos++; |
81
|
62794
|
|
|
|
|
73066
|
$bits_left -= $bits_to_read; |
82
|
62794
|
|
|
|
|
161079
|
$bpos = 0; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
|
86
|
112031
|
100
|
|
|
|
317731
|
$self->_setpos( $pos + $bits ) unless $peek; |
87
|
112031
|
|
|
|
|
371205
|
$val; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
sub write { |
90
|
54117
|
|
|
54117
|
1
|
78229
|
my $self = shift; |
91
|
54117
|
100
|
|
|
|
152168
|
$self->error_stream_mode('write') unless $self->writing; |
92
|
54116
|
|
|
|
|
64805
|
my $bits = shift; |
93
|
54116
|
100
|
66
|
|
|
235234
|
$self->error_code('param', 'bits must be > 0') unless defined $bits && $bits > 0; |
94
|
54114
|
|
|
|
|
84304
|
my $val = shift; |
95
|
54114
|
50
|
33
|
|
|
240857
|
$self->error_code('zeroval') unless defined $val and $val >= 0; |
96
|
|
|
|
|
|
|
|
97
|
54114
|
|
|
|
|
94466
|
my $len = $self->len; |
98
|
54114
|
|
|
|
|
77444
|
my $new_len = $len + $bits; |
99
|
|
|
|
|
|
|
|
100
|
54114
|
100
|
|
|
|
136715
|
if ($val == 0) { # optimize writing 0 |
101
|
5642
|
|
|
|
|
10719
|
$self->_setlen( $new_len ); |
102
|
5642
|
|
|
|
|
20700
|
return 1; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
48472
|
100
|
|
|
|
109217
|
if ($val == 1) { $len += $bits-1; $bits = 1; } |
|
1749
|
|
|
|
|
2405
|
|
|
1749
|
|
|
|
|
2441
|
|
106
|
|
|
|
|
|
|
|
107
|
48472
|
100
|
|
|
|
168187
|
$self->error_code('param', 'bits must be <= ' . $self->maxbits) if $bits > $self->maxbits; |
108
|
|
|
|
|
|
|
|
109
|
48471
|
|
|
|
|
82592
|
my $wpos = $len >> 5; # / 32 |
110
|
48471
|
|
|
|
|
65000
|
my $bpos = $len & 0x1F; # % 32 |
111
|
48471
|
|
|
|
|
103773
|
my $rvec = $self->_vecref; |
112
|
|
|
|
|
|
|
|
113
|
48471
|
|
|
|
|
69042
|
my $wlen = 32-$bits; |
114
|
48471
|
100
|
|
|
|
89949
|
if ( $bpos <= $wlen ) { # optimize single word write |
115
|
31070
|
|
|
|
|
108537
|
vec($$rvec, $wpos, 32) |= ($val & (0xFFFFFFFF >> $wlen)) << ($wlen-$bpos); |
116
|
|
|
|
|
|
|
} else { |
117
|
17401
|
|
|
|
|
38782
|
while ($bits > 0) { |
118
|
42236
|
100
|
|
|
|
87867
|
my $epos = (($bpos+$bits) > 32) ? 32 : $bpos+$bits; |
119
|
42236
|
|
|
|
|
55624
|
my $bits_to_write = $epos - $bpos; # between 0 and 32 |
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
# get rid of parts of val to the right that we aren't writing yet |
122
|
42236
|
|
|
|
|
52592
|
my $val_to_write = $val >> ($bits - $bits_to_write); |
123
|
|
|
|
|
|
|
# get rid of parts of val to the left |
124
|
42236
|
|
|
|
|
57008
|
$val_to_write &= 0xFFFFFFFF >> (32-$bits_to_write); |
125
|
|
|
|
|
|
|
|
126
|
42236
|
|
|
|
|
115712
|
vec($$rvec, $wpos, 32) |= ($val_to_write << (32-$epos)); |
127
|
|
|
|
|
|
|
|
128
|
42236
|
|
|
|
|
74111
|
$wpos++; |
129
|
42236
|
|
|
|
|
55431
|
$bits -= $bits_to_write; |
130
|
42236
|
|
|
|
|
105000
|
$bpos = 0; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
|
134
|
48471
|
|
|
|
|
107522
|
$self->_setlen( $new_len ); |
135
|
48471
|
|
|
|
|
197150
|
1; |
136
|
|
|
|
|
|
|
} |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub put_unary { |
139
|
5874
|
|
|
5874
|
1
|
11745
|
my $self = shift; |
140
|
5874
|
50
|
|
|
|
16092
|
$self->error_stream_mode('write') unless $self->writing; |
141
|
|
|
|
|
|
|
|
142
|
5874
|
|
|
|
|
9785
|
my $len = $self->len; |
143
|
5874
|
|
|
|
|
10669
|
my $rvec = $self->_vecref; |
144
|
|
|
|
|
|
|
|
145
|
5874
|
|
|
|
|
10377
|
foreach my $val (@_) { |
146
|
6476
|
100
|
100
|
|
|
25906
|
$self->error_code('zeroval') unless defined $val and $val >= 0; |
147
|
|
|
|
|
|
|
# We're writing $val 0's, so just skip them |
148
|
6474
|
|
|
|
|
7312
|
$len += $val; |
149
|
6474
|
|
|
|
|
8308
|
my $wpos = $len >> 5; # / 32 |
150
|
6474
|
|
|
|
|
8132
|
my $bpos = $len & 0x1F; # % 32 |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# Write a 1 in the correct position |
153
|
6474
|
|
|
|
|
18709
|
vec($$rvec, $wpos, 32) |= (1 << ((32-$bpos) - 1)); |
154
|
6474
|
|
|
|
|
16737
|
$len++; |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
5872
|
|
|
|
|
12067
|
$self->_setlen( $len ); |
158
|
5872
|
|
|
|
|
14136
|
1; |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub get_unary { |
162
|
40076
|
|
|
40076
|
1
|
59919
|
my $self = shift; |
163
|
40076
|
50
|
|
|
|
107268
|
$self->error_stream_mode('read') if $self->writing; |
164
|
40076
|
|
|
|
|
49568
|
my $count = shift; |
165
|
40076
|
100
|
|
|
|
74552
|
if (!defined $count) { $count = 1; } |
|
40063
|
100
|
|
|
|
55287
|
|
|
|
100
|
|
|
|
|
|
166
|
9
|
|
|
|
|
19
|
elsif ($count < 0) { $count = ~0; } # Get everything |
167
|
2
|
|
|
|
|
9
|
elsif ($count == 0) { return; } |
168
|
|
|
|
|
|
|
|
169
|
40074
|
|
|
|
|
73759
|
my $pos = $self->pos; |
170
|
40074
|
|
|
|
|
61260
|
my $len = $self->len; |
171
|
40074
|
|
|
|
|
82403
|
my $rvec = $self->_vecref; |
172
|
|
|
|
|
|
|
|
173
|
40074
|
|
|
|
|
52363
|
my @vals; |
174
|
40074
|
|
|
|
|
91213
|
while ($count-- > 0) { |
175
|
40702
|
100
|
|
|
|
83262
|
last if $pos >= $len; |
176
|
40523
|
|
|
|
|
45345
|
my $onepos = $pos; |
177
|
40523
|
|
|
|
|
50910
|
my $wpos = $pos >> 5; # / 32 |
178
|
40523
|
|
|
|
|
49322
|
my $bpos = $pos & 0x1F; # % 32 |
179
|
|
|
|
|
|
|
# Get the current word, shifted left so current position is leftmost. |
180
|
40523
|
|
|
|
|
69364
|
my $v = ( vec($$rvec, $wpos++, 32) << $bpos ) & 0xFFFFFFFF; |
181
|
|
|
|
|
|
|
# Optimize common small values. |
182
|
40523
|
100
|
|
|
|
81464
|
if ($v & 0xF0000000) { |
183
|
22521
|
100
|
|
|
|
71707
|
my $val = ($v & 0x80000000) ? 0 : |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
184
|
|
|
|
|
|
|
($v & 0x40000000) ? 1 : |
185
|
|
|
|
|
|
|
($v & 0x20000000) ? 2 : 3; |
186
|
22521
|
|
|
|
|
27440
|
push @vals, $val; |
187
|
22521
|
|
|
|
|
30347
|
$pos += $val+1; |
188
|
22521
|
|
|
|
|
66642
|
next; |
189
|
|
|
|
|
|
|
} |
190
|
18002
|
100
|
|
|
|
36528
|
if ($v == 0) { |
191
|
|
|
|
|
|
|
# If this word is 0, advance words until we find one that is non-zero. |
192
|
6853
|
|
|
|
|
9294
|
$onepos += (32-$bpos); |
193
|
6853
|
|
|
|
|
9531
|
$v = vec($$rvec, $wpos++, 32); |
194
|
6853
|
100
|
|
|
|
12985
|
if ($v == 0) { |
195
|
|
|
|
|
|
|
# We've seen at least 33 zeros. Start trying to scan quickly. |
196
|
1526
|
|
|
|
|
1670
|
$onepos += 32; |
197
|
1526
|
|
|
|
|
1762
|
my $startwpos = $wpos; |
198
|
1526
|
|
|
|
|
2033
|
my $lastwpos = ($len+31) >> 5; |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# 100us: //g followed by pos |
201
|
|
|
|
|
|
|
# 34us: unpack("%32W*", substr($$rvec,$wpos*4,32)) == 0 |
202
|
|
|
|
|
|
|
# 27us: substr($$rvec,$wpos*4,32) =~ tr/\000/\000/ == 32 |
203
|
|
|
|
|
|
|
# 24us: substr($$rvec,$wpos*4,32) eq "\x00 .... \x00" |
204
|
|
|
|
|
|
|
# 12us: tr with 128 then 32 |
205
|
|
|
|
|
|
|
|
206
|
1526
|
|
100
|
|
|
11783
|
$wpos += 32 while ( (($wpos+31) < $lastwpos) && (substr($$rvec,$wpos*4,128) =~ tr/\000/\000/ == 128) ); |
207
|
1526
|
|
100
|
|
|
10152
|
$wpos += 8 while ( (($wpos+7) < $lastwpos) && (substr($$rvec,$wpos*4,32) =~ tr/\000/\000/ == 32) ); |
208
|
1526
|
|
100
|
|
|
20050
|
$wpos++ while ($wpos <= $lastwpos && vec($$rvec, $wpos, 32) == 0); |
209
|
1526
|
|
|
|
|
2068
|
$v = vec($$rvec, $wpos, 32); |
210
|
1526
|
|
|
|
|
2820
|
$onepos += 32*($wpos - $startwpos); |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
} |
213
|
18002
|
100
|
|
|
|
32532
|
$self->error_off_stream() if $onepos >= $len; |
214
|
17972
|
50
|
|
|
|
34878
|
$self->error_code('assert', "v must be 0") if $v == 0; |
215
|
|
|
|
|
|
|
# This word is non-zero. Find the leftmost set bit. |
216
|
17972
|
100
|
|
|
|
33026
|
if (($v & 0xFFFF0000) == 0) { $onepos += 16; $v <<= 16; } |
|
1845
|
|
|
|
|
2095
|
|
|
1845
|
|
|
|
|
2028
|
|
217
|
17972
|
100
|
|
|
|
32921
|
if (($v & 0xFF000000) == 0) { $onepos += 8; $v <<= 8; } |
|
6584
|
|
|
|
|
7580
|
|
|
6584
|
|
|
|
|
8269
|
|
218
|
17972
|
100
|
|
|
|
33287
|
if (($v & 0xF0000000) == 0) { $onepos += 4; $v <<= 4; } |
|
9175
|
|
|
|
|
10015
|
|
|
9175
|
|
|
|
|
10364
|
|
219
|
17972
|
100
|
|
|
|
31776
|
if (($v & 0xC0000000) == 0) { $onepos += 2; $v <<= 2; } |
|
5750
|
|
|
|
|
12471
|
|
|
5750
|
|
|
|
|
6268
|
|
220
|
17972
|
100
|
|
|
|
43267
|
if (($v & 0x80000000) == 0) { $onepos += 1; $v <<= 1; } |
|
8819
|
|
|
|
|
9023
|
|
|
8819
|
|
|
|
|
9801
|
|
221
|
17972
|
|
|
|
|
31417
|
push @vals, $onepos - $pos; |
222
|
17972
|
|
|
|
|
48069
|
$pos = $onepos+1; |
223
|
|
|
|
|
|
|
} |
224
|
40044
|
|
|
|
|
76472
|
$self->_setpos( $pos ); |
225
|
40044
|
100
|
|
|
|
145880
|
wantarray ? @vals : $vals[-1]; |
226
|
|
|
|
|
|
|
} |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# This is pretty important for speed |
229
|
|
|
|
|
|
|
sub put_gamma { |
230
|
13478
|
|
|
13478
|
1
|
43183
|
my $self = shift; |
231
|
13478
|
100
|
|
|
|
44450
|
$self->error_stream_mode('write') unless $self->writing; |
232
|
|
|
|
|
|
|
|
233
|
13477
|
|
|
|
|
22103
|
my $len = $self->len; |
234
|
13477
|
|
|
|
|
26913
|
my $rvec = $self->_vecref; |
235
|
13477
|
|
|
|
|
41801
|
my $maxval = $self->maxval(); |
236
|
|
|
|
|
|
|
|
237
|
13477
|
|
|
|
|
25097
|
foreach my $val (@_) { |
238
|
17483
|
100
|
100
|
|
|
79583
|
$self->error_code('zeroval') unless defined $val and $val >= 0; |
239
|
|
|
|
|
|
|
|
240
|
17481
|
|
|
|
|
23343
|
my $wpos = $len >> 5; # / 32 |
241
|
17481
|
|
|
|
|
24083
|
my $bpos = $len & 0x1F; # % 32 |
242
|
|
|
|
|
|
|
|
243
|
17481
|
100
|
|
|
|
46123
|
if ($val == 0) { # Quickly set zero |
|
|
100
|
|
|
|
|
|
244
|
2296
|
|
|
|
|
7099
|
vec($$rvec, $wpos, 32) |= (1 << ((32-$bpos) - 1)); |
245
|
2296
|
|
|
|
|
3552
|
$len++; |
246
|
2296
|
|
|
|
|
5720
|
next; |
247
|
|
|
|
|
|
|
} elsif ($val == $maxval) { # Encode ~0 as unary maxbits |
248
|
2
|
|
|
|
|
10
|
$len += $self->maxbits; |
249
|
2
|
|
|
|
|
3
|
$wpos = $len >> 5; # / 32 |
250
|
2
|
|
|
|
|
4
|
$bpos = $len & 0x1F; # % 32 |
251
|
2
|
|
|
|
|
6
|
vec($$rvec, $wpos, 32) |= (1 << ((32-$bpos) - 1)); |
252
|
2
|
|
|
|
|
8
|
$len++; |
253
|
2
|
|
|
|
|
5
|
next; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
|
256
|
15183
|
|
|
|
|
16784
|
my $bits; |
257
|
15183
|
100
|
|
|
|
26687
|
if ($val < 511) { |
258
|
11221
|
100
|
|
|
|
49942
|
$bits = ($val < 1) ? 1 : |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
259
|
|
|
|
|
|
|
($val < 3) ? 3 : |
260
|
|
|
|
|
|
|
($val < 7) ? 5 : |
261
|
|
|
|
|
|
|
($val < 15) ? 7 : |
262
|
|
|
|
|
|
|
($val < 31) ? 9 : |
263
|
|
|
|
|
|
|
($val < 63) ? 11 : |
264
|
|
|
|
|
|
|
($val <127) ? 13 : |
265
|
|
|
|
|
|
|
($val <255) ? 15 : 17; |
266
|
|
|
|
|
|
|
} else { |
267
|
3962
|
|
|
|
|
4965
|
$bits = 2*9+1; |
268
|
3962
|
|
|
|
|
5022
|
my $v = ($val+1) >> 9; |
269
|
3962
|
|
|
|
|
34527
|
$bits += 2 while ($v >>= 1); |
270
|
|
|
|
|
|
|
} |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
# Quickly insert if the code fits inside a single word |
273
|
15183
|
100
|
|
|
|
43180
|
if ( $bpos <= (32-$bits) ) { |
274
|
9643
|
|
|
|
|
273072
|
vec($$rvec, $wpos, 32) |= ( ($val+1) << ((32-$bpos) - $bits)); |
275
|
9643
|
|
|
|
|
19210
|
$len += $bits; |
276
|
9643
|
|
|
|
|
36108
|
next; |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
# Effectively we're doing: |
280
|
|
|
|
|
|
|
# |
281
|
|
|
|
|
|
|
# $self->put_unary($base); |
282
|
|
|
|
|
|
|
# $self->write($base, $val+1); |
283
|
|
|
|
|
|
|
# |
284
|
|
|
|
|
|
|
# which is equivalent to: |
285
|
|
|
|
|
|
|
# |
286
|
|
|
|
|
|
|
# $self->write($base, 0); |
287
|
|
|
|
|
|
|
# $self->write($base+1, $val+1); |
288
|
|
|
|
|
|
|
|
289
|
5540
|
|
|
|
|
6995
|
my $base = $bits >> 1; |
290
|
5540
|
|
|
|
|
6213
|
$len += $base; |
291
|
5540
|
|
|
|
|
6601
|
$base += 1; |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# write value in binary using $base bits |
294
|
|
|
|
|
|
|
{ |
295
|
5540
|
|
|
|
|
5491
|
my $v = $val+1; |
|
5540
|
|
|
|
|
7126
|
|
296
|
5540
|
|
|
|
|
5933
|
my $bits = $base; |
297
|
5540
|
|
|
|
|
7444
|
$wpos = $len >> 5; # / 32 |
298
|
5540
|
|
|
|
|
6924
|
$bpos = $len & 0x1F; # % 32 |
299
|
|
|
|
|
|
|
|
300
|
5540
|
|
|
|
|
11162
|
while ($bits > 0) { |
301
|
9110
|
100
|
|
|
|
16772
|
my $epos = (($bpos+$bits) > 32) ? 32 : $bpos+$bits; |
302
|
9110
|
|
|
|
|
10742
|
my $bits_to_write = $epos - $bpos; # between 0 and 32 |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
# get rid of parts of val to the right that we aren't writing yet |
305
|
9110
|
|
|
|
|
10699
|
my $val_to_write = $v >> ($bits - $bits_to_write); |
306
|
|
|
|
|
|
|
# get rid of parts of val to the left |
307
|
9110
|
|
|
|
|
10835
|
$val_to_write &= 0xFFFFFFFF >> (32-$bits_to_write); |
308
|
|
|
|
|
|
|
|
309
|
9110
|
|
|
|
|
23701
|
vec($$rvec, $wpos, 32) |= ($val_to_write << (32-$epos)); |
310
|
|
|
|
|
|
|
|
311
|
9110
|
|
|
|
|
14527
|
$wpos++; |
312
|
9110
|
|
|
|
|
10258
|
$bits -= $bits_to_write; |
313
|
9110
|
|
|
|
|
21340
|
$bpos = 0; |
314
|
|
|
|
|
|
|
} |
315
|
5540
|
|
|
|
|
15364
|
$len += $base; |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
} |
318
|
13475
|
|
|
|
|
32117
|
$self->_setlen( $len ); |
319
|
13475
|
|
|
|
|
43961
|
1; |
320
|
|
|
|
|
|
|
} |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
# Using default read_string |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
sub put_string { |
326
|
2457
|
|
|
2457
|
1
|
4676
|
my $self = shift; |
327
|
2457
|
100
|
|
|
|
6944
|
$self->error_stream_mode('write') unless $self->writing; |
328
|
|
|
|
|
|
|
|
329
|
2456
|
|
|
|
|
4328
|
my $len = $self->len; |
330
|
2456
|
|
|
|
|
4848
|
my $rvec = $self->_vecref; |
331
|
|
|
|
|
|
|
|
332
|
2456
|
|
|
|
|
4482
|
foreach my $str (@_) { |
333
|
2456
|
50
|
|
|
|
5008
|
next unless defined $str; |
334
|
2456
|
50
|
|
|
|
5550
|
$self->error_code('string') if $str =~ tr/01//c; |
335
|
2456
|
|
|
|
|
3540
|
my $bits = length($str); |
336
|
2456
|
50
|
|
|
|
5153
|
next unless $bits > 0; |
337
|
|
|
|
|
|
|
|
338
|
2456
|
|
|
|
|
2788
|
my $wpos = $len >> 5; |
339
|
2456
|
|
|
|
|
2860
|
my $bpos = $len & 0x1F; |
340
|
2456
|
|
|
|
|
2452
|
my $bits_to_write = $bits; |
341
|
|
|
|
|
|
|
# First get the part that fills the last word. |
342
|
2456
|
100
|
|
|
|
4599
|
my $first_bits = ($bpos == 0) ? 0 : 32-$bpos; |
343
|
2456
|
100
|
|
|
|
3928
|
if ($bpos > 0) { |
344
|
2215
|
|
|
|
|
6276
|
my $newvec = pack("B*", substr($str, 0, $first_bits) ); |
345
|
2215
|
|
|
|
|
6761
|
vec($$rvec, $wpos++, 32) |= vec($newvec, 0, 32) >> $bpos; |
346
|
2215
|
|
|
|
|
3942
|
$bits_to_write -= $first_bits; |
347
|
|
|
|
|
|
|
} else { |
348
|
|
|
|
|
|
|
# The fast part below does a string concat, which means we have to |
349
|
|
|
|
|
|
|
# make sure the vector is extended properly. This happens if we have |
350
|
|
|
|
|
|
|
# written zeros with the write() method, which just extends $len. |
351
|
241
|
100
|
|
|
|
741
|
vec($$rvec, $wpos-1, 32) |= 0 if $wpos > 0; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
# Now put the rest of the string in place quickly. |
354
|
2456
|
100
|
|
|
|
5668
|
if ($bits_to_write > 0) { |
355
|
2006
|
|
|
|
|
5030
|
$$rvec .= pack("B*", substr($str, $first_bits)); |
356
|
|
|
|
|
|
|
} |
357
|
|
|
|
|
|
|
|
358
|
2456
|
|
|
|
|
6085
|
$len += $bits; |
359
|
|
|
|
|
|
|
} |
360
|
2456
|
|
|
|
|
5329
|
$self->_setlen($len); |
361
|
2456
|
|
|
|
|
7932
|
1; |
362
|
|
|
|
|
|
|
} |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
sub to_string { |
365
|
2874
|
|
|
2874
|
1
|
12856
|
my $self = shift; |
366
|
2874
|
|
|
|
|
7346
|
$self->write_close; |
367
|
2874
|
|
|
|
|
4843
|
my $len = $self->len; |
368
|
2874
|
|
|
|
|
5863
|
my $rvec = $self->_vecref; |
369
|
2874
|
|
|
|
|
13029
|
my $str = unpack("B$len", $$rvec); |
370
|
|
|
|
|
|
|
# unpack sometimes drops 0 bits at the end, so we need to check and add them. |
371
|
2874
|
|
|
|
|
4402
|
my $strlen = length($str); |
372
|
2874
|
50
|
|
|
|
6036
|
$self->error_code('assert', "string length") if $strlen > $len; |
373
|
2874
|
100
|
|
|
|
5122
|
if ($strlen < $len) { |
374
|
7
|
|
|
|
|
19
|
$str .= "0" x ($len - $strlen); |
375
|
|
|
|
|
|
|
} |
376
|
2874
|
|
|
|
|
9221
|
$str; |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
sub from_string { |
379
|
2867
|
|
|
2867
|
1
|
35114
|
my $self = shift; |
380
|
2867
|
|
|
|
|
3731
|
my $str = shift; |
381
|
2867
|
50
|
|
|
|
10244
|
$self->error_code('string') if $str =~ tr/01//c; |
382
|
2867
|
|
66
|
|
|
6258
|
my $bits = shift || length($str); |
383
|
2867
|
|
|
|
|
7725
|
$self->write_open; |
384
|
|
|
|
|
|
|
|
385
|
2867
|
|
|
|
|
6263
|
my $rvec = $self->_vecref; |
386
|
2867
|
|
|
|
|
8556
|
$$rvec = pack("B*", $str); |
387
|
2867
|
|
|
|
|
5786
|
$self->_setlen($bits); |
388
|
|
|
|
|
|
|
|
389
|
2867
|
|
|
|
|
11566
|
$self->rewind_for_read; |
390
|
|
|
|
|
|
|
} |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# Our internal format is a big-endian vector, so to_raw and from_raw |
393
|
|
|
|
|
|
|
# are easy. We default to_store and from_store. |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
sub to_raw { |
396
|
5
|
|
|
5
|
1
|
815
|
my $self = shift; |
397
|
5
|
|
|
|
|
28
|
$self->write_close; |
398
|
5
|
|
|
|
|
27
|
my $rvec = $self->_vecref; |
399
|
5
|
|
|
|
|
25
|
return $$rvec; |
400
|
|
|
|
|
|
|
} |
401
|
|
|
|
|
|
|
|
402
|
|
|
|
|
|
|
sub from_raw { |
403
|
3
|
|
|
3
|
1
|
7715
|
my $self = $_[0]; |
404
|
|
|
|
|
|
|
# data comes in 2nd argument |
405
|
3
|
|
33
|
|
|
29
|
my $bits = $_[2] || 8*length($_[1]); |
406
|
|
|
|
|
|
|
|
407
|
3
|
|
|
|
|
18
|
$self->write_open; |
408
|
|
|
|
|
|
|
|
409
|
3
|
|
|
|
|
12
|
my $rvec = $self->_vecref; |
410
|
3
|
|
|
|
|
10
|
$$rvec = $_[1]; |
411
|
|
|
|
|
|
|
|
412
|
3
|
|
|
|
|
180
|
$self->_setlen( $bits ); |
413
|
3
|
|
|
|
|
14
|
$self->rewind_for_read; |
414
|
|
|
|
|
|
|
} |
415
|
|
|
|
|
|
|
|
416
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
417
|
28
|
|
|
28
|
|
87635
|
no Moo; |
|
28
|
|
|
|
|
97
|
|
|
28
|
|
|
|
|
195
|
|
418
|
|
|
|
|
|
|
1; |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
# ABSTRACT: A Vector-32 implementation of Data::BitStream |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=pod |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
=head1 NAME |
425
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
Data::BitStream::WordVec - A Vector-32 implementation of Data::BitStream |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head1 SYNOPSIS |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
use Data::BitStream::WordVec; |
431
|
|
|
|
|
|
|
my $stream = Data::BitStream::WordVec->new; |
432
|
|
|
|
|
|
|
$stream->put_gamma($_) for (1 .. 20); |
433
|
|
|
|
|
|
|
$stream->rewind_for_read; |
434
|
|
|
|
|
|
|
my @values = $stream->get_gamma(-1); |
435
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=head1 DESCRIPTION |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
An implementation of L. See the documentation for that |
439
|
|
|
|
|
|
|
module for many more examples, and L for the API. |
440
|
|
|
|
|
|
|
This document only describes the unique features of this implementation, |
441
|
|
|
|
|
|
|
which is of limited value to people purely using L. |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
This implementation uses a Perl C to store the data. The vector is |
444
|
|
|
|
|
|
|
accessed in 32-bit units, which makes it safe for 32-bit and 64-bit machines |
445
|
|
|
|
|
|
|
as well as reasonably time efficient. |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
This is the default L implementation. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head2 DATA |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
=over 4 |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
=item B< _vec > |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
A private scalar holding the data as a vector. |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
=back |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=head2 CLASS METHODS |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
=over 4 |
462
|
|
|
|
|
|
|
|
463
|
|
|
|
|
|
|
=item B< _vecref > |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
Retrieves a reference to the private vector. |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
=item I B< erase > |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
Sets the private vector to the empty string C<''>. |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
=item B< read > |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
=item B< write > |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
=item B< put_unary > |
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
=item B< get_unary > |
478
|
|
|
|
|
|
|
|
479
|
|
|
|
|
|
|
=item B< put_gamma > |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
=item B< put_string > |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=item B< to_string > |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
=item B< from_string > |
486
|
|
|
|
|
|
|
|
487
|
|
|
|
|
|
|
=item B< from_raw > |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=item B< to_raw > |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
These methods have custom implementations. |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
=back |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
=head2 ROLES |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
The following roles are included. |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
=over 4 |
500
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
=item L |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=item L |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=item L |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=item L |
508
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
=item L |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
=item L |
512
|
|
|
|
|
|
|
|
513
|
|
|
|
|
|
|
=item L |
514
|
|
|
|
|
|
|
|
515
|
|
|
|
|
|
|
=item L |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
=item L |
518
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=item L |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
=item L |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
=item L |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
=item L |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
=item L |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=item L |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
=item L |
532
|
|
|
|
|
|
|
|
533
|
|
|
|
|
|
|
=item L |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=item L |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
=back |
538
|
|
|
|
|
|
|
|
539
|
|
|
|
|
|
|
=head1 SEE ALSO |
540
|
|
|
|
|
|
|
|
541
|
|
|
|
|
|
|
=over 4 |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=item L |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=item L |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=item L |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
=back |
550
|
|
|
|
|
|
|
|
551
|
|
|
|
|
|
|
=head1 AUTHORS |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
Dana Jacobsen Edana@acm.orgE |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=head1 COPYRIGHT |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
Copyright 2011-2012 by Dana Jacobsen Edana@acm.orgE |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. |
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
=cut |