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 The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21// Based on https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
22//-----------------------------------------------------------------------------
23// MurmurHash3 was written by Austin Appleby, and is placed in the public
24// domain. The author hereby disclaims copyright to this source code.
25
26#ifndef MMH3_HASH_H_
27#define MMH3_HASH_H_
28
29#include <hash_128.h>
30
31#include <algorithm>
32#include <cstring>
33#include <string>
34#include <vector>
35
36//-----------------------------------------------------------------------------
37// Platform-specific functions and macros
38
39// Microsoft Visual Studio
40#if defined( _MSC_VER )
41 #define FORCE_INLINE __forceinline
42 #include <stdlib.h>
43 #define ROTL64( x, y ) _rotl64( x, y )
44 #define BIG_CONSTANT( x ) ( x )
45 // Other compilers
46#else // defined(_MSC_VER)
47 #define FORCE_INLINE inline __attribute__( ( always_inline ) )
48 inline uint64_t mmh3_rotl64( uint64_t x, int8_t r )
49 {
50 return ( x << r ) | ( x >> ( 64 - r ) );
51 }
52 #define ROTL64( x, y ) mmh3_rotl64( x, y )
53 #define BIG_CONSTANT( x ) ( x##LLU )
54#endif // !defined(_MSC_VER)
55
56
61{
62public:
63 MMH3_HASH() { reset( 0 ); };
64
65 MMH3_HASH( uint32_t aSeed ) { reset( aSeed ); }
66
67 FORCE_INLINE void reset( uint32_t aSeed = 0 )
68 {
69 h1 = aSeed;
70 h2 = aSeed;
71 len = 0;
72 }
73
74 FORCE_INLINE void addData( const uint8_t* data, size_t length )
75 {
76 size_t remaining = length;
77 size_t pending = len % 16;
78
79 // Complete a block an earlier call left partial, so data may arrive in pieces of any size
80 if( pending > 0 && remaining > 0 )
81 {
82 size_t fill = std::min( remaining, 16 - pending );
83 memcpy( reinterpret_cast<uint8_t*>( blocks ) + pending, data, fill );
84 data += fill;
85 remaining -= fill;
86 len += fill;
87
88 if( len % 16 != 0 )
89 return;
90
91 hashBlock();
92 }
93
94 while( remaining >= 16 )
95 {
96 memcpy( blocks, data, 16 );
97 hashBlock();
98 data += 16;
99 remaining -= 16;
100 len += 16;
101 }
102
103 if( remaining > 0 )
104 {
105 memcpy( blocks, data, remaining );
106 memset( reinterpret_cast<uint8_t*>( blocks ) + remaining, 0, 16 - remaining );
107 len += remaining;
108 }
109 }
110
111 // Reproduces the pre-fix addData tail handling for reading files saved
112 // before the correction. The old code rounded remaining bytes to 4-byte
113 // alignment, counted padding in len, and only zeroed the padding bytes
114 // (not the full block remainder). This produced wrong hashes but files
115 // were saved with them, so we need to verify against them on load.
116 FORCE_INLINE void addDataV1( const uint8_t* data, size_t length )
117 {
118 size_t remaining = length;
119
120 while( remaining >= 16 )
121 {
122 memcpy( blocks, data, 16 );
123 hashBlock();
124 data += 16;
125 remaining -= 16;
126 len += 16;
127 }
128
129 if( remaining > 0 )
130 {
131 memcpy( blocks, data, remaining );
132 size_t padding = 4 - ( remaining + 4 ) % 4;
133 memset( reinterpret_cast<uint8_t*>( blocks ) + remaining, 0, padding );
134 len += remaining + padding;
135 }
136 }
137
138 FORCE_INLINE void add( const std::string& input )
139 {
140 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.length() );
141 }
142
143 FORCE_INLINE void add( const std::vector<char>& input )
144 {
145 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.size() );
146 }
147
148 FORCE_INLINE void add( int32_t input )
149 {
150 blocks[( len % 16 ) / 4] = input;
151 len += 4;
152
153 if( len % 16 == 0 )
154 hashBlock();
155 }
156
158 {
159 hashTail();
160
161 HASH_128 h128;
162 hashFinal( h128 );
163
164 return h128;
165 }
166
167private:
168
169 // Block read - if your platform needs to do endian-swapping or can only
170 // handle aligned reads, do the conversion here
171 FORCE_INLINE uint64_t getblock64( int i )
172 {
173 return blocks64[i]; //
174 }
175
177 {
178 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
179 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
180
181 uint64_t k1 = getblock64( 0 );
182 uint64_t k2 = getblock64( 1 );
183
184 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
185
186 h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
187
188 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
189
190 h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
191 }
192
194 {
195 const uint8_t * tail = (const uint8_t*)(blocks);
196
197 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
198 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
199
200 uint64_t k1 = 0;
201 uint64_t k2 = 0;
202
203 switch( len & 15)
204 {
205 case 15: k2 ^= ((uint64_t)tail[14]) << 48; [[fallthrough]];
206 case 14: k2 ^= ((uint64_t)tail[13]) << 40; [[fallthrough]];
207 case 13: k2 ^= ((uint64_t)tail[12]) << 32; [[fallthrough]];
208 case 12: k2 ^= ((uint64_t)tail[11]) << 24; [[fallthrough]];
209 case 11: k2 ^= ((uint64_t)tail[10]) << 16; [[fallthrough]];
210 case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; [[fallthrough]];
211 case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
212 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
213 [[fallthrough]];
214
215 case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; [[fallthrough]];
216 case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; [[fallthrough]];
217 case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; [[fallthrough]];
218 case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; [[fallthrough]];
219 case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; [[fallthrough]];
220 case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; [[fallthrough]];
221 case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; [[fallthrough]];
222 case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
223 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
224 };
225 }
226
227 // Finalization mix - force all bits of a hash block to avalanche
228 static FORCE_INLINE uint64_t fmix64( uint64_t k )
229 {
230 k ^= k >> 33;
231 k *= BIG_CONSTANT( 0xff51afd7ed558ccd );
232 k ^= k >> 33;
233 k *= BIG_CONSTANT( 0xc4ceb9fe1a85ec53 );
234 k ^= k >> 33;
235
236 return k;
237 }
238
240 {
241 h1 ^= len;
242 h2 ^= len;
243
244 h1 += h2;
245 h2 += h1;
246
247 h1 = fmix64( h1 );
248 h2 = fmix64( h2 );
249
250 h1 += h2;
251 h2 += h1;
252
253 out.Value64[0] = h1;
254 out.Value64[1] = h2;
255 }
256
257private:
258 uint64_t h1;
259 uint64_t h2;
260 union
261 {
262 uint32_t blocks[4];
263 uint64_t blocks64[2];
264 };
265 uint32_t len;
266};
267
268
269#undef FORCE_INLINE
270#undef ROTL64
271#undef BIG_CONSTANT
272
273
274#endif // MMH3_HASH_H_
FORCE_INLINE void hashBlock()
Definition mmh3_hash.h:176
FORCE_INLINE void add(int32_t input)
Definition mmh3_hash.h:148
uint32_t blocks[4]
Definition mmh3_hash.h:262
FORCE_INLINE void add(const std::vector< char > &input)
Definition mmh3_hash.h:143
FORCE_INLINE void addData(const uint8_t *data, size_t length)
Definition mmh3_hash.h:74
FORCE_INLINE void addDataV1(const uint8_t *data, size_t length)
Definition mmh3_hash.h:116
FORCE_INLINE void add(const std::string &input)
Definition mmh3_hash.h:138
FORCE_INLINE HASH_128 digest()
Definition mmh3_hash.h:157
uint64_t blocks64[2]
Definition mmh3_hash.h:263
MMH3_HASH(uint32_t aSeed)
Definition mmh3_hash.h:65
static FORCE_INLINE uint64_t fmix64(uint64_t k)
Definition mmh3_hash.h:228
uint64_t h2
Definition mmh3_hash.h:259
FORCE_INLINE void reset(uint32_t aSeed=0)
Definition mmh3_hash.h:67
FORCE_INLINE uint64_t getblock64(int i)
Definition mmh3_hash.h:171
uint32_t len
Definition mmh3_hash.h:265
FORCE_INLINE void hashTail()
Definition mmh3_hash.h:193
uint64_t h1
Definition mmh3_hash.h:258
FORCE_INLINE void hashFinal(HASH_128 &out)
Definition mmh3_hash.h:239
uint64_t mmh3_rotl64(uint64_t x, int8_t r)
Definition mmh3_hash.h:48
#define ROTL64(x, y)
Definition mmh3_hash.h:52
#define BIG_CONSTANT(x)
Definition mmh3_hash.h:53
#define FORCE_INLINE
Definition mmh3_hash.h:47
A storage class for 128-bit hash value.
Definition hash_128.h:33
uint64_t Value64[2]
Definition hash_128.h:58