File Coverage

lib/Net/BART/SparseArray256.pm
Criterion Covered Total %
statement 50 55 90.9
branch 8 10 80.0
condition n/a
subroutine 10 14 71.4
pod 0 11 0.0
total 68 90 75.5


line stmt bran cond sub pod time code
1             package Net::BART::SparseArray256;
2              
3 2     2   88569 use strict;
  2         3  
  2         55  
4 2     2   6 use warnings;
  2         2  
  2         105  
5 2     2   312 use Net::BART::BitSet256;
  2         3  
  2         1368  
6              
7             our $VERSION = '0.01';
8              
9             # A popcount-compressed sparse array with 256 possible indices.
10             # Uses a BitSet256 to track which indices are occupied,
11             # and a compact array holding only the occupied values.
12             #
13             # Structure: [$bitset, $items_arrayref]
14             # Using array-based object for speed over hash.
15              
16             sub new {
17 80     80 0 156570 return bless [Net::BART::BitSet256->new, []], $_[0];
18             }
19              
20             sub clone {
21 0     0 0 0 return bless [$_[0]->[0]->clone, [@{$_[0]->[1]}]], ref($_[0]);
  0         0  
22             }
23              
24             # Get value at index $i. Returns (value, 1) if present, (undef, 0) if not.
25             sub get {
26 829     829 0 3235 my $bs = $_[0]->[0];
27 829 100       2169 if ($bs->[$_[1] >> 6] & (1 << ($_[1] & 63))) {
28 545         1575 return ($_[0]->[1][$bs->rank($_[1]) - 1], 1);
29             }
30 284         695 return (undef, 0);
31             }
32              
33             # Insert or update value at index $i. Returns 1 if new, 0 if updated.
34             sub insert_at {
35 311     311 0 581 my ($self, $i, $value) = @_;
36 311         436 my $bs = $self->[0];
37 311 100       865 if ($bs->[$i >> 6] & (1 << ($i & 63))) {
38             # Update existing
39 12         48 $self->[1][$bs->rank($i) - 1] = $value;
40 12         24 return 0;
41             }
42             # Insert new
43 299         948 $bs->set($i);
44 299         709 my $rank = $bs->rank($i);
45 299         445 splice(@{$self->[1]}, $rank - 1, 0, $value);
  299         728  
46 299         589 return 1;
47             }
48              
49             # Delete value at index $i. Returns (old_value, 1) or (undef, 0).
50             sub delete_at {
51 3     3 0 10 my ($self, $i) = @_;
52 3         23 my $bs = $self->[0];
53 3 100       21 if (!($bs->[$i >> 6] & (1 << ($i & 63)))) {
54 1         2 return (undef, 0);
55             }
56 2         18 my $rank = $bs->rank($i);
57 2         4 my $old = splice(@{$self->[1]}, $rank - 1, 1);
  2         7  
58 2         8 $bs->clear($i);
59 2         7 return ($old, 1);
60             }
61              
62             # Test if index $i is occupied (inlined bitset test).
63             sub test {
64 0 0   0 0 0 return ($_[0]->[0]->[$_[1] >> 6] & (1 << ($_[1] & 63))) ? 1 : 0;
65             }
66              
67             sub len {
68 4     4 0 1839 return scalar @{$_[0]->[1]};
  4         14  
69             }
70              
71             sub is_empty {
72 1     1 0 4 return !@{$_[0]->[1]};
  1         8  
73             }
74              
75             # Iterate over occupied (index, value) pairs in ascending order.
76             sub each_pair {
77 5     5 0 14 my ($self, $callback) = @_;
78 5         15 my $items = $self->[1];
79 5         8 my $pos = 0;
80 5         9 my $bs = $self->[0];
81 5         9 for my $i (0, 1, 2, 3) {
82 20         29 my $w = $bs->[$i];
83 20 100       40 next unless $w;
84 5         9 my $base = $i << 6;
85 5         9 while ($w) {
86 5         8 my $t = $w & (-$w);
87 5         16 $callback->($base + Net::BART::BitSet256::_bit_len64($t) - 1, $items->[$pos]);
88 5         24 $pos++;
89 5         13 $w &= ($w - 1);
90             }
91             }
92             }
93              
94             # Direct access to the bitset (for LPM operations).
95 0     0 0   sub bitset { return $_[0]->[0] }
96              
97             # Direct access to items array.
98 0     0 0   sub items { return $_[0]->[1] }
99              
100             1;