File Coverage

blib/lib/Data/BitStream.pm
Criterion Covered Total %
statement 90 91 98.9
branch 47 58 81.0
condition 2 6 33.3
subroutine 12 12 100.0
pod 5 5 100.0
total 156 172 90.7


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__