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, 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 memset( reinterpret_cast<uint8_t*>( blocks ) + remaining, 0, 16 - remaining );
90 len += remaining;
91 }
92 }
93
94 // Reproduces the pre-fix addData tail handling for reading files saved
95 // before the correction. The old code rounded remaining bytes to 4-byte
96 // alignment, counted padding in len, and only zeroed the padding bytes
97 // (not the full block remainder). This produced wrong hashes but files
98 // were saved with them, so we need to verify against them on load.
99 FORCE_INLINE void addDataV1( const uint8_t* data, size_t length )
100 {
101 size_t remaining = length;
102
103 while( remaining >= 16 )
104 {
105 memcpy( blocks, data, 16 );
106 hashBlock();
107 data += 16;
108 remaining -= 16;
109 len += 16;
110 }
111
112 if( remaining > 0 )
113 {
114 memcpy( blocks, data, remaining );
115 size_t padding = 4 - ( remaining + 4 ) % 4;
116 memset( reinterpret_cast<uint8_t*>( blocks ) + remaining, 0, padding );
117 len += remaining + padding;
118 }
119 }
120
121 FORCE_INLINE void add( const std::string& input )
122 {
123 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.length() );
124 }
125
126 FORCE_INLINE void add( const std::vector<char>& input )
127 {
128 addData( reinterpret_cast<const uint8_t*>( input.data() ), input.size() );
129 }
130
131 FORCE_INLINE void add( int32_t input )
132 {
133 blocks[( len % 16 ) / 4] = input;
134 len += 4;
135
136 if( len % 16 == 0 )
137 hashBlock();
138 }
139
141 {
142 hashTail();
143
144 HASH_128 h128;
145 hashFinal( h128 );
146
147 return h128;
148 }
149
150private:
151
152 // Block read - if your platform needs to do endian-swapping or can only
153 // handle aligned reads, do the conversion here
154 FORCE_INLINE uint64_t getblock64( int i )
155 {
156 return blocks64[i]; //
157 }
158
160 {
161 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
162 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
163
164 uint64_t k1 = getblock64( 0 );
165 uint64_t k2 = getblock64( 1 );
166
167 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
168
169 h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729;
170
171 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
172
173 h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5;
174 }
175
177 {
178 const uint8_t * tail = (const uint8_t*)(blocks);
179
180 static const uint64_t c1 = BIG_CONSTANT( 0x87c37b91114253d5 );
181 static const uint64_t c2 = BIG_CONSTANT( 0x4cf5ad432745937f );
182
183 uint64_t k1 = 0;
184 uint64_t k2 = 0;
185
186 switch( len & 15)
187 {
188 case 15: k2 ^= ((uint64_t)tail[14]) << 48; [[fallthrough]];
189 case 14: k2 ^= ((uint64_t)tail[13]) << 40; [[fallthrough]];
190 case 13: k2 ^= ((uint64_t)tail[12]) << 32; [[fallthrough]];
191 case 12: k2 ^= ((uint64_t)tail[11]) << 24; [[fallthrough]];
192 case 11: k2 ^= ((uint64_t)tail[10]) << 16; [[fallthrough]];
193 case 10: k2 ^= ((uint64_t)tail[ 9]) << 8; [[fallthrough]];
194 case 9: k2 ^= ((uint64_t)tail[ 8]) << 0;
195 k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2;
196 [[fallthrough]];
197
198 case 8: k1 ^= ((uint64_t)tail[ 7]) << 56; [[fallthrough]];
199 case 7: k1 ^= ((uint64_t)tail[ 6]) << 48; [[fallthrough]];
200 case 6: k1 ^= ((uint64_t)tail[ 5]) << 40; [[fallthrough]];
201 case 5: k1 ^= ((uint64_t)tail[ 4]) << 32; [[fallthrough]];
202 case 4: k1 ^= ((uint64_t)tail[ 3]) << 24; [[fallthrough]];
203 case 3: k1 ^= ((uint64_t)tail[ 2]) << 16; [[fallthrough]];
204 case 2: k1 ^= ((uint64_t)tail[ 1]) << 8; [[fallthrough]];
205 case 1: k1 ^= ((uint64_t)tail[ 0]) << 0;
206 k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1;
207 };
208 }
209
210 // Finalization mix - force all bits of a hash block to avalanche
211 static FORCE_INLINE uint64_t fmix64( uint64_t k )
212 {
213 k ^= k >> 33;
214 k *= BIG_CONSTANT( 0xff51afd7ed558ccd );
215 k ^= k >> 33;
216 k *= BIG_CONSTANT( 0xc4ceb9fe1a85ec53 );
217 k ^= k >> 33;
218
219 return k;
220 }
221
223 {
224 h1 ^= len;
225 h2 ^= len;
226
227 h1 += h2;
228 h2 += h1;
229
230 h1 = fmix64( h1 );
231 h2 = fmix64( h2 );
232
233 h1 += h2;
234 h2 += h1;
235
236 out.Value64[0] = h1;
237 out.Value64[1] = h2;
238 }
239
240private:
241 uint64_t h1;
242 uint64_t h2;
243 union
244 {
245 uint32_t blocks[4];
246 uint64_t blocks64[2];
247 };
248 uint32_t len;
249};
250
251
252#undef FORCE_INLINE
253#undef ROTL64
254#undef BIG_CONSTANT
255
256
257#endif // MMH3_HASH_H_
FORCE_INLINE void hashBlock()
Definition mmh3_hash.h:159
FORCE_INLINE void add(int32_t input)
Definition mmh3_hash.h:131
uint32_t blocks[4]
Definition mmh3_hash.h:245
FORCE_INLINE void add(const std::vector< char > &input)
Definition mmh3_hash.h:126
FORCE_INLINE void addData(const uint8_t *data, size_t length)
Definition mmh3_hash.h:73
FORCE_INLINE void addDataV1(const uint8_t *data, size_t length)
Definition mmh3_hash.h:99
FORCE_INLINE void add(const std::string &input)
Definition mmh3_hash.h:121
FORCE_INLINE HASH_128 digest()
Definition mmh3_hash.h:140
uint64_t blocks64[2]
Definition mmh3_hash.h:246
MMH3_HASH(uint32_t aSeed)
Definition mmh3_hash.h:64
static FORCE_INLINE uint64_t fmix64(uint64_t k)
Definition mmh3_hash.h:211
uint64_t h2
Definition mmh3_hash.h:242
FORCE_INLINE void reset(uint32_t aSeed=0)
Definition mmh3_hash.h:66
FORCE_INLINE uint64_t getblock64(int i)
Definition mmh3_hash.h:154
uint32_t len
Definition mmh3_hash.h:248
FORCE_INLINE void hashTail()
Definition mmh3_hash.h:176
uint64_t h1
Definition mmh3_hash.h:241
FORCE_INLINE void hashFinal(HASH_128 &out)
Definition mmh3_hash.h:222
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