File Coverage

blib/lib/Tie/IntegerArray.pm
Criterion Covered Total %
statement 103 107 96.2
branch 39 60 65.0
condition 5 6 83.3
subroutine 15 15 100.0
pod n/a
total 162 188 86.1


line stmt bran cond sub pod time code
1             package Tie::IntegerArray;
2              
3             require 5.6.0;
4              
5 1     1   6919 use strict;
  1         2  
  1         35  
6 1     1   6 use warnings;
  1         3  
  1         33  
7 1     1   1313 use integer;
  1         16  
  1         6  
8              
9             our $VERSION = '0.01';
10              
11 1     1   48 use base 'Tie::Array';
  1         2  
  1         1045  
12              
13 1     1   2123 use Bit::Vector;
  1         2520  
  1         54  
14 1     1   7 use Carp qw(croak);
  1         2  
  1         1461  
15              
16             sub TIEARRAY {
17 2     2   117 my $pkg = shift;
18 2         5 my $self = {};
19              
20 2 50       18 croak("Tie::IntegerArray : bad call to tie - options must be specifyed as key-value pairs.")
21             if (@_ % 2);
22 2         6 %$self = @_;
23            
24             # setup defaults
25 2 50       10 $self->{size} = 1 unless exists $self->{size};
26 2 100       5 $self->{undef} = 0 unless exists $self->{undef};
27 2 50       6 $self->{signed} = 1 unless exists $self->{signed};
28 2 100       22 $self->{bits} = Bit::Vector->Word_Bits() unless exists $self->{bits};
29 2 50       6 $self->{trace} = 0 unless exists $self->{trace};
30              
31             # calculate range
32 2 50       7 if ($self->{signed}) {
33 2         9 $self->{min} = ((2 ** ($self->{bits} - 2)) * -1);
34 2         3 $self->{max} = ($self->{min} * -1) - 1;
35             } else {
36 0         0 $self->{min} = 0;
37 0         0 $self->{max} = 2 ** $self->{bits};
38             }
39              
40             # create value vector
41 2         14 $self->{vec} = Bit::Vector->new($self->{bits} * $self->{size});
42 2 50       29 croak("Tie::IntegerArray : unable to create internal Bit::Vector object")
43             unless defined $self->{vec};
44              
45             # create defined vector
46 2 100       7 if ($self->{undef}) {
47 1         4 $self->{dvec} = Bit::Vector->new($self->{size});
48 1 50       3 croak("Tie::IntegerArray : unable to create internal defined Bit::Vector object")
49             unless defined $self->{dvec};
50             }
51              
52             # create scratch vector for working with individual values
53 2         10 $self->{svec} = Bit::Vector->new($self->{bits});
54 2 50       5 croak("Tie::IntegerArray : unable to create internal scratch Bit::Vector object")
55             unless defined $self->{svec};
56              
57 2         8 return bless($self, $pkg);
58             }
59              
60             sub FETCH {
61 16     16   68 my $self = shift;
62 16         20 my $vec = $self->{vec};
63 16         17 my $svec = $self->{svec};
64 16         17 my $dvec = $self->{dvec};
65 16         17 my $index = shift;
66              
67 16 50       26 print STDERR "FETCH($index) called.\n" if $self->{trace};
68              
69             # get bit_index for this value
70 16         20 my $bit_index = $index * $self->{bits};
71              
72             # extend if necessary
73 16 50       42 $self->STORESIZE($index + 1)
74             if ($vec->Size() <= $bit_index);
75              
76             # check for undef in dvec
77 16 100 100     67 return undef if $self->{undef} and not $dvec->bit_test($index);
78            
79             # copy into svec and return to_Bin
80 13         47 $svec->Interval_Copy($vec,0,$bit_index,$svec->Size());
81 13         87 return $svec->to_Dec();
82             }
83              
84             sub STORESIZE {
85 1     1   4 my $self = shift;
86 1         2 my $vec = $self->{vec};
87 1         1 my $dvec = $self->{dvec};
88 1         2 my $index = shift;
89            
90 1 50       3 print STDERR "STORESIZE($index) called.\n" if $self->{trace};
91              
92 1         3 $vec->Resize($index * $self->{bits});
93 1 50       9 $dvec->Resize($index) if $self->{undef};
94             }
95 1     1   6 sub EXTEND { goto &STORESIZE; }
96              
97             sub CLEAR {
98 1     1   1 my $self = shift;
99 1         2 my $vec = $self->{vec};
100 1         2 my $dvec = $self->{dvec};
101              
102 1 50       3 print STDERR "CLEAR() called.\n" if $self->{trace};
103              
104 1         4 $vec->Resize(0);
105 1 50       8 $dvec->Resize(0) if $self->{undef};
106             }
107              
108             sub FETCHSIZE {
109 1     1   8 my $self = shift;
110 1         2 my $vec = $self->{vec};
111              
112 1 50       6 print STDERR "FETCHSIZE() called.\n" if $self->{trace};
113              
114 1         7 return $vec->Size() / $self->{bits};
115             }
116              
117             sub STORE {
118 10     10   37 my $self = shift;
119 10         19 my $vec = $self->{vec};
120 10         11 my $svec = $self->{svec};
121 10         13 my $dvec = $self->{dvec};
122 10         9 my $index = shift;
123 10         11 my $value = shift;
124              
125 10 50       20 print STDERR "STORE($index, $value) called.\n" if $self->{trace};
126              
127             # get bit_index for this value
128 10         14 my $bit_index = $index * $self->{bits};
129              
130             # extend if necessary
131 10 100       37 if ($vec->Size() <= $bit_index) {
132 6         52 $vec->Resize(($index + 1) * $self->{bits});
133 6 100       20 $dvec->Resize($index + 1) if $self->{undef};
134             }
135              
136             # set undef appropriately if required
137 10 100       22 if ($self->{undef}) {
138 6 50       11 if (defined $value) {
139 6         17 $dvec->Bit_On($index);
140             } else {
141 0         0 $dvec->Bit_Off($index);
142 0         0 return undef; # all done if set to undef now
143             }
144             }
145              
146 10 50       56 croak("Tie::IntegerArray : cannot store non-integer value '$value'!")
147             unless $value =~ /^-?\d+$/;
148              
149 10 100 66     228 croak("Tie::IntegerArray : Unable to store value '$value' - out of range ($self->{min} - $self->{max})")
150             if $value < $self->{min} or $value > $self->{max};
151              
152             # store the number in svec and then copy into place
153 9         162 $svec->from_Dec($value);
154 9         39 $vec->Interval_Substitute($svec,$bit_index,$self->{bits},0,$self->{bits});
155              
156 9         24 return $value;
157             }
158              
159             sub EXISTS {
160 3     3   113 my $self = shift;
161 3         5 my $vec = $self->{vec};
162 3         4 my $index = shift;
163              
164 3 50       7 print STDERR "EXISTS($index) called.\n" if $self->{trace};
165              
166             # get bit_index for this value
167 3         4 my $bit_index = $index * $self->{bits};
168              
169             # does this slot exist?
170 3         15 return ($bit_index < $vec->Size());
171             }
172              
173             sub DELETE {
174 2     2   4 my $self = shift;
175 2         4 my $vec = $self->{vec};
176 2         3 my $dvec = $self->{dvec};
177 2         4 my $svec = $self->{svec};
178 2         3 my $index = shift;
179              
180 2 50       7 print STDERR "DELETE($index) called.\n" if $self->{trace};
181              
182             # get bit_index for this value
183 2         5 my $bit_index = $index * $self->{bits};
184              
185             # extend if necessary
186 2 50       12 return undef if $bit_index >= $vec->Size();
187              
188 2         10 $vec->Interval_Empty($bit_index,$bit_index + $self->{bits} - 1);
189 2 100       11 $dvec->Bit_Off($index) if $self->{undef};
190 2         6 return 1;
191             }
192              
193             1;
194             __END__