File Coverage

blib/lib/FactorOracle.pm
Criterion Covered Total %
statement 57 65 87.6
branch 9 16 56.2
condition n/a
subroutine 10 11 90.9
pod 0 8 0.0
total 76 100 76.0


line stmt bran cond sub pod time code
1             package FactorOracle;
2              
3 1     1   49853 use 5.008002;
  1         5  
  1         43  
4 1     1   6 use strict;
  1         1  
  1         36  
5 1     1   6 use warnings;
  1         268  
  1         828  
6              
7             our $VERSION = '0.01';
8              
9             # Factor Oracle data structure is in the form of two contiguous
10             # strings of data (in memory or on disk)
11             # STATES: [suffix link(int)][initial via char][transitions link (int)]
12             # TRANSITIONS: [via char][state link (int)][next trans (int)]
13              
14              
15              
16             sub new {
17 1     1 0 12 my $class = shift;
18 1         4 my $self = { S => '', T => '' };
19              
20             # initial state
21 1         3 $self->{S} .= pack("lal", -1, 'a', -1);
22 1         4 return bless $self, $class;
23             }
24              
25             sub add {
26 1     1 0 689 my $self = shift;
27 1         3 my $string = shift;
28 1         4 for my $i (0..length($string)-1){
29 7         19 $self->add_char( substr($string, $i, 1) );
30             }
31             }
32              
33              
34              
35             sub add_char {
36 7     7 0 10 my $self = shift;
37 7         14 my $char = shift;
38 7         12 my $Slen = length $self->{S};
39 7 50       18 die "bad length" unless ($Slen % 9) == 0;
40 7         12 my $m = $Slen/9 - 1; # index of final state
41 7         10 my $final = $m*9; # string index position of final state
42 7         14 my $sl = $self->sl($m); # suffix link of final state
43              
44             # set initial transition via $char
45 7         14 substr($self->{S}, $final+4, 1) = $char;
46              
47              
48 7         15 while($sl > -1){
49 8 100       19 if(my $state = $self->trans_exists($sl, $char)){
50 5         12 $sl = $state; # [state pointed to by state $sl via $char]
51 5         7 last;
52             }
53             else {
54             # Create transition, follow back
55 3         9 $self->create_trans($sl, $char, $m+1);
56 3         7 $sl = $self->sl($sl);
57             }
58             }
59 7 100       16 $sl = ($sl < 0) ? 0 : $sl;
60              
61             # Add new state with just suffix link initialized.
62 7         32 $self->{S} .= pack("lal", $sl, 0, -1);
63             }
64              
65             sub trans_exists {
66 11     11 0 1182 my $self = shift;
67 11         16 my $from = shift;
68 11         13 my $via = shift;
69              
70 11         36 my ($to, $char, $extra) = unpack("lal", substr($self->{S}, $from*9, 9));
71 11 100       32 return $from+1 if $char eq $via;
72              
73             # search transition string for $via
74 6         14 while($extra > -1){
75 3         11 ($char, $to, $extra) = unpack("all", substr($self->{T}, $extra*9, 9));
76 3 50       28 return $to if $char eq $via;
77 0 0       0 last unless $extra > -1;
78             }
79             # no such transition exists
80 3         9 return undef;
81             }
82              
83              
84             sub create_trans {
85 3     3 0 5 my $self = shift;
86 3         4 my $from = shift;
87 3         4 my $via = shift;
88 3         3 my $to = shift;
89              
90 3         5 my $ntrans = length($self->{T})/9;
91 3         9 my(undef, undef, $extra) = unpack("lal", substr($self->{S}, $from*9, 9));
92 3 50       9 if($extra == -1){
93 3         9 substr($self->{S}, $from*9+5, 4) = pack("l", $ntrans);
94             }
95 3         8 while($extra > -1){
96 0         0 my $next = unpack("l", substr($self->{T}, $extra*9+5, 4));
97 0 0       0 if($next == 0){
98             # point last trans to new linked trans
99 0         0 substr($self->{T}, $extra*9+5, 4) = pack("l", $ntrans);
100 0         0 last;
101             }
102 0         0 $extra = $next;
103             }
104 3         9 $self->{T} .= pack("all", $via, $to, -1);
105             }
106              
107             sub states {
108 1     1 0 6 my $self = shift;
109 1         4 return length($self->{S})/9;
110             }
111              
112             sub transitions {
113 0     0 0 0 my $self = shift;
114 0         0 return length($self->{T})/9;
115             }
116              
117             sub sl {
118 18     18 0 2888 my $self = shift;
119 18         25 my $state = shift;
120              
121 18         67 return unpack("l", substr($self->{S}, $state*9, 4));
122             }
123              
124              
125             1;
126             __END__