line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# A memory-efficient, but slow, single-string structure with a hash interface. |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# <@LICENSE> |
4
|
|
|
|
|
|
|
# Licensed to the Apache Software Foundation (ASF) under one or more |
5
|
|
|
|
|
|
|
# contributor license agreements. See the NOTICE file distributed with |
6
|
|
|
|
|
|
|
# this work for additional information regarding copyright ownership. |
7
|
|
|
|
|
|
|
# The ASF licenses this file to you under the Apache License, Version 2.0 |
8
|
|
|
|
|
|
|
# (the "License"); you may not use this file except in compliance with |
9
|
|
|
|
|
|
|
# the License. You may obtain a copy of the License at: |
10
|
|
|
|
|
|
|
# |
11
|
|
|
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0 |
12
|
|
|
|
|
|
|
# |
13
|
|
|
|
|
|
|
# Unless required by applicable law or agreed to in writing, software |
14
|
|
|
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS, |
15
|
|
|
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
16
|
|
|
|
|
|
|
# See the License for the specific language governing permissions and |
17
|
|
|
|
|
|
|
# limitations under the License. |
18
|
|
|
|
|
|
|
# </@LICENSE> |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
package Mail::SpamAssassin::Util::TieOneStringHash; |
21
|
|
|
|
|
|
|
|
22
|
40
|
|
|
40
|
|
287
|
use strict; |
|
40
|
|
|
|
|
98
|
|
|
40
|
|
|
|
|
1220
|
|
23
|
40
|
|
|
40
|
|
221
|
use warnings; |
|
40
|
|
|
|
|
84
|
|
|
40
|
|
|
|
|
1146
|
|
24
|
40
|
|
|
40
|
|
212
|
use re 'taint'; |
|
40
|
|
|
|
|
87
|
|
|
40
|
|
|
|
|
1325
|
|
25
|
40
|
|
|
40
|
|
229
|
use Carp qw(croak); |
|
40
|
|
|
|
|
80
|
|
|
40
|
|
|
|
|
21103
|
|
26
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our @ISA = qw(); |
28
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
# the structure is pretty simple: it's a single string, containing |
30
|
|
|
|
|
|
|
# items like so: |
31
|
|
|
|
|
|
|
# |
32
|
|
|
|
|
|
|
# \n KEY 0x00 VALUE 0x00 \n |
33
|
|
|
|
|
|
|
# \n KEY2 0x00 VALUE2 0x00 \n |
34
|
|
|
|
|
|
|
# ... |
35
|
|
|
|
|
|
|
# |
36
|
|
|
|
|
|
|
# undef values are represented using $UNDEF_VALUE, a hacky magic string. |
37
|
|
|
|
|
|
|
# Only simple scalars can be stored; refs of any kind produce a croak(). |
38
|
|
|
|
|
|
|
# |
39
|
|
|
|
|
|
|
# writes are slowest, reads are slow, but memory usage is very low |
40
|
|
|
|
|
|
|
# compared to a "real" hash table -- in other words, this is perfect |
41
|
|
|
|
|
|
|
# for infrequently-read data that has to be kept around but should |
42
|
|
|
|
|
|
|
# affect memory usage as little as possible. |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $UNDEF_VALUE = "_UNDEF_\001"; |
45
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
########################################################################### |
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
sub TIEHASH { |
49
|
81
|
|
|
81
|
|
418
|
my $class = shift; |
50
|
81
|
|
|
|
|
379
|
my $str = ''; |
51
|
81
|
|
|
|
|
1038
|
return bless \$str, $class; |
52
|
|
|
|
|
|
|
} |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub STORE { |
55
|
1744
|
|
|
1744
|
|
3841
|
my ($store, $k, $v) = @_; |
56
|
1744
|
50
|
|
|
|
3118
|
$v = $UNDEF_VALUE unless defined($v); |
57
|
|
|
|
|
|
|
|
58
|
1744
|
50
|
|
|
|
3058
|
if (ref $v) { |
59
|
0
|
|
|
|
|
0
|
croak "oops! only simple scalars can be stored in a TieOneStringHash"; |
60
|
|
|
|
|
|
|
} |
61
|
1744
|
50
|
|
|
|
2983
|
if (!defined $k) { |
62
|
0
|
|
|
|
|
0
|
croak "oops! TieOneStringHash requires defined keys"; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
1744
|
100
|
|
|
|
26477
|
if ($$store !~ s{\n\Q$k\E\000.*?\000\n} |
66
|
|
|
|
|
|
|
{\n$k\000$v\000\n}xgs) |
67
|
1681
|
|
|
|
|
7726
|
{ |
68
|
|
|
|
|
|
|
$$store .= "\n$k\000$v\000\n"; |
69
|
1744
|
|
|
|
|
6254
|
} |
70
|
|
|
|
|
|
|
1; |
71
|
|
|
|
|
|
|
} |
72
|
|
|
|
|
|
|
|
73
|
1909
|
|
|
1909
|
|
6008
|
sub FETCH { |
74
|
1909
|
100
|
|
|
|
28734
|
my ($store, $k) = @_; |
75
|
|
|
|
|
|
|
if ($$store =~ m{\n\Q$k\E\000(.*?)\000\n}xs) |
76
|
1796
|
50
|
|
|
|
10723
|
{ |
77
|
|
|
|
|
|
|
return $1 eq $UNDEF_VALUE ? undef : $1; |
78
|
113
|
|
|
|
|
475
|
} |
79
|
|
|
|
|
|
|
return; |
80
|
|
|
|
|
|
|
} |
81
|
|
|
|
|
|
|
|
82
|
3378
|
|
|
3378
|
|
5733
|
sub EXISTS { |
83
|
3378
|
100
|
|
|
|
31362
|
my ($store, $k) = @_; |
84
|
|
|
|
|
|
|
if ($$store =~ m{\n\Q$k\E\000}xs) |
85
|
1628
|
|
|
|
|
6159
|
{ |
86
|
|
|
|
|
|
|
return 1; |
87
|
1750
|
|
|
|
|
5256
|
} |
88
|
|
|
|
|
|
|
return; |
89
|
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
0
|
|
|
0
|
|
0
|
sub DELETE { |
92
|
0
|
0
|
|
|
|
0
|
my ($store, $k) = @_; |
93
|
|
|
|
|
|
|
if ($$store =~ s{\n\Q$k\E\000(.*?)\000\n} |
94
|
0
|
0
|
|
|
|
0
|
{}xgs) |
95
|
|
|
|
|
|
|
{ |
96
|
0
|
|
|
|
|
0
|
return $1 eq $UNDEF_VALUE ? undef : $1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
return; |
99
|
|
|
|
|
|
|
} |
100
|
34
|
|
|
34
|
|
122
|
|
101
|
34
|
50
|
|
|
|
262
|
sub FIRSTKEY { |
102
|
|
|
|
|
|
|
my ($store) = @_; |
103
|
34
|
|
|
|
|
286
|
if ($$store =~ m{^\n(.*?)\000}s) |
104
|
|
|
|
|
|
|
{ |
105
|
0
|
|
|
|
|
0
|
return $1; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
return; |
108
|
|
|
|
|
|
|
} |
109
|
885
|
|
|
885
|
|
1570
|
|
110
|
885
|
100
|
|
|
|
13271
|
sub NEXTKEY { |
111
|
|
|
|
|
|
|
my ($store, $lastk) = @_; |
112
|
|
|
|
|
|
|
if ($$store =~ m{\n\Q$lastk\E\000.*?\000\n |
113
|
851
|
|
|
|
|
3980
|
\n(.*?)\000}xs) |
114
|
|
|
|
|
|
|
{ |
115
|
34
|
|
|
|
|
174
|
return $1; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
return; |
118
|
|
|
|
|
|
|
} |
119
|
2
|
|
|
2
|
|
5
|
|
120
|
2
|
|
|
|
|
19
|
sub CLEAR { |
121
|
|
|
|
|
|
|
my ($store) = @_; |
122
|
|
|
|
|
|
|
$$store = ''; |
123
|
|
|
|
|
|
|
} |
124
|
0
|
|
|
0
|
|
|
|
125
|
0
|
|
|
|
|
|
sub SCALAR { |
126
|
|
|
|
|
|
|
my ($store) = @_; |
127
|
|
|
|
|
|
|
return $$store; # as a string! |
128
|
|
|
|
|
|
|
} |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
1; |