Coverage Report

Created: 2024-11-21 16:04

/root/doris/be/src/gutil/hash/city.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright 2010 Google Inc. All Rights Reserved.
2
// Authors: gpike@google.com (Geoff Pike), jyrki@google.com (Jyrki Alakuijala)
3
//
4
// This file provides CityHash64() and related functions.
5
//
6
// The externally visible functions follow the naming conventions of
7
// hash.h, where the size of the output is part of the name.  For
8
// example, CityHash64 returns a 64-bit hash.  The internal helpers do
9
// not have the return type in their name, but instead have names like
10
// HashLenXX or HashLenXXtoYY, where XX and YY are input string lengths.
11
//
12
// Most of the constants and tricks here were copied from murmur.cc or
13
// hash.h, or discovered by trial and error.  It's probably possible to further
14
// optimize the code here by writing a program that systematically explores
15
// more of the space of possible hash functions, or by using SIMD instructions.
16
17
#include "gutil/hash/city.h"
18
19
// IWYU pragma: no_include <pstl/glue_algorithm_defs.h>
20
21
#include <sys/types.h>
22
#include <algorithm>
23
#include <iterator>
24
25
using std::copy;
26
using std::max;
27
using std::min;
28
using std::reverse;
29
using std::sort;
30
using std::swap;
31
#include <utility>
32
33
using std::make_pair;
34
using std::pair;
35
36
#include "common/logging.h"
37
38
#include "gutil/endian.h"
39
#include "gutil/hash/hash128to64.h"
40
#include "gutil/int128.h"
41
#include "gutil/integral_types.h"
42
#include "gutil/port.h"
43
44
namespace util_hash {
45
46
// Some primes between 2^63 and 2^64 for various uses.
47
static const uint64 k0 = 0xa5b85c5e198ed849ULL;
48
static const uint64 k1 = 0x8d58ac26afe12e47ULL;
49
static const uint64 k2 = 0xc47b6e9e3a970ed3ULL;
50
static const uint64 k3 = 0xc70f6907e782aa0bULL;
51
52
// Bitwise right rotate.  Normally this will compile to a single
53
// instruction, especially if the shift is a manifest constant.
54
14.5k
static uint64 Rotate(uint64 val, int shift) {
55
14.5k
    DCHECK_GE(shift, 0);
56
14.5k
    DCHECK_LE(shift, 63);
57
    // Avoid shifting by 64: doing so yields an undefined result.
58
14.5k
    return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
59
14.5k
}
60
61
// Equivalent to Rotate(), but requires the second arg to be non-zero.
62
// On x86-64, and probably others, it's possible for this to compile
63
// to a single instruction if both args are already in registers.
64
1.84k
static uint64 RotateByAtLeast1(uint64 val, int shift) {
65
1.84k
    DCHECK_GE(shift, 1);
66
1.84k
    DCHECK_LE(shift, 63);
67
1.84k
    return (val >> shift) | (val << (64 - shift));
68
1.84k
}
69
70
2.54k
static uint64 ShiftMix(uint64 val) {
71
2.54k
    return val ^ (val >> 47);
72
2.54k
}
73
74
9.46k
static uint64 HashLen16(uint64 u, uint64 v) {
75
9.46k
    return Hash128to64(uint128(u, v));
76
9.46k
}
77
78
7.13k
static uint64 HashLen0to16(const char* s, size_t len) {
79
7.13k
    DCHECK_GE(len, 0);
80
7.13k
    DCHECK_LE(len, 16);
81
7.13k
    if (len > 8) {
82
1.84k
        uint64 a = LittleEndian::Load64(s);
83
1.84k
        uint64 b = LittleEndian::Load64(s + len - 8);
84
1.84k
        return HashLen16(a, RotateByAtLeast1(b + len, len)) ^ b;
85
1.84k
    }
86
5.29k
    if (len >= 4) {
87
2.75k
        uint64 a = LittleEndian::Load32(s);
88
2.75k
        return HashLen16(len + (a << 3), LittleEndian::Load32(s + len - 4));
89
2.75k
    }
90
2.54k
    if (len > 0) {
91
2.54k
        uint8 a = s[0];
92
2.54k
        uint8 b = s[len >> 1];
93
2.54k
        uint8 c = s[len - 1];
94
2.54k
        uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
95
2.54k
        uint32 z = len + (static_cast<uint32>(c) << 2);
96
2.54k
        return ShiftMix(y * k2 ^ z * k3) * k2;
97
2.54k
    }
98
0
    return k2;
99
2.54k
}
100
101
// This probably works well for 16-byte strings as well, but it may be overkill
102
// in that case.
103
4.85k
static uint64 HashLen17to32(const char* s, size_t len) {
104
4.85k
    DCHECK_GE(len, 17);
105
4.85k
    DCHECK_LE(len, 32);
106
4.85k
    uint64 a = LittleEndian::Load64(s) * k1;
107
4.85k
    uint64 b = LittleEndian::Load64(s + 8);
108
4.85k
    uint64 c = LittleEndian::Load64(s + len - 8) * k2;
109
4.85k
    uint64 d = LittleEndian::Load64(s + len - 16) * k0;
110
4.85k
    return HashLen16(Rotate(a - b, 43) + Rotate(c, 30) + d, a + Rotate(b ^ k3, 20) - c + len);
111
4.85k
}
112
113
// Return a 16-byte hash for 48 bytes.  Quick and dirty.
114
// Callers do best to use "random-looking" values for a and b.
115
// (For more, see the code review discussion of CL 18799087.)
116
static pair<uint64, uint64> WeakHashLen32WithSeeds(uint64 w, uint64 x, uint64 y, uint64 z, uint64 a,
117
0
                                                   uint64 b) {
118
0
    a += w;
119
0
    b = Rotate(b + a + z, 51);
120
0
    uint64 c = a;
121
0
    a += x;
122
0
    a += y;
123
0
    b += Rotate(a, 23);
124
0
    return make_pair(a + z, b + c);
125
0
}
126
127
// Return a 16-byte hash for s[0] ... s[31], a, and b.  Quick and dirty.
128
0
static pair<uint64, uint64> WeakHashLen32WithSeeds(const char* s, uint64 a, uint64 b) {
129
0
    return WeakHashLen32WithSeeds(LittleEndian::Load64(s), LittleEndian::Load64(s + 8),
130
0
                                  LittleEndian::Load64(s + 16), LittleEndian::Load64(s + 24), a, b);
131
0
}
132
133
// Return an 8-byte hash for 33 to 64 bytes.
134
0
static uint64 HashLen33to64(const char* s, size_t len) {
135
0
    uint64 z = LittleEndian::Load64(s + 24);
136
0
    uint64 a = LittleEndian::Load64(s) + (len + LittleEndian::Load64(s + len - 16)) * k0;
137
0
    uint64 b = Rotate(a + z, 52);
138
0
    uint64 c = Rotate(a, 37);
139
0
    a += LittleEndian::Load64(s + 8);
140
0
    c += Rotate(a, 7);
141
0
    a += LittleEndian::Load64(s + 16);
142
0
    uint64 vf = a + z;
143
0
    uint64 vs = b + Rotate(a, 31) + c;
144
0
    a = LittleEndian::Load64(s + 16) + LittleEndian::Load64(s + len - 32);
145
0
    z += LittleEndian::Load64(s + len - 8);
146
0
    b = Rotate(a + z, 52);
147
0
    c = Rotate(a, 37);
148
0
    a += LittleEndian::Load64(s + len - 24);
149
0
    c += Rotate(a, 7);
150
0
    a += LittleEndian::Load64(s + len - 16);
151
0
    uint64 wf = a + z;
152
0
    uint64 ws = b + Rotate(a, 31) + c;
153
0
    uint64 r = ShiftMix((vf + ws) * k2 + (wf + vs) * k0);
154
0
    return ShiftMix(r * k0 + vs) * k2;
155
0
}
156
157
11.9k
uint64 CityHash64(const char* s, size_t len) {
158
11.9k
    if (len <= 32) {
159
11.9k
        if (len <= 16) {
160
7.13k
            return HashLen0to16(s, len);
161
7.13k
        } else {
162
4.85k
            return HashLen17to32(s, len);
163
4.85k
        }
164
11.9k
    } else if (len <= 64) {
165
0
        return HashLen33to64(s, len);
166
0
    }
167
168
    // For strings over 64 bytes we hash the end first, and then as we
169
    // loop we keep 56 bytes of state: v, w, x, y, and z.
170
0
    uint64 x = LittleEndian::Load64(s + len - 40);
171
0
    uint64 y = LittleEndian::Load64(s + len - 16) + LittleEndian::Load64(s + len - 56);
172
0
    uint64 z =
173
0
            HashLen16(LittleEndian::Load64(s + len - 48) + len, LittleEndian::Load64(s + len - 24));
174
0
    pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
175
0
    pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
176
0
    x = x * k1 + LittleEndian::Load64(s);
177
178
    // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
179
0
    len = (len - 1) & ~static_cast<size_t>(63);
180
0
    DCHECK_GT(len, 0);
181
0
    DCHECK_EQ(len, len / 64 * 64);
182
0
    do {
183
0
        x = Rotate(x + y + v.first + LittleEndian::Load64(s + 8), 37) * k1;
184
0
        y = Rotate(y + v.second + LittleEndian::Load64(s + 48), 42) * k1;
185
0
        x ^= w.second;
186
0
        y += v.first + LittleEndian::Load64(s + 40);
187
0
        z = Rotate(z + w.first, 33) * k1;
188
0
        v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
189
0
        w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + LittleEndian::Load64(s + 16));
190
0
        std::swap(z, x);
191
0
        s += 64;
192
0
        len -= 64;
193
0
    } while (len != 0);
194
0
    return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
195
0
                     HashLen16(v.second, w.second) + x);
196
11.9k
}
197
198
14
uint64 CityHash64WithSeed(const char* s, size_t len, uint64 seed) {
199
14
    return CityHash64WithSeeds(s, len, k2, seed);
200
14
}
201
202
14
uint64 CityHash64WithSeeds(const char* s, size_t len, uint64 seed0, uint64 seed1) {
203
14
    return HashLen16(CityHash64(s, len) - seed0, seed1);
204
14
}
205
206
// A subroutine for CityHash128().  Returns a decent 128-bit hash for strings
207
// of any length representable in ssize_t.  Based on City and Murmur128.
208
0
static uint128 CityMurmur(const char* s, size_t len, uint128 seed) {
209
0
    uint64 a = Uint128Low64(seed);
210
0
    uint64 b = Uint128High64(seed);
211
0
    uint64 c = 0;
212
0
    uint64 d = 0;
213
0
    ssize_t l = len - 16;
214
0
    if (l <= 0) { // len <= 16
215
0
        c = b * k1 + HashLen0to16(s, len);
216
0
        d = Rotate(a + (len >= 8 ? LittleEndian::Load64(s) : c), 32);
217
0
    } else { // len > 16
218
0
        c = HashLen16(LittleEndian::Load64(s + len - 8) + k1, a);
219
0
        d = HashLen16(b + len, c + LittleEndian::Load64(s + len - 16));
220
0
        a += d;
221
0
        do {
222
0
            a ^= ShiftMix(LittleEndian::Load64(s) * k1) * k1;
223
0
            a *= k1;
224
0
            b ^= a;
225
0
            c ^= ShiftMix(LittleEndian::Load64(s + 8) * k1) * k1;
226
0
            c *= k1;
227
0
            d ^= c;
228
0
            s += 16;
229
0
            l -= 16;
230
0
        } while (l > 0);
231
0
    }
232
0
    a = HashLen16(a, c);
233
0
    b = HashLen16(d, b);
234
0
    return uint128(a ^ b, HashLen16(b, a));
235
0
}
236
237
0
uint128 CityHash128WithSeed(const char* s, size_t len, uint128 seed) {
238
    // TODO(user): As of February 2011, there's a beta of Murmur3 that would
239
    // most likely be useful here.  E.g., if (len < 900) return Murmur3(...)
240
0
    if (len < 128) {
241
0
        return CityMurmur(s, len, seed);
242
0
    }
243
244
    // We expect len >= 128 to be the common case.  Keep 56 bytes of state:
245
    // v, w, x, y, and z.
246
0
    pair<uint64, uint64> v, w;
247
0
    uint64 x = Uint128Low64(seed);
248
0
    uint64 y = Uint128High64(seed);
249
0
    uint64 z = len * k1;
250
0
    v.first = Rotate(y ^ k1, 49) * k1 + LittleEndian::Load64(s);
251
0
    v.second = Rotate(v.first, 42) * k1 + LittleEndian::Load64(s + 8);
252
0
    w.first = Rotate(y + z, 35) * k1 + x;
253
0
    w.second = Rotate(x + LittleEndian::Load64(s + 88), 53) * k1;
254
255
    // This is similar to the inner loop of CityHash64(), manually unrolled.
256
0
    do {
257
0
        x = Rotate(x + y + v.first + LittleEndian::Load64(s + 16), 37) * k1;
258
0
        y = Rotate(y + v.second + LittleEndian::Load64(s + 48), 42) * k1;
259
0
        x ^= w.second;
260
0
        y ^= v.first;
261
0
        z = Rotate(z ^ w.first, 33);
262
0
        v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
263
0
        w = WeakHashLen32WithSeeds(s + 32, z + w.second, y);
264
0
        std::swap(z, x);
265
0
        s += 64;
266
0
        x = Rotate(x + y + v.first + LittleEndian::Load64(s + 16), 37) * k1;
267
0
        y = Rotate(y + v.second + LittleEndian::Load64(s + 48), 42) * k1;
268
0
        x ^= w.second;
269
0
        y ^= v.first;
270
0
        z = Rotate(z ^ w.first, 33);
271
0
        v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
272
0
        w = WeakHashLen32WithSeeds(s + 32, z + w.second, y);
273
0
        std::swap(z, x);
274
0
        s += 64;
275
0
        len -= 128;
276
0
    } while (PREDICT_TRUE(len >= 128));
277
0
    y += Rotate(w.first, 37) * k0 + z;
278
0
    x += Rotate(v.first + z, 49) * k0;
279
    // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
280
0
    for (size_t tail_done = 0; tail_done < len;) {
281
0
        tail_done += 32;
282
0
        y = Rotate(y - x, 42) * k0 + v.second;
283
0
        w.first += LittleEndian::Load64(s + len - tail_done + 16);
284
0
        x = Rotate(x, 49) * k0 + w.first;
285
0
        w.first += v.first;
286
0
        v = WeakHashLen32WithSeeds(s + len - tail_done, v.first, v.second);
287
0
    }
288
    // At this point our 48 bytes of state should contain more than
289
    // enough information for a strong 128-bit hash.  We use two
290
    // different 48-byte-to-8-byte hashes to get a 16-byte final result.
291
0
    x = HashLen16(x, v.first);
292
0
    y = HashLen16(y, w.first);
293
0
    return uint128(HashLen16(x + v.second, w.second) + y, HashLen16(x + w.second, y + v.second));
294
0
}
295
296
0
uint128 CityHash128(const char* s, size_t len) {
297
0
    if (len >= 16) {
298
0
        return CityHash128WithSeed(
299
0
                s + 16, len - 16,
300
0
                uint128(LittleEndian::Load64(s) ^ k3, LittleEndian::Load64(s + 8)));
301
0
    } else if (len >= 8) {
302
0
        return CityHash128WithSeed(nullptr, 0,
303
0
                                   uint128(LittleEndian::Load64(s) ^ (len * k0),
304
0
                                           LittleEndian::Load64(s + len - 8) ^ k1));
305
0
    } else {
306
0
        return CityHash128WithSeed(s, len, uint128(k0, k1));
307
0
    }
308
0
}
309
310
} // namespace util_hash