-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathfnv.cpp
194 lines (140 loc) · 3.81 KB
/
fnv.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// SPDX-License-Identifier: GPL-3.0-or-later
//
// Copyright (c) 2013-2023 plan44.ch / Lukas Zeller, Zurich, Switzerland
//
// Author: Lukas Zeller <luz@plan44.ch>
//
// This file is part of p44utils.
//
// p44utils is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// p44utils is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with p44utils. If not, see <http://www.gnu.org/licenses/>.
//
#include "fnv.hpp"
// Using the FNV hash: http://www.isthe.com/chongo/tech/comp/fnv/
// There is a minor variation of the FNV hash algorithm known as FNV-1a:
// hash = offset_basis
// for each octet_of_data to be hashed
// hash = hash xor octet_of_data
// hash = hash * FNV_prime
// return hash
//
// For 32bit FNV hash:
// FNV_prime = 16777619
// offset_basis = 2166136261
static const uint32_t FNV32_prime = 16777619ul;
static const uint32_t FNV32_offset_basis = 2166136261ul;
using namespace p44;
Fnv32::Fnv32()
{
reset();
}
Fnv32::Fnv32(uint32_t aBasedOn)
{
hash = aBasedOn; // continue a previously calculated hash
}
void Fnv32::reset()
{
hash = FNV32_offset_basis;
}
void Fnv32::addByte(uint8_t aByte)
{
hash ^= aByte;
hash *= FNV32_prime;
}
void Fnv32::addBytes(size_t aNumBytes, const uint8_t *aBytesP)
{
for (size_t i=0; i<aNumBytes; ++i) {
addByte(aBytesP[i]);
}
}
void Fnv32::addString(const string aString)
{
addBytes(aString.size(), (uint8_t *)aString.c_str());
}
void Fnv32::addCStr(const char *aCStr)
{
while (char c = *aCStr++)
addByte(c);
}
uint32_t Fnv32::getHash() const
{
return hash;
}
static const uint64_t FNV64_prime = 1099511628211ull;
static const uint64_t FNV64_offset_basis = 14695981039346656037ull;
Fnv64::Fnv64()
{
reset();
}
Fnv64::Fnv64(uint64_t aBasedOn)
{
hash = aBasedOn; // continue a previously calculated hash
}
void Fnv64::reset()
{
hash = FNV64_offset_basis;
}
void Fnv64::addByte(uint8_t aByte)
{
hash ^= aByte;
hash *= FNV64_prime;
}
void Fnv64::addBytes(size_t aNumBytes, const uint8_t *aBytesP)
{
for (size_t i=0; i<aNumBytes; ++i) {
addByte(aBytesP[i]);
}
}
void Fnv64::addCStr(const char *aCStr)
{
while (char c = *aCStr++)
addByte(c);
}
void Fnv64::addString(const string aString)
{
addBytes(aString.size(), (uint8_t *)aString.c_str());
}
uint64_t Fnv64::getHash() const
{
return hash;
}
// MARK: - folded down variants with less bits
// for non 2^x bit sized hashes, recommened practice is x-or folding:
// If you need an x-bit hash where x is not a power of 2, then we recommend
// that you compute the FNV hash that is just larger than x-bits and xor-fold
// the result down to x-bits. By xor-folding we mean shift the excess high order
// bits down and xor them with the lower x-bits.
#define MASK_48 (((uint64_t)1<<48)-1) /* i.e., (uint64_t)0xffffffffffff */
uint64_t Fnv64::getHash48() const
{
return (hash>>48) ^ (hash & MASK_48);
}
#define MASK_36 (((uint64_t)1<<36)-1) /* i.e., (uint64_t)0xffffffff */
uint64_t Fnv64::getHash36() const
{
return (hash>>36) ^ (hash & MASK_36);
}
#define MASK_32 (((uint64_t)1<<32)-1) /* i.e., (uint64_t)0xfffffff */
uint64_t Fnv64::getHash32() const
{
return (hash>>32) ^ (hash & MASK_32);
}
#define MASK_28 (((uint64_t)1<<28)-1) /* i.e., (uint64_t)0xffffffffffff */
uint32_t Fnv32::getHash28() const
{
return (hash>>28) ^ (hash & MASK_28);
}
uint32_t Fnv64::getHash28() const
{
return (uint32_t)((hash>>28) ^ (hash & MASK_28));
}