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