Murmur3F::rotl64()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 7
c 1
b 0
f 0
ccs 5
cts 5
cp 1
rs 9.4285
cc 1
eloc 5
nc 1
nop 2
crap 1
1
<?php
2
3
namespace Z38\MurmurHash;
4
5
class Murmur3F implements HashInterface
6
{
7
    private $seed;
8
    private $h1;
9
    private $h2;
10
    private $len;
11
    private $tail;
12
    private static $c1;
13
    private static $c2;
14
    private static $m1;
15
    private static $m2;
16
    private static $fmix1;
17
    private static $fmix2;
18
    private static $mask64;
19
20 14
    public function __construct($seed = 0)
21
    {
22 14
        self::init();
23 14
        $this->seed = $seed;
24 14
        $this->reset();
25 14
    }
26
27 14
    public function reset()
28
    {
29 14
        $this->h1 = $this->seed;
30 14
        $this->h2 = $this->seed;
31 14
        $this->len = 0;
32 14
        $this->tail = '';
33 14
    }
34
35 14
    public function write($data)
36
    {
37 14
        $this->len += strlen($data);
38 14
        $this->tail .= $data;
39 14
        while (strlen($this->tail) >= 16) {
40 5
            $k1 = gmp_init(bin2hex(strrev(substr($this->tail, 0, 8))), 16);
41 5
            $k2 = gmp_init(bin2hex(strrev(substr($this->tail, 8, 8))), 16);
42 5
            $this->tail = substr($this->tail, 16);
43
44 5
            $h1 = $this->h1;
45 5
            $h2 = $this->h2;
46
47 5
            $k1 = self::mul64($k1, self::$c1);
48 5
            $k1 = self::rotl64($k1, 31);
49 5
            $k1 = self::mul64($k1, self::$c2);
50 5
            $h1 = gmp_xor($h1, $k1);
51
52 5
            $h1 = self::rotl64($h1, 27);
53 5
            $h1 = self::add64($h1, $h2);
54 5
            $h1 = self::add64(gmp_mul(5, $h1), self::$m1);
55
56 5
            $k2 = self::mul64($k2, self::$c2);
57 5
            $k2 = self::rotl64($k2, 33);
58 5
            $k2 = self::mul64($k2, self::$c1);
59 5
            $h2 = gmp_xor($h2, $k2);
60
61 5
            $h2 = self::rotl64($h2, 31);
62 5
            $h2 = self::add64($h2, $h1);
63 5
            $h2 = self::add64(gmp_mul(5, $h2), self::$m2);
64
65 5
            $this->h1 = $h1;
66 5
            $this->h2 = $h2;
67 5
        }
68 14
    }
69
70 14
    public function sum()
71
    {
72 14
        $h1 = $this->h1;
73 14
        $h2 = $this->h2;
74
75 14
        $k1 = 0;
76 14
        $k2 = 0;
77
78 14
        $tail = array_values(unpack('C*', $this->tail));
79 14
        $len = count($tail);
80 14
        for ($i = $len; $i > 8; --$i) {
81 7
            $k2 = gmp_xor($k2, self::shiftl64($tail[$i - 1], ($i - 9) * 8));
82 7
        }
83 14
        if ($len > 8) {
84 7
            $k2 = self::mul64($k2, self::$c2);
85 7
            $k2 = self::rotl64($k2, 33);
86 7
            $k2 = self::mul64($k2, self::$c1);
87 7
            $h2 = gmp_xor($h2, $k2);
88 7
        }
89 14
        for ($i = min($len, 8); $i > 0; --$i) {
90 13
            $k1 = gmp_xor($k1, self::shiftl64($tail[$i - 1], ($i - 1) * 8));
91 13
        }
92 14
        if ($len > 0) {
93 13
            $k1 = self::mul64($k1, self::$c1);
94 13
            $k1 = self::rotl64($k1, 31);
95 13
            $k1 = self::mul64($k1, self::$c2);
96 13
            $h1 = gmp_xor($h1, $k1);
97 13
        }
98
99 14
        $h1 = gmp_xor($h1, $this->len);
100 14
        $h2 = gmp_xor($h2, $this->len);
101 14
        $h1 = self::add64($h1, $h2);
102 14
        $h2 = self::add64($h2, $h1);
103 14
        $h1 = self::fmix64($h1);
104 14
        $h2 = self::fmix64($h2);
105 14
        $h1 = self::add64($h1, $h2);
106 14
        $h2 = self::add64($h2, $h1);
107
108 14
        return self::export64($h1).self::export64($h2);
109
    }
110
111 14
    private static function init()
112
    {
113 14
        if (self::$c1 !== null) {
114 13
            return;
115
        }
116
117 1
        self::$c1 = gmp_init('0x87c37b91114253d5');
118 1
        self::$c2 = gmp_init('0x4cf5ad432745937f');
119 1
        self::$m1 = gmp_init('0x52dce729');
120 1
        self::$m2 = gmp_init('0x38495ab5');
121 1
        self::$fmix1 = gmp_init('0xff51afd7ed558ccd');
122 1
        self::$fmix2 = gmp_init('0xc4ceb9fe1a85ec53');
123 1
        self::$mask64 = gmp_init('0xffffffffffffffff');
124 1
    }
125
126 14
    private static function fmix64($x)
127
    {
128 14
        $x = gmp_xor($x, self::shiftr($x, 33));
129 14
        $x = self::mul64($x, self::$fmix1);
130 14
        $x = gmp_xor($x, self::shiftr($x, 33));
131 14
        $x = self::mul64($x, self::$fmix2);
132 14
        $x = gmp_xor($x, self::shiftr($x, 33));
133
134 14
        return $x;
135
    }
136
137 13
    private static function rotl64($x, $r)
138
    {
139 13
        return gmp_and(gmp_or(
140 13
            self::shiftl($x, $r),
141 13
            self::shiftr($x, 64 - $r)
142 13
        ), self::$mask64);
143
    }
144
145 14
    private static function export64($x)
146
    {
147 14
        return strrev(pack('H*', str_pad(gmp_strval($x, 16), 16, '0', STR_PAD_LEFT)));
148
    }
149
150 13
    private static function shiftl64($x, $shift)
151
    {
152 13
        return gmp_and(self::shiftl($x, $shift), self::$mask64);
153
    }
154
155 13
    private static function shiftl($x, $shift)
156
    {
157 13
        return gmp_mul($x, gmp_pow(2, $shift));
158
    }
159
160 14
    private static function shiftr($x, $shift)
161
    {
162 14
        return gmp_div($x, gmp_pow(2, $shift));
163
    }
164
165 14
    private static function mul64($a, $b)
166
    {
167 14
        return gmp_and(gmp_mul($a, $b), self::$mask64);
168
    }
169
170 14
    private static function add64($a, $b)
171
    {
172 14
        return gmp_and(gmp_add($a, $b), self::$mask64);
173
    }
174
}
175