be/src/exec/common/hash_table/hash.h
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | // This file is copied from |
18 | | // https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/HashTable/Hash.h |
19 | | // and modified by Doris |
20 | | |
21 | | #pragma once |
22 | | |
23 | | #include <type_traits> |
24 | | |
25 | | #include "core/extended_types.h" |
26 | | #include "core/string_ref.h" |
27 | | #include "core/types.h" |
28 | | #include "core/uint128.h" |
29 | | #include "core/value/timestamp_ns_value.h" |
30 | | #include "parallel_hashmap/phmap_utils.h" |
31 | | |
32 | | // Here is an empirical value. |
33 | | static constexpr size_t HASH_MAP_PREFETCH_DIST = 16; |
34 | | |
35 | | /** Hash functions that are better than the trivial function std::hash. |
36 | | * |
37 | | * Example: when we do aggregation by the visitor ID, the performance increase is more than 5 times. |
38 | | * This is because of following reasons: |
39 | | * - in Yandex, visitor identifier is an integer that has timestamp with seconds resolution in lower bits; |
40 | | * - in typical implementation of standard library, hash function for integers is trivial and just use lower bits; |
41 | | * - traffic is non-uniformly distributed across a day; |
42 | | * - we are using open-addressing linear probing hash tables that are most critical to hash function quality, |
43 | | * and trivial hash function gives disastrous results. |
44 | | */ |
45 | | |
46 | | /** Taken from MurmurHash. This is Murmur finalizer. |
47 | | * Faster than int_hash32 when inserting into the hash table UInt64 -> UInt64, where the key is the visitor ID. |
48 | | */ |
49 | 60 | inline doris::UInt64 int_hash64(doris::UInt64 x) { |
50 | 60 | x ^= x >> 33; |
51 | 60 | x *= 0xff51afd7ed558ccdULL; |
52 | 60 | x ^= x >> 33; |
53 | 60 | x *= 0xc4ceb9fe1a85ec53ULL; |
54 | 60 | x ^= x >> 33; |
55 | | |
56 | 60 | return x; |
57 | 60 | } |
58 | | |
59 | | /** CRC32C is not very high-quality as a hash function, |
60 | | * according to avalanche and bit independence tests (see SMHasher software), as well as a small number of bits, |
61 | | * but can behave well when used in hash tables, |
62 | | * due to high speed (latency 3 + 1 clock cycle, throughput 1 clock cycle). |
63 | | * Works only with SSE 4.2 support. |
64 | | */ |
65 | | #include "util/sse_util.hpp" |
66 | | |
67 | 4.15M | inline doris::UInt64 int_hash_crc32(doris::UInt64 x) { |
68 | 4.15M | #if defined(__SSE4_2__) || (defined(__aarch64__) && defined(__ARM_FEATURE_CRC32)) |
69 | 4.15M | return _mm_crc32_u64(-1ULL, x); |
70 | | #else |
71 | | /// On other platforms we do not have CRC32. NOTE This can be confusing. |
72 | | return int_hash64(x); |
73 | | #endif |
74 | 4.15M | } |
75 | | |
76 | | template <typename T> |
77 | 60 | inline size_t default_hash64(T key) { |
78 | 60 | union { |
79 | 60 | T in; |
80 | 60 | doris::UInt64 out; |
81 | 60 | } u; |
82 | 60 | u.out = 0; |
83 | 60 | u.in = key; |
84 | 60 | return int_hash64(u.out); |
85 | 60 | } Unexecuted instantiation: _Z14default_hash64IhEmT_ Unexecuted instantiation: _Z14default_hash64IaEmT_ Unexecuted instantiation: _Z14default_hash64IsEmT_ Line | Count | Source | 77 | 16 | inline size_t default_hash64(T key) { | 78 | 16 | union { | 79 | 16 | T in; | 80 | 16 | doris::UInt64 out; | 81 | 16 | } u; | 82 | 16 | u.out = 0; | 83 | 16 | u.in = key; | 84 | 16 | return int_hash64(u.out); | 85 | 16 | } |
Unexecuted instantiation: _Z14default_hash64IlEmT_ Line | Count | Source | 77 | 41 | inline size_t default_hash64(T key) { | 78 | 41 | union { | 79 | 41 | T in; | 80 | 41 | doris::UInt64 out; | 81 | 41 | } u; | 82 | 41 | u.out = 0; | 83 | 41 | u.in = key; | 84 | 41 | return int_hash64(u.out); | 85 | 41 | } |
Unexecuted instantiation: _Z14default_hash64IfEmT_ Line | Count | Source | 77 | 3 | inline size_t default_hash64(T key) { | 78 | 3 | union { | 79 | 3 | T in; | 80 | 3 | doris::UInt64 out; | 81 | 3 | } u; | 82 | 3 | u.out = 0; | 83 | 3 | u.in = key; | 84 | 3 | return int_hash64(u.out); | 85 | 3 | } |
Unexecuted instantiation: _Z14default_hash64IjEmT_ Unexecuted instantiation: _Z14default_hash64IoEmT_ |
86 | | |
87 | | template <typename T, typename Enable = void> |
88 | | struct DefaultHash; |
89 | | |
90 | | template <typename T> |
91 | | requires std::is_arithmetic_v<T> |
92 | | struct DefaultHash<T> { |
93 | 60 | size_t operator()(T key) const { return default_hash64<T>(key); }Unexecuted instantiation: _ZNK11DefaultHashIhvEclEh Unexecuted instantiation: _ZNK11DefaultHashIavEclEa Unexecuted instantiation: _ZNK11DefaultHashIsvEclEs _ZNK11DefaultHashIivEclEi Line | Count | Source | 93 | 16 | size_t operator()(T key) const { return default_hash64<T>(key); } |
Unexecuted instantiation: _ZNK11DefaultHashIlvEclEl _ZNK11DefaultHashInvEclEn Line | Count | Source | 93 | 41 | size_t operator()(T key) const { return default_hash64<T>(key); } |
Unexecuted instantiation: _ZNK11DefaultHashIfvEclEf _ZNK11DefaultHashIdvEclEd Line | Count | Source | 93 | 3 | size_t operator()(T key) const { return default_hash64<T>(key); } |
Unexecuted instantiation: _ZNK11DefaultHashIjvEclEj Unexecuted instantiation: _ZNK11DefaultHashIovEclEo |
94 | | }; |
95 | | |
96 | | template <> |
97 | | struct DefaultHash<doris::VecDateTimeValue> { |
98 | 0 | size_t operator()(doris::VecDateTimeValue key) const { return int_hash64(*(int64_t*)&key); } |
99 | | }; |
100 | | |
101 | | template <> |
102 | | struct DefaultHash<doris::DateV2Value<doris::DateTimeV2ValueType>> { |
103 | 0 | size_t operator()(doris::DateV2Value<doris::DateTimeV2ValueType> key) const { |
104 | 0 | return int_hash64(key.to_date_int_val()); |
105 | 0 | } |
106 | | }; |
107 | | |
108 | | template <> |
109 | | struct DefaultHash<doris::DateV2Value<doris::DateV2ValueType>> { |
110 | 0 | size_t operator()(doris::DateV2Value<doris::DateV2ValueType> key) const { |
111 | 0 | return int_hash64(key.to_date_int_val()); |
112 | 0 | } |
113 | | }; |
114 | | |
115 | | template <> |
116 | | struct DefaultHash<doris::TimeStampNsValue> { |
117 | 0 | size_t operator()(doris::TimeStampNsValue key) const { return int_hash64(key.epoch_nanos()); } |
118 | | }; |
119 | | |
120 | | template <> |
121 | | struct DefaultHash<doris::TimestampTzValue> { |
122 | 0 | size_t operator()(doris::TimestampTzValue key) const { |
123 | 0 | return int_hash64(key.to_date_int_val()); |
124 | 0 | } |
125 | | }; |
126 | | |
127 | | template <> |
128 | | struct DefaultHash<doris::StringRef> : public doris::StringRefHash {}; |
129 | | |
130 | | template <> |
131 | | struct DefaultHash<wide::Int256> : public std::hash<wide::Int256> {}; |
132 | | |
133 | | template <typename T> |
134 | | struct HashCRC32; |
135 | | |
136 | | template <typename T> |
137 | 4.15M | inline size_t hash_crc32(T key) { |
138 | 4.15M | union { |
139 | 4.15M | T in; |
140 | 4.15M | doris::UInt64 out; |
141 | 4.15M | } u; |
142 | 4.15M | u.out = 0; |
143 | 4.15M | u.in = key; |
144 | 4.15M | return int_hash_crc32(u.out); |
145 | 4.15M | } Line | Count | Source | 137 | 12 | inline size_t hash_crc32(T key) { | 138 | 12 | union { | 139 | 12 | T in; | 140 | 12 | doris::UInt64 out; | 141 | 12 | } u; | 142 | 12 | u.out = 0; | 143 | 12 | u.in = key; | 144 | 12 | return int_hash_crc32(u.out); | 145 | 12 | } |
Line | Count | Source | 137 | 33.9k | inline size_t hash_crc32(T key) { | 138 | 33.9k | union { | 139 | 33.9k | T in; | 140 | 33.9k | doris::UInt64 out; | 141 | 33.9k | } u; | 142 | 33.9k | u.out = 0; | 143 | 33.9k | u.in = key; | 144 | 33.9k | return int_hash_crc32(u.out); | 145 | 33.9k | } |
Line | Count | Source | 137 | 4.03M | inline size_t hash_crc32(T key) { | 138 | 4.03M | union { | 139 | 4.03M | T in; | 140 | 4.03M | doris::UInt64 out; | 141 | 4.03M | } u; | 142 | 4.03M | u.out = 0; | 143 | 4.03M | u.in = key; | 144 | 4.03M | return int_hash_crc32(u.out); | 145 | 4.03M | } |
Line | Count | Source | 137 | 29.2k | inline size_t hash_crc32(T key) { | 138 | 29.2k | union { | 139 | 29.2k | T in; | 140 | 29.2k | doris::UInt64 out; | 141 | 29.2k | } u; | 142 | 29.2k | u.out = 0; | 143 | 29.2k | u.in = key; | 144 | 29.2k | return int_hash_crc32(u.out); | 145 | 29.2k | } |
Line | Count | Source | 137 | 18.9k | inline size_t hash_crc32(T key) { | 138 | 18.9k | union { | 139 | 18.9k | T in; | 140 | 18.9k | doris::UInt64 out; | 141 | 18.9k | } u; | 142 | 18.9k | u.out = 0; | 143 | 18.9k | u.in = key; | 144 | 18.9k | return int_hash_crc32(u.out); | 145 | 18.9k | } |
Line | Count | Source | 137 | 8.50k | inline size_t hash_crc32(T key) { | 138 | 8.50k | union { | 139 | 8.50k | T in; | 140 | 8.50k | doris::UInt64 out; | 141 | 8.50k | } u; | 142 | 8.50k | u.out = 0; | 143 | 8.50k | u.in = key; | 144 | 8.50k | return int_hash_crc32(u.out); | 145 | 8.50k | } |
Line | Count | Source | 137 | 8.50k | inline size_t hash_crc32(T key) { | 138 | 8.50k | union { | 139 | 8.50k | T in; | 140 | 8.50k | doris::UInt64 out; | 141 | 8.50k | } u; | 142 | 8.50k | u.out = 0; | 143 | 8.50k | u.in = key; | 144 | 8.50k | return int_hash_crc32(u.out); | 145 | 8.50k | } |
Line | Count | Source | 137 | 20.5k | inline size_t hash_crc32(T key) { | 138 | 20.5k | union { | 139 | 20.5k | T in; | 140 | 20.5k | doris::UInt64 out; | 141 | 20.5k | } u; | 142 | 20.5k | u.out = 0; | 143 | 20.5k | u.in = key; | 144 | 20.5k | return int_hash_crc32(u.out); | 145 | 20.5k | } |
Unexecuted instantiation: _Z10hash_crc32IfEmT_ Line | Count | Source | 137 | 3 | inline size_t hash_crc32(T key) { | 138 | 3 | union { | 139 | 3 | T in; | 140 | 3 | doris::UInt64 out; | 141 | 3 | } u; | 142 | 3 | u.out = 0; | 143 | 3 | u.in = key; | 144 | 3 | return int_hash_crc32(u.out); | 145 | 3 | } |
|
146 | | |
147 | | template <> |
148 | 20.7k | inline size_t hash_crc32(doris::UInt128 u) { |
149 | 20.7k | return doris::UInt128HashCRC32()(u); |
150 | 20.7k | } |
151 | | |
152 | | template <> |
153 | 3 | inline size_t hash_crc32(unsigned __int128 u) { |
154 | 3 | return doris::UInt128HashCRC32()(u); |
155 | 3 | } |
156 | | |
157 | | template <> |
158 | 12 | inline size_t hash_crc32(doris::Int128 u) { |
159 | 12 | return doris::UInt128HashCRC32()({(u >> 64) & int64_t(-1), u & int64_t(-1)}); |
160 | 12 | } |
161 | | |
162 | | template <> |
163 | 0 | inline size_t hash_crc32(doris::VecDateTimeValue u) { |
164 | 0 | return hash_crc32(*(int64_t*)&u); |
165 | 0 | } |
166 | | |
167 | | template <> |
168 | 0 | inline size_t hash_crc32(doris::DateV2Value<doris::DateTimeV2ValueType> u) { |
169 | 0 | return hash_crc32(u.to_date_int_val()); |
170 | 0 | } |
171 | | |
172 | | template <> |
173 | 0 | inline size_t hash_crc32(doris::DateV2Value<doris::DateV2ValueType> u) { |
174 | 0 | return hash_crc32(u.to_date_int_val()); |
175 | 0 | } |
176 | | |
177 | | template <> |
178 | 6 | inline size_t hash_crc32(doris::TimeStampNsValue u) { |
179 | 6 | return hash_crc32(u.epoch_nanos()); |
180 | 6 | } |
181 | | |
182 | | template <> |
183 | 0 | inline size_t hash_crc32(doris::TimestampTzValue u) { |
184 | 0 | return hash_crc32(u.to_date_int_val()); |
185 | 0 | } |
186 | | |
187 | | #define DEFINE_HASH(T) \ |
188 | | template <> \ |
189 | | struct HashCRC32<T> { \ |
190 | 4.17M | size_t operator()(T key) const { \ |
191 | 4.17M | return hash_crc32<T>(key); \ |
192 | 4.17M | } \ Line | Count | Source | 190 | 29.2k | size_t operator()(T key) const { \ | 191 | 29.2k | return hash_crc32<T>(key); \ | 192 | 29.2k | } \ |
Line | Count | Source | 190 | 18.9k | size_t operator()(T key) const { \ | 191 | 18.9k | return hash_crc32<T>(key); \ | 192 | 18.9k | } \ |
Line | Count | Source | 190 | 4.03M | size_t operator()(T key) const { \ | 191 | 4.03M | return hash_crc32<T>(key); \ | 192 | 4.03M | } \ |
Line | Count | Source | 190 | 33.9k | size_t operator()(T key) const { \ | 191 | 33.9k | return hash_crc32<T>(key); \ | 192 | 33.9k | } \ |
_ZNK9HashCRC32IN4wide7integerILm128EjEEEclES2_ Line | Count | Source | 190 | 20.7k | size_t operator()(T key) const { \ | 191 | 20.7k | return hash_crc32<T>(key); \ | 192 | 20.7k | } \ |
Line | Count | Source | 190 | 8.50k | size_t operator()(T key) const { \ | 191 | 8.50k | return hash_crc32<T>(key); \ | 192 | 8.50k | } \ |
Line | Count | Source | 190 | 8.50k | size_t operator()(T key) const { \ | 191 | 8.50k | return hash_crc32<T>(key); \ | 192 | 8.50k | } \ |
Line | Count | Source | 190 | 20.5k | size_t operator()(T key) const { \ | 191 | 20.5k | return hash_crc32<T>(key); \ | 192 | 20.5k | } \ |
Line | Count | Source | 190 | 6 | size_t operator()(T key) const { \ | 191 | 6 | return hash_crc32<T>(key); \ | 192 | 6 | } \ |
Line | Count | Source | 190 | 12 | size_t operator()(T key) const { \ | 191 | 12 | return hash_crc32<T>(key); \ | 192 | 12 | } \ |
Unexecuted instantiation: _ZNK9HashCRC32IfEclEf Line | Count | Source | 190 | 3 | size_t operator()(T key) const { \ | 191 | 3 | return hash_crc32<T>(key); \ | 192 | 3 | } \ |
Unexecuted instantiation: _ZNK9HashCRC32IN5doris16VecDateTimeValueEEclES1_ Unexecuted instantiation: _ZNK9HashCRC32IN5doris11DateV2ValueINS0_19DateTimeV2ValueTypeEEEEclES3_ Unexecuted instantiation: _ZNK9HashCRC32IN5doris11DateV2ValueINS0_15DateV2ValueTypeEEEEclES3_ _ZNK9HashCRC32IN5doris16TimeStampNsValueEEclES1_ Line | Count | Source | 190 | 6 | size_t operator()(T key) const { \ | 191 | 6 | return hash_crc32<T>(key); \ | 192 | 6 | } \ |
Unexecuted instantiation: _ZNK9HashCRC32IN5doris16TimestampTzValueEEclES1_ Line | Count | Source | 190 | 3 | size_t operator()(T key) const { \ | 191 | 3 | return hash_crc32<T>(key); \ | 192 | 3 | } \ |
|
193 | | }; |
194 | | |
195 | | DEFINE_HASH(doris::UInt8) |
196 | | DEFINE_HASH(doris::UInt16) |
197 | | DEFINE_HASH(doris::UInt32) |
198 | | DEFINE_HASH(doris::UInt64) |
199 | | DEFINE_HASH(doris::UInt128) |
200 | | DEFINE_HASH(doris::Int8) |
201 | | DEFINE_HASH(doris::Int16) |
202 | | DEFINE_HASH(doris::Int32) |
203 | | DEFINE_HASH(doris::Int64) |
204 | | DEFINE_HASH(doris::Int128) |
205 | | DEFINE_HASH(doris::Float32) |
206 | | DEFINE_HASH(doris::Float64) |
207 | | DEFINE_HASH(doris::VecDateTimeValue) |
208 | | DEFINE_HASH(doris::DateV2Value<doris::DateTimeV2ValueType>) |
209 | | DEFINE_HASH(doris::DateV2Value<doris::DateV2ValueType>) |
210 | | DEFINE_HASH(doris::TimeStampNsValue) |
211 | | DEFINE_HASH(doris::TimestampTzValue) |
212 | | DEFINE_HASH(unsigned __int128) |
213 | | |
214 | | #undef DEFINE_HASH |
215 | | |
216 | | template <typename Key, typename Hash = HashCRC32<Key>> |
217 | | struct HashMixWrapper { |
218 | 3.99M | size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); }_ZNK14HashMixWrapperIj9HashCRC32IjEEclEj Line | Count | Source | 218 | 3.99M | size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); } |
_ZNK14HashMixWrapperIm9HashCRC32ImEEclEm Line | Count | Source | 218 | 1.96k | size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); } |
|
219 | | }; |
220 | | |
221 | | template <> |
222 | | struct HashCRC32<doris::UInt256> { |
223 | 8 | size_t operator()(const doris::UInt256& x) const { |
224 | 8 | #if defined(__SSE4_2__) || defined(__aarch64__) |
225 | 8 | doris::UInt64 crc = -1ULL; |
226 | 8 | crc = _mm_crc32_u64(crc, x.items[0]); |
227 | 8 | crc = _mm_crc32_u64(crc, x.items[1]); |
228 | 8 | crc = _mm_crc32_u64(crc, x.items[2]); |
229 | 8 | crc = _mm_crc32_u64(crc, x.items[3]); |
230 | 8 | return crc; |
231 | | #else |
232 | | return Hash128to64({Hash128to64({x.a, x.b}), Hash128to64({x.c, x.d})}); |
233 | | #endif |
234 | 8 | } |
235 | | }; |
236 | | |
237 | | template <> |
238 | | struct HashCRC32<wide::Int256> { |
239 | 8.19k | size_t operator()(const wide::Int256& x) const { |
240 | 8.19k | #if defined(__SSE4_2__) || defined(__aarch64__) |
241 | 8.19k | doris::UInt64 crc = -1ULL; |
242 | 8.19k | crc = _mm_crc32_u64(crc, x.items[0]); |
243 | 8.19k | crc = _mm_crc32_u64(crc, x.items[1]); |
244 | 8.19k | crc = _mm_crc32_u64(crc, x.items[2]); |
245 | 8.19k | crc = _mm_crc32_u64(crc, x.items[3]); |
246 | 8.19k | return crc; |
247 | | #else |
248 | | return Hash128to64( |
249 | | {Hash128to64({x.items[0], x.items[1]}), Hash128to64({x.items[2], x.items[3]})}); |
250 | | #endif |
251 | 8.19k | } |
252 | | }; |
253 | | |
254 | | template <> |
255 | | struct HashCRC32<doris::Decimal256> { |
256 | 0 | size_t operator()(const doris::Decimal256& value) const { |
257 | 0 | return HashCRC32<wide::Int256>()(value.value); |
258 | 0 | } |
259 | | }; |
260 | | |
261 | | template <> |
262 | | struct HashCRC32<doris::Decimal32> { |
263 | 0 | size_t operator()(const doris::Decimal32& value) const { |
264 | 0 | return HashCRC32<int32_t>()(value.value); |
265 | 0 | } |
266 | | }; |
267 | | |
268 | | template <> |
269 | | struct HashCRC32<doris::Decimal64> { |
270 | 0 | size_t operator()(const doris::Decimal64& value) const { |
271 | 0 | return HashCRC32<int64_t>()(value.value); |
272 | 0 | } |
273 | | }; |
274 | | |
275 | | template <> |
276 | | struct HashCRC32<doris::Decimal128V3> { |
277 | 0 | size_t operator()(const doris::Decimal128V3& value) const { |
278 | 0 | return HashCRC32<__int128>()(value.value); |
279 | 0 | } |
280 | | }; |
281 | | |
282 | | template <> |
283 | | struct HashCRC32<doris::Decimal128V2> { |
284 | 0 | size_t operator()(const doris::Decimal128V2& value) const { |
285 | 0 | return HashCRC32<__int128>()(value.value); |
286 | 0 | } |
287 | | }; |
288 | | |
289 | | template <> |
290 | | struct HashCRC32<doris::DecimalV2Value> { |
291 | 0 | size_t operator()(const doris::DecimalV2Value& value) const { |
292 | 0 | return HashCRC32<__int128>()(value.value()); |
293 | 0 | } |
294 | | }; |
295 | | |
296 | | #include "common/compile_check_avoid_begin.h" |
297 | | |
298 | | template <> |
299 | | struct HashCRC32<doris::UInt72> { |
300 | 0 | size_t operator()(const doris::UInt72& x) const { |
301 | 0 | doris::UInt64 crc = -1ULL; |
302 | 0 | crc = _mm_crc32_u8(crc, x.a); |
303 | 0 | crc = _mm_crc32_u64(crc, x.b); |
304 | 0 | return crc; |
305 | 0 | } |
306 | | }; |
307 | | |
308 | | template <> |
309 | | struct HashCRC32<doris::UInt96> { |
310 | 21 | size_t operator()(const doris::UInt96& x) const { |
311 | 21 | doris::UInt64 crc = -1ULL; |
312 | 21 | crc = _mm_crc32_u32(crc, x.a); |
313 | 21 | crc = _mm_crc32_u64(crc, x.b); |
314 | 21 | return crc; |
315 | 21 | } |
316 | | }; |
317 | | |
318 | | template <> |
319 | | struct HashCRC32<doris::UInt104> { |
320 | 0 | size_t operator()(const doris::UInt104& x) const { |
321 | 0 | doris::UInt64 crc = -1ULL; |
322 | 0 | crc = _mm_crc32_u8(crc, x.a); |
323 | 0 | crc = _mm_crc32_u32(crc, x.b); |
324 | 0 | crc = _mm_crc32_u64(crc, x.c); |
325 | 0 | return crc; |
326 | 0 | } |
327 | | }; |
328 | | |
329 | | template <> |
330 | | struct HashCRC32<doris::UInt136> { |
331 | 2 | size_t operator()(const doris::UInt136& x) const { |
332 | 2 | doris::UInt64 crc = -1ULL; |
333 | 2 | crc = _mm_crc32_u8(crc, x.a); |
334 | 2 | crc = _mm_crc32_u64(crc, x.b); |
335 | 2 | crc = _mm_crc32_u64(crc, x.c); |
336 | 2 | return crc; |
337 | 2 | } |
338 | | }; |
339 | | |
340 | | #include "common/compile_check_avoid_end.h" |