File Coverage

blib/lib/Algorithm/BinarySearch/Vec.pm
Criterion Covered Total %
statement 129 133 96.9
branch 39 52 75.0
condition 12 15 80.0
subroutine 22 24 91.6
pod 1 1 100.0
total 203 225 90.2


line stmt bran cond sub pod time code
1             package Algorithm::BinarySearch::Vec;
2              
3 5     5   58085 use Exporter;
  5         8  
  5         224  
4 5     5   22 use Carp;
  5         6  
  5         297  
5 5     5   2439 use AutoLoader;
  5         5945  
  5         24  
6 5     5   158 use Config qw();
  5         7  
  5         94  
7 5     5   15 use strict;
  5         7  
  5         86  
8 5     5   1873 use bytes;
  5         34  
  5         24  
9              
10             our @ISA = qw(Exporter);
11             our $VERSION = '0.08';
12              
13             our ($HAVE_XS);
14             eval {
15             require XSLoader;
16             $HAVE_XS = XSLoader::load('Algorithm::BinarySearch::Vec', $VERSION);
17             } or do {
18             $HAVE_XS = 0;
19             };
20              
21             # Preloaded methods go here.
22             #require Algorithm::BinarySearch::Vec::XS::Whatever;
23              
24             # Autoload methods go after =cut, and are processed by the autosplit program.
25              
26             ##======================================================================
27             ## Exports
28             ##======================================================================
29              
30 5     5   473 no warnings 'portable'; ##-- avoid "Bit vector size > 32 non-portable" errors for native quads
  5         7  
  5         1008  
31             our $HAVE_QUAD = ($Config::Config{use64bitint} ##-- avoid errors with xs U64TYPE but no perl-side 64bit ints (e.g. freebsd w/o -use64bitint perl config option)
32             &&
33             ($HAVE_XS ? Algorithm::BinarySearch::Vec::XS::HAVE_QUAD() : $Config::Config{d_quad})
34             );
35             our $KEY_NOT_FOUND = $HAVE_XS ? Algorithm::BinarySearch::Vec::XS::KEY_NOT_FOUND() : 0xffffffff;
36             #our $KEY_NOT_FOUND = $HAVE_XS ? Algorithm::BinarySearch::Vec::XS::KEY_NOT_FOUND() : ($HAVE_QUAD ? 0xffffffffffffffff : 0xffffffff);
37              
38             our (%EXPORT_TAGS, @EXPORT_OK, @EXPORT);
39             BEGIN {
40 5     5   34 %EXPORT_TAGS =
41             (
42             api => [qw( vbsearch vbsearch_lb vbsearch_ub),
43             qw(vabsearch vabsearch_lb vabsearch_ub),
44             qw(vvbsearch vvbsearch_lb vvbsearch_ub),
45             qw(vunion vintersect vsetdiff),
46             ],
47             const => [qw($HAVE_QUAD $KEY_NOT_FOUND)],
48             debug => [qw(vget vset vec2array)],
49             );
50 5         15 $EXPORT_TAGS{all} = [map {@$_} @EXPORT_TAGS{qw(api const debug)}];
  15         37  
51 5         10 $EXPORT_TAGS{default} = [map {@$_} @EXPORT_TAGS{qw(api const)}];
  10         23  
52 5         28 @EXPORT_OK = @{$EXPORT_TAGS{all}};
  5         17  
53 5         6 @EXPORT = @{$EXPORT_TAGS{default}};
  5         6084  
54             }
55              
56             ##======================================================================
57             ## Debug wrappers
58              
59             ##--------------------------------------------------------------
60             ## $val = vget($vec,$i,$nbits)
61             sub _vget {
62 0     0   0 return vec($_[0],$_[1],$_[2]);
63             }
64              
65             ##--------------------------------------------------------------
66             ## undef = vset($vec,$i,$nbits,$val)
67             sub _vset {
68 0     0   0 return vec($_[0],$_[1],$_[2])=$_[3];
69             }
70              
71              
72             ##======================================================================
73             ## API: Search: element-wise
74              
75             ##--------------------------------------------------------------
76             ## $index = vbsearch($v,$key,$nbits)
77             ## $index = vbsearch($v,$key,$nbits,$ilo,$ihi)
78             sub _vbsearch {
79 5     5   2156 my ($vr,$key,$nbits,$ilo,$ihi) = (\$_[0],@_[1..$#_]);
80 5 50       28 $ilo = 0 if (!defined($ilo));
81 5 50       12 $ihi = 8*length($$vr)/$nbits if (!defined($ihi));
82 5         4 my ($imid);
83 5         10 while ($ilo < $ihi) {
84 16         8 $imid = ($ihi+$ilo) >> 1;
85 16 100       20 if (vec($$vr,$imid,$nbits) < $key) {
86 6         8 $ilo = $imid + 1;
87             } else {
88 10         16 $ihi = $imid;
89             }
90             }
91 5 100 66     24 return ($ilo==$ihi) && vec($$vr,$ilo,$nbits)==$key ? $ilo : $KEY_NOT_FOUND;
92             }
93              
94             ##--------------------------------------------------------------
95             ## $index = vbsearch_lb($v,$key,$nbits)
96             ## $index = vbsearch_lb($v,$key,$nbits,$ilo,$ihi)
97             sub _vbsearch_lb {
98 6     6   5123 my ($vr,$key,$nbits,$ilo,$ihi) = (\$_[0],@_[1..$#_]);
99 6 50       14 $ilo = 0 if (!defined($ilo));
100 6 50       11 $ihi = 8*length($$vr)/$nbits if (!defined($ihi));
101 6         5 my ($imin,$imax,$imid) = ($ilo,$ihi);
102 6         13 while ($ihi-$ilo > 1) {
103 17         32 $imid = ($ihi+$ilo) >> 1;
104 17 100       19 if (vec($$vr,$imid,$nbits) < $key) {
105 6         8 $ilo = $imid;
106             } else {
107 11         17 $ihi = $imid;
108             }
109             }
110 6 50       11 return $ilo if ( vec($$vr,$ilo,$nbits)==$key);
111 6 100 100     25 return $ihi if ($ihi < $imax && vec($$vr,$ihi,$nbits)==$key);
112 4 100 100     16 return $ilo if ($ilo > $imin || vec($$vr,$ilo,$nbits) <$key);
113 1         1 return $KEY_NOT_FOUND;
114             }
115              
116             ##--------------------------------------------------------------
117             ## $index = vbsearch_ub($v,$key,$nbits)
118             ## $index = vbsearch_ub($v,$key,$nbits,$ilo,$ihi)
119             sub _vbsearch_ub {
120 62     62   5459 my ($vr,$key,$nbits,$ilo,$ihi) = (\$_[0],@_[1..$#_]);
121 62 100       86 $ilo = 0 if (!defined($ilo));
122 62 100       74 $ihi = 8*length($$vr)/$nbits if (!defined($ihi));
123 62         49 my ($imin,$imax,$imid) = ($ilo,$ihi);
124 62         102 while ($ihi-$ilo > 1) {
125 138         90 $imid = ($ihi+$ilo) >> 1;
126 138 100       145 if (vec($$vr,$imid,$nbits) > $key) {
127 105         131 $ihi = $imid;
128             } else {
129 33         50 $ilo = $imid;
130             }
131             }
132 62 50 66     185 return $ihi if ($ihi < $imax && vec($$vr,$ihi,$nbits)==$key);
133 62 100       100 return $ilo if ( vec($$vr,$ilo,$nbits)>=$key);
134 23 100       35 return $ihi>=$imax ? $KEY_NOT_FOUND : $ihi;
135             }
136              
137             ##======================================================================
138             ## API: Search: array-wise
139              
140             ##--------------------------------------------------------------
141             ## \@indices = vabsearch($v,\@keys,$nbits)
142             ## \@indices = vabsearch($v,\@keys,$nbits,$ilo,$ihi)
143             sub _vabsearch {
144 1     1   3049 return [map {vbsearch($_[0],$_,@_[2..$#_])} @{$_[1]}];
  7         15  
  1         3  
145             }
146              
147              
148             ##--------------------------------------------------------------
149             ## \@indices = vabsearch_lb($v,\@keys,$nbits)
150             ## \@indices = vabsearch_lb($v,\@keys,$nbits,$ilo,$ihi)
151             sub _vabsearch_lb {
152 1     1   516 return [map {vbsearch_lb($_[0],$_,@_[2..$#_])} @{$_[1]}];
  7         15  
  1         3  
153             }
154              
155             ##--------------------------------------------------------------
156             ## \@indices = vabsearch_ub($v,\@keys,$nbits)
157             ## \@indices = vabsearch_ub($v,\@keys,$nbits,$ilo,$ihi)
158             sub _vabsearch_ub {
159 1     1   509 return [map {vbsearch_ub($_[0],$_,@_[2..$#_])} @{$_[1]}];
  7         16  
  1         3  
160             }
161              
162             ##======================================================================
163             ## API: Search: vec-wise
164              
165             ## \@a = vec2array($vec,$nbits)
166             sub vec2array {
167 3     3 1 19 return [map {vec($_[0],$_,$_[1])} (0..(length($_[0])*8/$_[1]-1))];
  21         70  
168             }
169              
170             ##--------------------------------------------------------------
171             ## $indices = vvbsearch($v,$keys,$nbits)
172             ## $indices = vvbsearch($v,$keys,$nbits,$ilo,$ihi)
173             sub _vvbsearch {
174 1     1   2040 return pack('N*', @{vabsearch($_[0],vec2array(@_[1,2]),@_[2..$#_])});
  1         6  
175             }
176              
177             ##--------------------------------------------------------------
178             ## $indices = vvbsearch_lb($v,$keys,$nbits)
179             ## $indices = vvbsearch_lb($v,$keys,$nbits,$ilo,$ihi)
180             sub _vvbsearch_lb {
181 1     1   742 return pack('N*', @{vabsearch_lb($_[0],vec2array(@_[1,2]),@_[2..$#_])});
  1         8  
182             }
183              
184             ##--------------------------------------------------------------
185             ## $indices = vvbsearch_ub($v,$keys,$nbits)
186             ## $indices = vvbsearch_ub($v,$keys,$nbits,$ilo,$ihi)
187             sub _vvbsearch_ub {
188 1     1   892 return pack('N*', @{vabsearch_ub($_[0],vec2array(@_[1,2]),@_[2..$#_])});
  1         4  
189             }
190              
191             ##======================================================================
192             ## API: set operations
193              
194             ##--------------------------------------------------------------
195             ## $vunion = vunion($av,$bv,$nbits)
196             sub _vunion {
197 4     4   1873 my ($avr,$bvr,$nbits) = (\$_[0],\$_[1],$_[2]);
198 4 50       10 die(__PACKAGE__ , "::_vunion(): cannot handle nbits < 8, but you requested $nbits") if ($nbits < 8);
199 4         8 my $na = length($$avr)*8/$nbits;
200 4         5 my $nb = length($$bvr)*8/$nbits;
201 4         4 my $cv = '';
202 4         3 my ($ai,$bi,$ci, $aval,$bval);
203 4   66     18 for ($ai=0,$bi=0,$ci=0; $ai < $na && $bi < $nb; ++$ci) {
204 36         21 $aval = vec($$avr,$ai,$nbits);
205 36         26 $bval = vec($$bvr,$bi,$nbits);
206 36 50       31 if ($aval <= $bval) {
207 36         33 vec($cv,$ci,$nbits) = $aval;
208 36         23 ++$ai;
209 36 100       105 ++$bi if ($aval == $bval);
210             } else { ##-- $aval == $bval
211 0         0 vec($cv,$ci,$nbits) = $bval;
212 0         0 ++$bi;
213             }
214             }
215 4         7 $cv .= substr($$avr, $ai*$nbits/8);
216 4         6 $cv .= substr($$bvr, $bi*$nbits/8);
217 4         7 return $cv;
218             }
219              
220             ##--------------------------------------------------------------
221             ## $vintersect = vintersect($av,$bv,$nbits)
222             sub _vintersect {
223 4     4   3887 my ($avr,$bvr,$nbits) = (\$_[0],\$_[1],$_[2]);
224 4 50       11 die(__PACKAGE__ , "::_vintersect(): cannot handle nbits < 8, but you requested $nbits") if ($nbits < 8);
225              
226             ##-- ensure smaller set is "a"
227 4 50       14 ($$avr,$$bvr) = ($$bvr,$$avr) if (length($$bvr) < length($$avr));
228              
229 4         7 my $na = length($$avr)*8/$nbits;
230 4         5 my $nb = length($$bvr)*8/$nbits;
231 4         4 my $cv = '';
232 4         4 my ($ai,$bi,$ci, $blo,$aval,$bval);
233 4         9 for ($ai=0,$blo=0,$ci=0; $ai < $na; ++$ai) {
234 20         19 $aval = vec($$avr,$ai,$nbits);
235 20         25 $bi = _vbsearch_ub($$bvr,$aval,$nbits,$blo,$nb);
236 20 100       40 last if ($bi == $KEY_NOT_FOUND);
237 16 50       43 vec($cv,$ci++,$nbits) = $aval if ($aval == vec($$bvr,$bi,$nbits));
238 16         27 $blo = $bi;
239             }
240 4         9 return $cv;
241             }
242              
243             ##--------------------------------------------------------------
244             ## $vsetdiff = vsetdiff($av,$bv,$nbits)
245             sub _vsetdiff {
246 4     4   3704 my ($avr,$bvr,$nbits) = (\$_[0],\$_[1],$_[2]);
247 4 50       10 die(__PACKAGE__ , "::_vintersect(): cannot handle nbits < 8, but you requested $nbits") if ($nbits < 8);
248              
249 4         7 my $na = length($$avr)*8/$nbits;
250 4         4 my $nb = length($$bvr)*8/$nbits;
251 4         4 my $cv = '';
252 4         3 my ($ai,$bi,$ci, $blo,$aval,$bval);
253 4         12 for ($ai=0,$blo=0,$ci=0; $ai < $na; ++$ai) {
254 36         24 $aval = vec($$avr,$ai,$nbits);
255 36         39 $bi = _vbsearch_ub($$bvr,$aval,$nbits,$blo,$nb);
256 36 50       46 last if ($bi == $KEY_NOT_FOUND);
257 36 100       57 vec($cv,$ci++,$nbits) = $aval if ($aval != vec($$bvr,$bi,$nbits));
258 36         58 $blo = $bi;
259             }
260 4         7 $cv .= substr($$avr, $ai*$nbits/8);
261 4         7 return $cv;
262             }
263              
264              
265             ##======================================================================
266             ## delegate: attempt to delegate to XS module
267             foreach my $func (map {@$_} @EXPORT_TAGS{qw(api debug)}) {
268 5     5   26 no warnings 'redefine';
  5         5  
  5         489  
269             if ($HAVE_XS && Algorithm::BinarySearch::Vec::XS->can($func)) {
270             eval "\*$func = \\&Algorithm::BinarySearch::Vec::XS::$func;";
271             } elsif (__PACKAGE__->can("_$func")) {
272             eval "\*$func = \\&_$func;";
273             }
274             }
275              
276              
277             1; ##-- be happy
278              
279             __END__