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__ |