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