File Coverage

blib/lib/Digest/MurmurHash3/PurePerl.pm
Criterion Covered Total %
statement 197 197 100.0
branch 36 36 100.0
condition n/a
subroutine 16 16 100.0
pod 2 2 100.0
total 251 251 100.0


line stmt bran cond sub pod time code
1             package Digest::MurmurHash3::PurePerl;
2 2     2   58181 use strict;
  2         6  
  2         65  
3 2     2   10 use warnings;
  2         5  
  2         47  
4 2     2   42 use 5.008008;
  2         11  
  2         90  
5 2     2   19 use base 'Exporter';
  2         3  
  2         1097  
6              
7             our $VERSION = '1.01';
8              
9             our @EXPORT = qw(murmur32 murmur128);
10              
11             sub murmur32 {
12 4     4 1 6362 my ( $key, $seed ) = @_;
13 4 100       13 if ( !defined $seed ) {
14 2         4 $seed = 0;
15             }
16              
17 4         11 utf8::encode($key);
18 4         6 my $len = length($key);
19 4         11 my $num_blocks = int( $len / 4 );
20 4         7 my $tail_len = $len % 4;
21 4         19 my @vals = unpack 'V*C*', $key;
22 4         10 my @tail = splice( @vals, scalar(@vals) - $tail_len, $tail_len );
23 4         7 my $h1 = $seed;
24              
25 4         7 for my $block (@vals) {
26 34         29 my $k1 = $block;
27 34         48 $h1 ^= _mmix32($k1);
28 34         41 $h1 = _rotl32( $h1, 13 );
29 2     2   2048 use integer;
  2         22  
  2         11  
30 34         69 $h1 = _to_uint32( $h1 * 5 + 0xe6546b64 );
31             }
32              
33 4 100       12 if ( $tail_len > 0 ) {
34 2         4 my $k1 = 0;
35 2         4 for my $c1 ( reverse @tail ) {
36 2         61 $k1 = ( ( $k1 << 8 ) | $c1 );
37             }
38 2         32 $k1 = _mmix32($k1);
39 2         35 $h1 = ( $h1 ^ $k1 );
40             }
41 4         6 $h1 = ( $h1 ^ $len );
42 4         7 $h1 = _fmix32($h1);
43 4         11 return $h1;
44             }
45              
46             sub murmur128 {
47 5     5 1 8186 my ( $key, $seed ) = @_;
48 5 100       20 if ( !defined $seed ) {
49 3         7 $seed = 0;
50             }
51 5         10 my ( $h1, $h2, $h3, $h4 ) = ( $seed, $seed, $seed, $seed );
52              
53 5         7 my $c1 = 0x239b961b;
54 5         7 my $c2 = 0xab0e9789;
55 5         7 my $c3 = 0x38b34ae5;
56 5         5 my $c4 = 0xa1e38b93;
57              
58 5         15 utf8::encode($key);
59 5         6 my $len = length($key);
60 5         13 my $num_blocks = int( $len / 16 );
61 5         25 my @vals = unpack 'V*C*', $key;
62 5         9 my ( $k1, $k2, $k3, $k4 );
63              
64 2     2   678 use integer;
  2         4  
  2         7  
65              
66 5         19 for ( my $i = 0; $i < $num_blocks; $i++ ) {
67 8         14 $k1 = $vals[ $i * 4 + 0 ];
68 8         13 $k2 = $vals[ $i * 4 + 1 ];
69 8         10 $k3 = $vals[ $i * 4 + 2 ];
70 8         10 $k4 = $vals[ $i * 4 + 3 ];
71              
72 8         16 $k1 = _to_uint32( $k1 * $c1 );
73 8         12 $k1 = _rotl32( $k1, 15 );
74 8         14 $k1 = _to_uint32( $k1 * $c2 );
75 8         9 $h1 ^= $k1;
76 8         14 $h1 = _rotl32( $h1, 19 );
77 8         22 $h1 = _to_uint32( $h1 + $h2 );
78 8         18 $h1 = _to_uint32( $h1 * 5 + 0x561ccd1b );
79              
80 8         12 $k2 = _to_uint32( $k2 * $c2 );
81 8         19 $k2 = _rotl32( $k2, 16 );
82 8         18 $k2 = _to_uint32( $k2 * $c3 );
83 8         10 $h2 ^= $k2;
84 8         13 $h2 = _rotl32( $h2, 17 );
85 8         16 $h2 = _to_uint32( $h2 + $h3 );
86 8         15 $h2 = _to_uint32( $h2 * 5 + 0x0bcaa747 );
87              
88 8         14 $k3 = _to_uint32( $k3 * $c3 );
89 8         15 $k3 = _rotl32( $k3, 17 );
90 8         16 $k3 = _to_uint32( $k3 * $c4 );
91 8         11 $h3 ^= $k3;
92 8         10 $h3 = _rotl32( $h3, 15 );
93 8         15 $h3 = _to_uint32( $h3 + $h4 );
94 8         15 $h3 = _to_uint32( $h3 * 5 + 0x96cd1c35 );
95              
96 8         16 $k4 = _to_uint32( $k4 * $c4 );
97 8         13 $k4 = _rotl32( $k4, 18 );
98 8         13 $k4 = _to_uint32( $k4 * $c1 );
99 8         9 $h4 ^= $k4;
100 8         17 $h4 = _rotl32( $h4, 13 );
101 8         16 $h4 = _to_uint32( $h4 + $h1 );
102 8         16 $h4 = _to_uint32( $h4 * 5 + 0x32ac3b17 );
103             }
104              
105 5         23 my $tail_len = $len % 16;
106 5         7 my @tail;
107 5         8 my $sblock_num = int( $tail_len / 4 );
108 5         14 for ( my $i = 0; $i < $sblock_num; $i++ ) {
109 5         23 my @tmp = unpack 'C4', pack( 'V', $vals[ $num_blocks * 4 + $i ] );
110 5         17 push @tail, @tmp;
111             }
112 5         13 for ( my $i = $num_blocks * 4 + $sblock_num; $i < scalar(@vals); $i++ ) {
113 5         13 push @tail, $vals[$i];
114             }
115              
116 5         5 $k1 = 0;
117 5         6 $k2 = 0;
118 5         6 $k3 = 0;
119 5         4 $k4 = 0;
120              
121             {
122 5         7 my $len_lo4 = $len & 0x0F;
  5         6  
123 5 100       12 if ( $len_lo4 == 15 ) { $k4 ^= $tail[14] << 16; }
  1         2  
124 5 100       13 if ( $len_lo4 >= 14 ) { $k4 ^= $tail[13] << 8; }
  1         2  
125 5 100       670 if ( $len_lo4 >= 13 ) {
126            
127 1         2 $k4 ^= $tail[12] << 0;
128 1         3 $k4 = _to_uint32( $k4 * $c4 );
129 1         32 $k4 = _rotl32( $k4, 18 );
130 1         10 $k4 = _to_uint32( $k4 * $c1 );
131 1         1 $h4 ^= $k4;
132             }
133 5 100       14 if ( $len_lo4 >= 12 ) { $k3 ^= $tail[11] << 24; }
  1         2  
134 5 100       9 if ( $len_lo4 >= 11 ) { $k3 ^= $tail[10] << 16; }
  1         2  
135 5 100       12 if ( $len_lo4 >= 10 ) { $k3 ^= $tail[9] << 8; }
  1         2  
136 5 100       11 if ( $len_lo4 >= 9 ) {
137 1         1 $k3 ^= $tail[8] << 0;
138 1         4 $k3 = _to_uint32( $k3 * $c3 );
139 1         3 $k3 = _rotl32( $k3, 17 );
140 1         4 $k3 = _to_uint32( $k3 * $c4 );
141 1         2 $h3 ^= $k3;
142             }
143              
144 5 100       9 if ( $len_lo4 >= 8 ) { $k2 ^= $tail[7] << 24; }
  1         2  
145 5 100       11 if ( $len_lo4 >= 7 ) { $k2 ^= $tail[6] << 16; }
  1         2  
146 5 100       11 if ( $len_lo4 >= 6 ) { $k2 ^= $tail[5] << 8; }
  1         2  
147 5 100       10 if ( $len_lo4 >= 5 ) {
148 3         6 $k2 ^= $tail[4] << 0;
149 3         7 $k2 = _to_uint32( $k2 * $c2 );
150 3         7 $k2 = _rotl32( $k2, 16 );
151 3         6 $k2 = _to_uint32( $k2 * $c3 );
152 3         4 $h2 ^= $k2;
153             }
154 5 100       10 if ( $len_lo4 >= 4 ) { $k1 ^= $tail[3] << 24; }
  3         4  
155 5 100       11 if ( $len_lo4 >= 3 ) { $k1 ^= $tail[2] << 16; }
  3         6  
156 5 100       10 if ( $len_lo4 >= 2 ) { $k1 ^= $tail[1] << 8; }
  3         5  
157 5 100       10 if ( $len_lo4 >= 1 ) {
158 3         4 $k1 ^= $tail[0] << 0;
159 3         6 $k1 = _to_uint32( $k1 * $c1 );
160 3         7 $k1 = _rotl32( $k1, 15 );
161 3         7 $k1 = _to_uint32( $k1 * $c2 );
162 3         6 $h1 ^= $k1;
163             }
164              
165 5         6 $h1 ^= $len;
166 5         5 $h2 ^= $len;
167 5         6 $h3 ^= $len;
168 5         6 $h4 ^= $len;
169              
170 5         11 $h1 = _to_uint32( $h1 + $h2 );
171 5         10 $h1 = _to_uint32( $h1 + $h3 );
172 5         9 $h1 = _to_uint32( $h1 + $h4 );
173 5         7 $h2 = _to_uint32( $h2 + $h1 );
174 5         9 $h3 = _to_uint32( $h3 + $h1 );
175 5         9 $h4 = _to_uint32( $h4 + $h1 );
176              
177 5         9 $h1 = _fmix32($h1);
178 5         10 $h2 = _fmix32($h2);
179 5         10 $h3 = _fmix32($h3);
180 5         8 $h4 = _fmix32($h4);
181              
182 5         10 $h1 = _to_uint32( $h1 + $h2 );
183 5         11 $h1 = _to_uint32( $h1 + $h3 );
184 5         9 $h1 = _to_uint32( $h1 + $h4 );
185 5         9 $h2 = _to_uint32( $h2 + $h1 );
186 5         7 $h3 = _to_uint32( $h3 + $h1 );
187 5         10 $h4 = _to_uint32( $h4 + $h1 );
188             }
189 5         23 return ( $h1, $h2, $h3, $h4 );
190             }
191              
192             sub _rotl32 {
193 142     142   227 my ( $x, $r ) = @_;
194 142         209 return ( ( $x << $r ) | ( $x >> ( 32 - $r ) ) );
195             }
196              
197             sub _fmix32 {
198 24     24   27 my $h = shift;
199 24         29 $h = ( $h ^ ( $h >> 16 ) );
200             {
201 2     2   2371 use integer;
  2         5  
  2         7  
  24         28  
202 24         41 $h = _to_uint32( $h * 0x85ebca6b );
203             }
204 24         30 $h = ( $h ^ ( $h >> 13 ) );
205             {
206 2     2   90 use integer;
  2         2  
  2         8  
  24         22  
207 24         36 $h = _to_uint32( $h * 0xc2b2ae35 );
208             }
209 24         67 $h = ( $h ^ ( $h >> 16 ) );
210 24         29 return $h;
211             }
212              
213             sub _mmix32 {
214 36     36   34 my $k1 = shift;
215 2     2   143 use integer;
  2         3  
  2         8  
216 36         42 $k1 = _to_uint32( $k1 * 0xcc9e2d51 );
217 36         49 $k1 = _rotl32( $k1, 15 );
218 36         49 return _to_uint32( $k1 * 0x1b873593 );
219             }
220              
221             sub _to_uint32 {
222 2     2   140 no integer;
  2         8  
  2         8  
223 358     358   527 return $_[0] & 0xFFFFFFFF;
224             }
225              
226             1;
227             __END__