line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Data::BitStream; |
2
|
|
|
|
|
|
|
# I have tested with 5.6.2 through 5.17.7 using Mouse. |
3
|
|
|
|
|
|
|
# Moo requires perl 5.8.1, Moose requires 5.8.3. |
4
|
6
|
|
|
6
|
|
143229
|
use strict; |
|
6
|
|
|
|
|
13
|
|
|
6
|
|
|
|
|
323
|
|
5
|
6
|
|
|
6
|
|
34
|
use warnings; |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
301
|
|
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = '0.08'; |
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
# Since we're using Moo, things get rather messed up if we try to |
10
|
|
|
|
|
|
|
# inherit from Exporter. Really all we want is the ability to let people |
11
|
|
|
|
|
|
|
# use a couple convenience functions, so just grab the import method. |
12
|
6
|
|
|
6
|
|
42
|
use Exporter qw(import); |
|
6
|
|
|
|
|
87
|
|
|
6
|
|
|
|
|
2520
|
|
13
|
|
|
|
|
|
|
our @EXPORT_OK = qw( code_is_supported code_is_universal ); |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
# Our class methods to support referencing codes by text names. |
17
|
|
|
|
|
|
|
my %codeinfo; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
sub add_code { |
20
|
162
|
|
|
162
|
1
|
201
|
my $rinfo = shift; |
21
|
162
|
50
|
33
|
|
|
909
|
die "add_code needs a hash ref" unless defined $rinfo && ref $rinfo eq 'HASH'; |
22
|
162
|
|
|
|
|
241
|
foreach my $p (qw(package name universal params encodesub decodesub)) { |
23
|
972
|
50
|
|
|
|
2180
|
die "invalid registration: missing $p" unless defined $$rinfo{$p}; |
24
|
|
|
|
|
|
|
} |
25
|
162
|
|
|
|
|
333
|
my $name = lc $$rinfo{'name'}; |
26
|
162
|
100
|
|
|
|
368
|
if (defined $codeinfo{$name}) { |
27
|
54
|
50
|
|
|
|
185
|
return 1 if $codeinfo{$name}{'package'} eq $$rinfo{'package'}; |
28
|
0
|
|
|
|
|
0
|
die "module $$rinfo{'package'} trying to reuse code name '$name' already in use by $codeinfo{$name}{'package'}"; |
29
|
|
|
|
|
|
|
} |
30
|
108
|
|
|
|
|
278
|
$codeinfo{$name} = $rinfo; |
31
|
108
|
|
|
|
|
221
|
1; |
32
|
|
|
|
|
|
|
}; |
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
sub _find_code { |
35
|
853
|
|
|
853
|
|
1740
|
my $code = lc shift; |
36
|
|
|
|
|
|
|
|
37
|
853
|
100
|
|
|
|
6154
|
return $codeinfo{$code} if defined $codeinfo{$code}; |
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# Load codes from base |
40
|
6
|
50
|
33
|
|
|
72
|
if ( defined $Data::BitStream::Base::CODEINFO |
41
|
|
|
|
|
|
|
&& ref $Data::BitStream::Base::CODEINFO eq 'ARRAY') { |
42
|
6
|
|
|
|
|
12
|
foreach my $r (@{$Data::BitStream::Base::CODEINFO}) { |
|
6
|
|
|
|
|
21
|
|
43
|
18
|
50
|
|
|
|
55
|
next unless ref $r eq 'HASH'; |
44
|
18
|
|
|
|
|
69
|
add_code($r); |
45
|
|
|
|
|
|
|
} |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Load info for all code modules that have been included |
49
|
6
|
|
|
|
|
69
|
foreach my $module (keys %Data::BitStream::Code::) { |
50
|
|
|
|
|
|
|
# module is 'Gamma::' mname is 'Gamma' |
51
|
120
|
|
|
|
|
489
|
my ($mname) = $module =~ /(.+)::$/; |
52
|
120
|
50
|
|
|
|
340
|
next unless defined $mname; |
53
|
|
|
|
|
|
|
# Load the CODEINFO variable, skip if it isn't found |
54
|
120
|
|
|
|
|
116
|
my $rinfo; |
55
|
|
|
|
|
|
|
{ |
56
|
120
|
|
|
|
|
115
|
my $pname = 'Data::BitStream::Code::' . $module; |
|
120
|
|
|
|
|
204
|
|
57
|
6
|
|
|
6
|
|
474
|
no strict 'refs'; ## no critic |
|
6
|
|
|
|
|
11
|
|
|
6
|
|
|
|
|
2361
|
|
58
|
120
|
|
|
|
|
120
|
$rinfo = ${$pname}{'CODEINFO'}; |
|
120
|
|
|
|
|
577
|
|
59
|
120
|
100
|
|
|
|
247
|
next unless defined $rinfo; |
60
|
114
|
50
|
|
|
|
852
|
next unless $rinfo =~ s/^\*//; |
61
|
114
|
|
|
|
|
189
|
$rinfo = ${$rinfo}; |
|
114
|
|
|
|
|
375
|
|
62
|
|
|
|
|
|
|
} |
63
|
120
|
100
|
|
|
|
277
|
next unless defined $rinfo; |
64
|
114
|
100
|
|
|
|
267
|
if (ref $rinfo eq 'HASH') { |
|
|
50
|
|
|
|
|
|
65
|
96
|
|
|
|
|
154
|
add_code($rinfo); |
66
|
|
|
|
|
|
|
} elsif (ref $rinfo eq 'ARRAY') { |
67
|
18
|
|
|
|
|
23
|
foreach my $r (@{$rinfo}) { |
|
18
|
|
|
|
|
49
|
|
68
|
48
|
50
|
|
|
|
125
|
next unless ref $r eq 'HASH'; |
69
|
48
|
|
|
|
|
85
|
add_code($r); |
70
|
|
|
|
|
|
|
} |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
} |
73
|
|
|
|
|
|
|
|
74
|
6
|
|
|
|
|
95
|
$codeinfo{$code}; |
75
|
|
|
|
|
|
|
}; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
sub code_is_supported { |
78
|
40
|
|
|
40
|
1
|
43492
|
my $code = lc shift; |
79
|
40
|
100
|
|
|
|
64
|
my $param; $param = $1 if $code =~ s/\((.+)\)$//; |
|
40
|
|
|
|
|
297
|
|
80
|
40
|
|
|
|
|
95
|
return defined _find_code($code); |
81
|
|
|
|
|
|
|
} |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
sub code_is_universal { |
84
|
41
|
|
|
41
|
1
|
366
|
my $code = lc shift; |
85
|
41
|
100
|
|
|
|
53
|
my $param; $param = $1 if $code =~ s/\((.+)\)$//; |
|
41
|
|
|
|
|
202
|
|
86
|
41
|
|
|
|
|
85
|
my $inforef = _find_code($code); |
87
|
41
|
100
|
|
|
|
106
|
return unless defined $inforef; # Unknown code. |
88
|
40
|
|
|
|
|
132
|
return $inforef->{'universal'}; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
|
92
|
|
|
|
|
|
|
# Pick one implementation as the default. |
93
|
|
|
|
|
|
|
# |
94
|
|
|
|
|
|
|
# BLVec uses the Data::BitStream::XS class, and is 50-100x faster than the |
95
|
|
|
|
|
|
|
# others for most codes. |
96
|
|
|
|
|
|
|
# |
97
|
|
|
|
|
|
|
# WordVec is the preferred Pure Perl implementation, being both space and time |
98
|
|
|
|
|
|
|
# efficient. |
99
|
|
|
|
|
|
|
# |
100
|
|
|
|
|
|
|
# String is simple and surprisingly fast, but uses more memory (1 byte per bit). |
101
|
|
|
|
|
|
|
# |
102
|
|
|
|
|
|
|
# Vec is deprecated. |
103
|
|
|
|
|
|
|
# |
104
|
|
|
|
|
|
|
# MinimalVec is for example only. |
105
|
|
|
|
|
|
|
# |
106
|
|
|
|
|
|
|
# BitVec uses Bit::Vector to try to obtain better performance. While a few |
107
|
|
|
|
|
|
|
# operations (e.g. get_unary) can be fast, in general it is as slow or slower |
108
|
|
|
|
|
|
|
# than the WordVec implementation. The main issue is that Bit::Vector uses a |
109
|
|
|
|
|
|
|
# little-endian representation which does not match what we want. |
110
|
|
|
|
|
|
|
# |
111
|
|
|
|
|
|
|
# bench-codes with many codes, sum: |
112
|
|
|
|
|
|
|
# |
113
|
|
|
|
|
|
|
# BLVec 4829 ns encode 11102 ns decode 71 x |
114
|
|
|
|
|
|
|
# String 403470 ns encode 494878 ns decode 1.3 x |
115
|
|
|
|
|
|
|
# WordVec 457533 ns encode 676737 ns decode 1.0 |
116
|
|
|
|
|
|
|
# BitVec 492701 ns encode 666711 ns decode 0.98x |
117
|
|
|
|
|
|
|
# Vec 549342 ns encode 927764 ns decode 0.77x |
118
|
|
|
|
|
|
|
# MinmlVec 554690 ns encode 8252307 ns decode 0.13x |
119
|
|
|
|
|
|
|
# |
120
|
|
|
|
|
|
|
# A 32-bit HP 9000/785 gave similar results though ~15x slower overall. |
121
|
|
|
|
|
|
|
|
122
|
6
|
|
|
6
|
|
42106
|
use Moo; |
|
6
|
|
|
|
|
157317
|
|
|
6
|
|
|
|
|
51
|
|
123
|
|
|
|
|
|
|
if (eval {require Data::BitStream::BLVec}) { |
124
|
|
|
|
|
|
|
extends 'Data::BitStream::BLVec'; |
125
|
|
|
|
|
|
|
} else { |
126
|
|
|
|
|
|
|
extends 'Data::BitStream::WordVec'; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# get and put methods for referencing codes by text names |
130
|
|
|
|
|
|
|
sub code_put { |
131
|
97
|
|
|
97
|
1
|
76277
|
my $self = shift; |
132
|
97
|
|
|
|
|
263
|
my $code = lc shift; |
133
|
97
|
100
|
|
|
|
117
|
my $param; $param = $1 if $code =~ s/\((.+)\)$//; |
|
97
|
|
|
|
|
874
|
|
134
|
97
|
|
|
|
|
332
|
my $inforef = _find_code($code); |
135
|
97
|
100
|
|
|
|
249
|
die "Unknown code $code" unless defined $inforef; |
136
|
96
|
|
|
|
|
233
|
my $sub = $inforef->{'encodesub'}; |
137
|
96
|
50
|
|
|
|
294
|
die "No encoding sub for code $code!" unless defined $sub; |
138
|
96
|
100
|
|
|
|
276
|
if ($inforef->{'params'}) { |
139
|
71
|
100
|
|
|
|
175
|
die "Code $code needs a parameter" unless defined $param; |
140
|
70
|
|
|
|
|
297
|
return $sub->($self, $param, @_); |
141
|
|
|
|
|
|
|
} else { |
142
|
25
|
100
|
|
|
|
72
|
die "Code $code does not have parameters" if defined $param; |
143
|
24
|
|
|
|
|
117
|
return $sub->($self, @_); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
sub code_get { |
148
|
675
|
|
|
675
|
1
|
99629
|
my $self = shift; |
149
|
675
|
|
|
|
|
2578
|
my $code = lc shift; |
150
|
675
|
100
|
|
|
|
818
|
my $param; $param = $1 if $code =~ s/\((.+)\)$//; |
|
675
|
|
|
|
|
5933
|
|
151
|
675
|
|
|
|
|
2612
|
my $inforef = _find_code($code); |
152
|
675
|
100
|
|
|
|
2723
|
die "Unknown code $code" unless defined $inforef; |
153
|
674
|
|
|
|
|
2158
|
my $sub = $inforef->{'decodesub'}; |
154
|
674
|
50
|
|
|
|
1673
|
die "No decoding sub for code $code!" unless defined $sub; |
155
|
674
|
100
|
|
|
|
2038
|
if ($inforef->{'params'}) { |
156
|
470
|
100
|
|
|
|
3460
|
die "Code $code needs a parameter" unless defined $param; |
157
|
469
|
|
|
|
|
2798
|
return $sub->($self, $param, @_); |
158
|
|
|
|
|
|
|
} else { |
159
|
204
|
100
|
|
|
|
529
|
die "Code $code does not have parameters" if defined $param; |
160
|
203
|
|
|
|
|
967
|
return $sub->($self, @_); |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
} |
163
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
__PACKAGE__->meta->make_immutable; |
165
|
6
|
|
|
6
|
|
25679
|
no Moo; |
|
6
|
|
|
|
|
18
|
|
|
6
|
|
|
|
|
54
|
|
166
|
|
|
|
|
|
|
|
167
|
|
|
|
|
|
|
1; |
168
|
|
|
|
|
|
|
__END__ |