KiCad PCB EDA Suite
Loading...
Searching...
No Matches
mmh3_hash.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2024 Alex Shvartzkop <[email protected]>
5 * Copyright (C) 2024 Kicad Developers, see AUTHORS.txt for contributors.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, you may find one here:
19 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20 * or you may search the http://www.gnu.org website for the version 2 license,
21 * or you may write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23 */
24
25// Based on https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
26//-----------------------------------------------------------------------------
27// MurmurHash3 was written by Austin Appleby, and is placed in the public
28// domain. The author hereby disclaims copyright to this source code.
29
30#ifndef MMH3_HASH_H_
31#define MMH3_HASH_H_
32
33#include <hash_128.h>
34
35//-----------------------------------------------------------------------------
36// Platform-specific functions and macros
37
38// Microsoft Visual Studio
39#if defined( _MSC_VER )
40 #define FORCE_INLINE __forceinline
41 #include <stdlib.h>
42 #define ROTL64( x, y ) _rotl64( x, y )
43 #define BIG_CONSTANT( x ) ( x )
44 // Other compilers
45#else // defined(_MSC_VER)
46 #define FORCE_INLINE inline __attribute__( ( always_inline ) )
47 inline uint64_t mmh3_rotl64( uint64_t x, int8_t r )
48 {
49 return ( x << r ) | ( x >> ( 64 - r ) );
50 }
51 #define ROTL64( x, y ) mmh3_rotl64( x, y )
52 #define BIG_CONSTANT( x ) ( x##LLU )
53#endif // !defined(_MSC_VER)
54
55
60{
61public:
62 MMH3_HASH() { reset( 0 ); };
63
64 MMH3_HASH( uint32_t aSeed ) { reset( aSeed ); }
65
66 FORCE_INLINE void reset( uint32_t aSeed = 0 )
67 {
68 h1 = aSeed;
69 h2 = aSeed;
70 len = 0;
71 }
72
73 FORCE_INLINE void addData( const uint8_t* data, size_t length )
74 {
75 size_t remaining = length;
76
77 while( remaining >= 16 )
78 {
79 memcpy( blocks, data, 16 );
80 hashBlock();
81 data += 16;
82 remaining -= 16;
83 len += 16;
84 }
85
86 if( remaining > 0 )
87 {
88 memcpy( blocks, data, remaining );
89 size_t padding = 4 - ( remaining + 4 ) % 4;
90 memset( reinterpret_cast<uint8_t*>( blocks ) + remaining, 0, padding );
91 len += remaining + padding;
92 }
93 }
94
95 FORCE_INLINE void add( const std::string& input )
96 {
97 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.length() );
98 }
99
100 FORCE_INLINE void add( const std::vector<char>& input )
101 {
102 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.size() );
103 }
104
105 FORCE_INLINE void add( int32_t input )
106 {
107 blocks[( len % 16 ) / 4] = input;
108 len += 4;
109
110 if( len % 16 == 0 )
111 hashBlock();
112 }
113
115 {
116 hashTail();
117
118 HASH_128 h128;
119 hashFinal( h128 );
120
121 return h128;
122 }
123
124private:
125
126 // Block read - if your platform needs to do endian-swapping or can only
127 // handle aligned reads, do the conversion here
128 FORCE_INLINE uint64_t getblock64( int i )
129 {
130 return blocks64[i]; //
131 }
132
134 {
135 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
136 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
137
138 uint64_t k1 = getblock64( 0 );
139 uint64_t k2 = getblock64( 1 );
140
141 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
142
143 h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
144
145 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
146
147 h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
148 }
149
151 {
152 const uint8_t * tail = (const uint8_t*)(blocks);
153
154 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
155 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
156
157 uint64_t k1 = 0;
158 uint64_t k2 = 0;
159
160 switch( len & 15)
161 {
162 case 15: k2 ^= ((uint64_t)tail[14]) << 48; [[fallthrough]];
163 case 14: k2 ^= ((uint64_t)tail[13]) << 40; [[fallthrough]];
164 case 13: k2 ^= ((uint64_t)tail[12]) << 32; [[fallthrough]];
165 case 12: k2 ^= ((uint64_t)tail[11]) << 24; [[fallthrough]];
166 case 11: k2 ^= ((uint64_t)tail[10]) << 16; [[fallthrough]];
167 case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; [[fallthrough]];
168 case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
169 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
170 [[fallthrough]];
171
172 case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; [[fallthrough]];
173 case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; [[fallthrough]];
174 case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; [[fallthrough]];
175 case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; [[fallthrough]];
176 case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; [[fallthrough]];
177 case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; [[fallthrough]];
178 case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; [[fallthrough]];
179 case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
180 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
181 };
182 }
183
184 // Finalization mix - force all bits of a hash block to avalanche
185 static FORCE_INLINE uint64_t fmix64( uint64_t k )
186 {
187 k ^= k >> 33;
188 k *= BIG_CONSTANT( 0xff51afd7ed558ccd );
189 k ^= k >> 33;
190 k *= BIG_CONSTANT( 0xc4ceb9fe1a85ec53 );
191 k ^= k >> 33;
192
193 return k;
194 }
195
197 {
198 h1 ^= len;
199 h2 ^= len;
200
201 h1 += h2;
202 h2 += h1;
203
204 h1 = fmix64( h1 );
205 h2 = fmix64( h2 );
206
207 h1 += h2;
208 h2 += h1;
209
210 out.Value64[0] = h1;
211 out.Value64[1] = h2;
212 }
213
214private:
215 uint64_t h1;
216 uint64_t h2;
217 union
218 {
219 uint32_t blocks[4];
220 uint64_t blocks64[2];
221 };
222 uint32_t len;
223};
224
225
226#undef FORCE_INLINE
227#undef ROTL64
228#undef BIG_CONSTANT
229
230
231#endif // MMH3_HASH_H_
A streaming C++ equivalent for MurmurHash3_x64_128.
Definition: mmh3_hash.h:60
FORCE_INLINE void hashBlock()
Definition: mmh3_hash.h:133
FORCE_INLINE void add(int32_t input)
Definition: mmh3_hash.h:105
uint32_t blocks[4]
Definition: mmh3_hash.h:219
FORCE_INLINE void add(const std::vector< char > &input)
Definition: mmh3_hash.h:100
FORCE_INLINE void addData(const uint8_t *data, size_t length)
Definition: mmh3_hash.h:73
MMH3_HASH()
Definition: mmh3_hash.h:62
FORCE_INLINE void add(const std::string &input)
Definition: mmh3_hash.h:95
FORCE_INLINE HASH_128 digest()
Definition: mmh3_hash.h:114
uint64_t blocks64[2]
Definition: mmh3_hash.h:220
MMH3_HASH(uint32_t aSeed)
Definition: mmh3_hash.h:64
static FORCE_INLINE uint64_t fmix64(uint64_t k)
Definition: mmh3_hash.h:185
uint64_t h2
Definition: mmh3_hash.h:216
FORCE_INLINE void reset(uint32_t aSeed=0)
Definition: mmh3_hash.h:66
FORCE_INLINE uint64_t getblock64(int i)
Definition: mmh3_hash.h:128
uint32_t len
Definition: mmh3_hash.h:222
FORCE_INLINE void hashTail()
Definition: mmh3_hash.h:150
uint64_t h1
Definition: mmh3_hash.h:215
FORCE_INLINE void hashFinal(HASH_128 &out)
Definition: mmh3_hash.h:196
uint64_t mmh3_rotl64(uint64_t x, int8_t r)
Definition: mmh3_hash.h:47
#define ROTL64(x, y)
Definition: mmh3_hash.h:51
#define BIG_CONSTANT(x)
Definition: mmh3_hash.h:52
#define FORCE_INLINE
Definition: mmh3_hash.h:46
A storage class for 128-bit hash value.
Definition: hash_128.h:36
uint64_t Value64[2]
Definition: hash_128.h:61