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