QtBase  v6.3.1
qhash.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2020 The Qt Company Ltd.
4 ** Copyright (C) 2021 Intel Corporation.
5 ** Copyright (C) 2012 Giuseppe D'Angelo <dangelog@gmail.com>.
6 ** Contact: https://www.qt.io/licensing/
7 **
8 ** This file is part of the QtCore module of the Qt Toolkit.
9 **
10 ** $QT_BEGIN_LICENSE:LGPL$
11 ** Commercial License Usage
12 ** Licensees holding valid commercial Qt licenses may use this file in
13 ** accordance with the commercial license agreement provided with the
14 ** Software or, alternatively, in accordance with the terms contained in
15 ** a written agreement between you and The Qt Company. For licensing terms
16 ** and conditions see https://www.qt.io/terms-conditions. For further
17 ** information use the contact form at https://www.qt.io/contact-us.
18 **
19 ** GNU Lesser General Public License Usage
20 ** Alternatively, this file may be used under the terms of the GNU Lesser
21 ** General Public License version 3 as published by the Free Software
22 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
23 ** packaging of this file. Please review the following information to
24 ** ensure the GNU Lesser General Public License version 3 requirements
25 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
26 **
27 ** GNU General Public License Usage
28 ** Alternatively, this file may be used under the terms of the GNU
29 ** General Public License version 2.0 or (at your option) the GNU General
30 ** Public license version 3 or any later version approved by the KDE Free
31 ** Qt Foundation. The licenses are as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
33 ** included in the packaging of this file. Please review the following
34 ** information to ensure the GNU General Public License requirements will
35 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
36 ** https://www.gnu.org/licenses/gpl-3.0.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 // for rand_s, _CRT_RAND_S must be #defined before #including stdlib.h.
43 // put it at the beginning so some indirect inclusion doesn't break it
44 #ifndef _CRT_RAND_S
45 #define _CRT_RAND_S
46 #endif
47 #include <stdlib.h>
48 #include <stdint.h>
49 
50 #include "qhash.h"
51 
52 #ifdef truncate
53 #undef truncate
54 #endif
55 
56 #include <qbitarray.h>
57 #include <qstring.h>
58 #include <qglobal.h>
59 #include <qbytearray.h>
60 #include <qdatetime.h>
61 #include <qbasicatomic.h>
62 #include <qendian.h>
63 #include <private/qrandom_p.h>
64 #include <private/qsimd_p.h>
65 
66 #ifndef QT_BOOTSTRAPPED
67 #include <qcoreapplication.h>
68 #include <qrandom.h>
69 #endif // QT_BOOTSTRAPPED
70 
71 #include <array>
72 #include <limits.h>
73 
74 #ifdef Q_CC_GNU
75 # define Q_DECL_HOT_FUNCTION __attribute__((hot))
76 #else
77 # define Q_DECL_HOT_FUNCTION
78 #endif
79 
81 
82 // We assume that pointers and size_t have the same size. If that assumption should fail
83 // on a platform the code selecting the different methods below needs to be fixed.
84 static_assert(sizeof(size_t) == QT_POINTER_SIZE, "size_t and pointers have different size.");
85 
86 namespace {
87 struct HashSeedStorage
88 {
89  static constexpr int SeedCount = 2;
91 
92  constexpr HashSeedStorage() = default;
93 
94  enum State {
95  OverriddenByEnvironment = -1,
96  JustInitialized,
97  AlreadyInitialized
98  };
99  struct StateResult {
100  quintptr requestedSeed;
101  State state;
102  };
103 
104  StateResult state(int which = -1);
105  Q_DECL_HOT_FUNCTION QHashSeed currentSeed(int which)
106  {
107  return { state(which).requestedSeed };
108  }
109 
110  void resetSeed()
111  {
112  if (state().state < AlreadyInitialized)
113  return;
114 
115  // update the public seed
117  seeds[0].storeRelaxed(sizeof(size_t) > sizeof(quint32)
119  }
120 
121  void clearSeed()
122  {
123  state();
124  seeds[0].storeRelaxed(0); // always write (smaller code)
125  }
126 
127 private:
128  Q_DECL_COLD_FUNCTION Q_NEVER_INLINE StateResult initialize(int which) noexcept;
129  [[maybe_unused]] static void ensureConstexprConstructibility()
130  {
131  static_assert(std::is_trivially_destructible_v<HashSeedStorage>);
132  static constexpr HashSeedStorage dummy {};
133  Q_UNUSED(dummy);
134  }
135 };
136 
137 [[maybe_unused]] HashSeedStorage::StateResult HashSeedStorage::initialize(int which) noexcept
138 {
139  StateResult result = { 0, OverriddenByEnvironment };
140  bool ok;
141  int seed = qEnvironmentVariableIntValue("QT_HASH_SEED", &ok);
142  if (ok) {
143  if (seed) {
144  // can't use qWarning here (reentrancy)
145  fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
146  }
147 
148  // we don't have to store to the seed, since it's pre-initialized by
149  // the compiler to zero
150  return result;
151  }
152 
153  // update the full seed
154  auto x = qt_initial_random_value();
155  for (int i = 0; i < SeedCount; ++i) {
156  seeds[i].storeRelaxed(x.data[i]);
157  if (which == i)
158  result.requestedSeed = x.data[i];
159  }
160  result.state = JustInitialized;
161  return result;
162 }
163 
164 inline HashSeedStorage::StateResult HashSeedStorage::state(int which)
165 {
166  constexpr quintptr BadSeed = quintptr(Q_UINT64_C(0x5555'5555'5555'5555));
167  StateResult result = { BadSeed, AlreadyInitialized };
168 
169 #ifndef QT_BOOTSTRAPPED
170  static auto once = [&]() {
171  result = initialize(which);
172  return true;
173  }();
174  Q_UNUSED(once);
175 #else
176  result = { 0, OverriddenByEnvironment };
177 #endif
178 
179  if (result.state == AlreadyInitialized && which >= 0)
180  return { seeds[which].loadRelaxed(), AlreadyInitialized };
181  return result;
182 }
183 } // unnamed namespace
184 
185 /*
186  The QHash seed itself.
187 */
188 static HashSeedStorage qt_qhash_seed;
189 
190 /*
191  * Hashing for memory segments is based on the public domain MurmurHash2 by
192  * Austin Appleby. See http://murmurhash.googlepages.com/
193  */
194 #if QT_POINTER_SIZE == 4
195 
196 static inline uint murmurhash(const void *key, uint len, uint seed) noexcept
197 {
198  // 'm' and 'r' are mixing constants generated offline.
199  // They're not really 'magic', they just happen to work well.
200 
201  const unsigned int m = 0x5bd1e995;
202  const int r = 24;
203 
204  // Initialize the hash to a 'random' value
205 
206  unsigned int h = seed ^ len;
207 
208  // Mix 4 bytes at a time into the hash
209 
210  const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
211  const unsigned char *end = data + (len & ~3);
212 
213  while (data != end) {
214  size_t k;
215  memcpy(&k, data, sizeof(uint));
216 
217  k *= m;
218  k ^= k >> r;
219  k *= m;
220 
221  h *= m;
222  h ^= k;
223 
224  data += 4;
225  }
226 
227  // Handle the last few bytes of the input array
228  len &= 3;
229  if (len) {
230  unsigned int k = 0;
231  end += len;
232 
233  while (data != end) {
234  k <<= 8;
235  k |= *data;
236  ++data;
237  }
238  h ^= k;
239  h *= m;
240  }
241 
242  // Do a few final mixes of the hash to ensure the last few
243  // bytes are well-incorporated.
244 
245  h ^= h >> 13;
246  h *= m;
247  h ^= h >> 15;
248 
249  return h;
250 }
251 
252 #else
253 
254 static inline uint64_t murmurhash(const void *key, uint64_t len, uint64_t seed) noexcept
255 {
256  const uint64_t m = 0xc6a4a7935bd1e995ULL;
257  const int r = 47;
258 
259  uint64_t h = seed ^ (len * m);
260 
261  const unsigned char *data = reinterpret_cast<const unsigned char *>(key);
262  const unsigned char *end = data + (len & ~7ul);
263 
264  while (data != end) {
265  uint64_t k;
266  memcpy(&k, data, sizeof(uint64_t));
267 
268  k *= m;
269  k ^= k >> r;
270  k *= m;
271 
272  h ^= k;
273  h *= m;
274 
275  data += 8;
276  }
277 
278  len &= 7;
279  if (len) {
280  // handle the last few bytes of input
281  size_t k = 0;
282  end += len;
283 
284  while (data != end) {
285  k <<= 8;
286  k |= *data;
287  ++data;
288  }
289  h ^= k;
290  h *= m;
291  }
292 
293  h ^= h >> r;
294  h *= m;
295  h ^= h >> r;
296 
297  return h;
298 }
299 
300 #endif
301 
302 #if QT_POINTER_SIZE == 8
303 // This is an inlined version of the SipHash implementation that is
304 // trying to avoid some memcpy's from uint64 to uint8[] and back.
305 //
306 
307 // Use SipHash-1-2, which has similar performance characteristics as
308 // stablehash() above, instead of the SipHash-2-4 default
309 #define cROUNDS 1
310 #define dROUNDS 2
311 
312 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
313 
314 #define SIPROUND \
315  do { \
316  v0 += v1; \
317  v1 = ROTL(v1, 13); \
318  v1 ^= v0; \
319  v0 = ROTL(v0, 32); \
320  v2 += v3; \
321  v3 = ROTL(v3, 16); \
322  v3 ^= v2; \
323  v0 += v3; \
324  v3 = ROTL(v3, 21); \
325  v3 ^= v0; \
326  v2 += v1; \
327  v1 = ROTL(v1, 17); \
328  v1 ^= v2; \
329  v2 = ROTL(v2, 32); \
330  } while (0)
331 
332 
333 static uint64_t siphash(const uint8_t *in, uint64_t inlen, uint64_t seed, uint64_t seed2)
334 {
335  /* "somepseudorandomlygeneratedbytes" */
336  uint64_t v0 = 0x736f6d6570736575ULL;
337  uint64_t v1 = 0x646f72616e646f6dULL;
338  uint64_t v2 = 0x6c7967656e657261ULL;
339  uint64_t v3 = 0x7465646279746573ULL;
340  uint64_t b;
341  uint64_t k0 = seed;
342  uint64_t k1 = seed2;
343  int i;
344  const uint8_t *end = in + (inlen & ~7ULL);
345  const int left = inlen & 7;
346  b = inlen << 56;
347  v3 ^= k1;
348  v2 ^= k0;
349  v1 ^= k1;
350  v0 ^= k0;
351 
352  for (; in != end; in += 8) {
353  uint64_t m = qFromUnaligned<uint64_t>(in);
354  v3 ^= m;
355 
356  for (i = 0; i < cROUNDS; ++i)
357  SIPROUND;
358 
359  v0 ^= m;
360  }
361 
362 
363 #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
364  QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
365 #endif
366  switch (left) {
367  case 7:
368  b |= ((uint64_t)in[6]) << 48;
369  case 6:
370  b |= ((uint64_t)in[5]) << 40;
371  case 5:
372  b |= ((uint64_t)in[4]) << 32;
373  case 4:
374  b |= ((uint64_t)in[3]) << 24;
375  case 3:
376  b |= ((uint64_t)in[2]) << 16;
377  case 2:
378  b |= ((uint64_t)in[1]) << 8;
379  case 1:
380  b |= ((uint64_t)in[0]);
381  break;
382  case 0:
383  break;
384  }
385 
386  v3 ^= b;
387 
388  for (i = 0; i < cROUNDS; ++i)
389  SIPROUND;
390 
391  v0 ^= b;
392 
393  v2 ^= 0xff;
394 
395  for (i = 0; i < dROUNDS; ++i)
396  SIPROUND;
397 
398  b = v0 ^ v1 ^ v2 ^ v3;
399  return b;
400 }
401 #else
402 // This is a "SipHash" implementation adopted for 32bit platforms. It performs
403 // basically the same operations as the 64bit version using 4 byte at a time
404 // instead of 8.
405 //
406 // To make this work, we also need to change the constants for the mixing
407 // rotations in ROTL. We're simply using half of the 64bit constants, rounded up
408 // for odd numbers.
409 //
410 // For the v0-v4 constants, simply use the first four bytes of the 64 bit versions.
411 //
412 // Use SipHash-1-2, which has similar performance characteristics as
413 // stablehash() above, instead of the SipHash-2-4 default
414 #define cROUNDS 1
415 #define dROUNDS 2
416 
417 #define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
418 
419 #define SIPROUND \
420  do { \
421  v0 += v1; \
422  v1 = ROTL(v1, 7); \
423  v1 ^= v0; \
424  v0 = ROTL(v0, 16); \
425  v2 += v3; \
426  v3 = ROTL(v3, 8); \
427  v3 ^= v2; \
428  v0 += v3; \
429  v3 = ROTL(v3, 11); \
430  v3 ^= v0; \
431  v2 += v1; \
432  v1 = ROTL(v1, 9); \
433  v1 ^= v2; \
434  v2 = ROTL(v2, 16); \
435  } while (0)
436 
437 
438 static uint siphash(const uint8_t *in, uint inlen, uint seed, uint seed2)
439 {
440  /* "somepseudorandomlygeneratedbytes" */
441  uint v0 = 0x736f6d65U;
442  uint v1 = 0x646f7261U;
443  uint v2 = 0x6c796765U;
444  uint v3 = 0x74656462U;
445  uint b;
446  uint k0 = seed;
447  uint k1 = seed2;
448  int i;
449  const uint8_t *end = in + (inlen & ~3ULL);
450  const int left = inlen & 3;
451  b = inlen << 24;
452  v3 ^= k1;
453  v2 ^= k0;
454  v1 ^= k1;
455  v0 ^= k0;
456 
457  for (; in != end; in += 4) {
458  uint m = qFromUnaligned<uint>(in);
459  v3 ^= m;
460 
461  for (i = 0; i < cROUNDS; ++i)
462  SIPROUND;
463 
464  v0 ^= m;
465  }
466 
467 #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
468  QT_WARNING_DISABLE_GCC("-Wimplicit-fallthrough")
469 #endif
470  switch (left) {
471  case 3:
472  b |= ((uint)in[2]) << 16;
473  case 2:
474  b |= ((uint)in[1]) << 8;
475  case 1:
476  b |= ((uint)in[0]);
477  break;
478  case 0:
479  break;
480  }
481 
482  v3 ^= b;
483 
484  for (i = 0; i < cROUNDS; ++i)
485  SIPROUND;
486 
487  v0 ^= b;
488 
489  v2 ^= 0xff;
490 
491  for (i = 0; i < dROUNDS; ++i)
492  SIPROUND;
493 
494  b = v0 ^ v1 ^ v2 ^ v3;
495  return b;
496 }
497 #endif
498 
499 #if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__) // GCC
500 # define QHASH_AES_SANITIZER_BUILD
501 #elif __has_feature(address_sanitizer) || __has_feature(thread_sanitizer) // Clang
502 # define QHASH_AES_SANITIZER_BUILD
503 #endif
504 
505 // When built with a sanitizer, aeshash() is rightfully reported to have a
506 // heap-buffer-overflow issue. However, we consider it to be safe in this
507 // specific case and overcome the problem by correctly discarding the
508 // out-of-range bits. To allow building the code with sanitizer,
509 // QHASH_AES_SANITIZER_BUILD is used to disable aeshash() usage.
510 #if QT_COMPILER_SUPPORTS_HERE(AES) && QT_COMPILER_SUPPORTS_HERE(SSE4_2) && \
511  !defined(QHASH_AES_SANITIZER_BUILD)
512 # define AESHASH
513 
514 #undef QHASH_AES_SANITIZER_BUILD
515 
517 static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
518 {
519  // This is inspired by the algorithm in the Go language. See:
520  // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_amd64.s#L1105
521  // https://github.com/golang/go/blob/01b6cf09fc9f272d9db3d30b4c93982f4911d120/src/runtime/asm_386.s#L908
522  //
523  // Even though we're using the AESENC instruction from the CPU, this code
524  // is not encryption and this routine makes no claim to be
525  // cryptographically secure. We're simply using the instruction that performs
526  // the scrambling round (step 3 in [1]) because it's just very good at
527  // spreading the bits around.
528  //
529  // [1] https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#High-level_description_of_the_algorithm
530 
531  // hash 16 bytes, running 3 scramble rounds of AES on itself (like label "final1")
532  const auto hash16bytes = [](__m128i &state0, __m128i data) QT_FUNCTION_TARGET(AES) {
533  state0 = _mm_xor_si128(state0, data);
534  state0 = _mm_aesenc_si128(state0, state0);
535  state0 = _mm_aesenc_si128(state0, state0);
536  state0 = _mm_aesenc_si128(state0, state0);
537  };
538 
539  // hash twice 16 bytes, running 2 scramble rounds of AES on itself
540  const auto hash2x16bytes = [](__m128i &state0, __m128i &state1, const __m128i *src0,
541  const __m128i *src1) QT_FUNCTION_TARGET(AES) {
542  __m128i data0 = _mm_loadu_si128(src0);
543  __m128i data1 = _mm_loadu_si128(src1);
544  state0 = _mm_xor_si128(data0, state0);
545  state1 = _mm_xor_si128(data1, state1);
546  state0 = _mm_aesenc_si128(state0, state0);
547  state1 = _mm_aesenc_si128(state1, state1);
548  state0 = _mm_aesenc_si128(state0, state0);
549  state1 = _mm_aesenc_si128(state1, state1);
550  };
551 
552  __m128i mseed, mseed2;
553  if (sizeof(size_t) == 8) {
554 #ifdef Q_PROCESSOR_X86_64
555  mseed = _mm_cvtsi64_si128(seed);
556  mseed2 = _mm_set1_epi64x(seed2);
557 #endif
558  } else {
559  mseed = _mm_cvtsi32_si128(int(seed));
560  mseed2 = _mm_set1_epi32(int(seed2));
561  }
562 
563  // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, 0, 0, 0 ]
564  mseed = _mm_insert_epi16(mseed, short(seed), 4);
565  // mseed (epi16) = [ seed, seed >> 16, seed >> 32, seed >> 48, len, len, len, len ]
566  mseed = _mm_shufflehi_epi16(mseed, 0);
567 
568  // merge with the process-global seed
569  __m128i key = _mm_xor_si128(mseed, mseed2);
570 
571  // scramble the key
572  __m128i state0 = _mm_aesenc_si128(key, key);
573 
574  auto src = reinterpret_cast<const __m128i *>(p);
575  if (len >= sizeof(__m128i)) {
576  // unlike the Go code, we don't have more per-process seed
577  __m128i state1 = _mm_aesenc_si128(state0, mseed2);
578 
579  const auto srcend = reinterpret_cast<const __m128i *>(p + len);
580 
581  // main loop: scramble two 16-byte blocks
582  for ( ; src + 2 < srcend; src += 2)
583  hash2x16bytes(state0, state1, src, src + 1);
584 
585  if (src + 1 < srcend) {
586  // epilogue: between 16 and 31 bytes
587  hash2x16bytes(state0, state1, src, srcend - 1);
588  } else if (src != srcend) {
589  // epilogue: between 1 and 16 bytes, overlap with the end
590  __m128i data = _mm_loadu_si128(srcend - 1);
591  hash16bytes(state0, data);
592  }
593 
594  // combine results:
595  state0 = _mm_xor_si128(state0, state1);
596  } else if (len) {
597  // We're going to load 16 bytes and mask zero the part we don't care
598  // (the hash of a short string is different from the hash of a longer
599  // including NULLs at the end because the length is in the key)
600  // WARNING: this may produce valgrind warnings, but it's safe
601 
602  constexpr quintptr PageSize = 4096;
603  __m128i data;
604 
605  if ((quintptr(src) & (PageSize / 2)) == 0) {
606  // lower half of the page:
607  // load all 16 bytes and mask off the bytes past the end of the source
608  static const qint8 maskarray[] = {
609  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
610  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
611  };
612  __m128i mask = _mm_loadu_si128(reinterpret_cast<const __m128i *>(maskarray + 15 - len));
613  data = _mm_loadu_si128(src);
614  data = _mm_and_si128(data, mask);
615  } else {
616  // upper half of the page:
617  // load 16 bytes ending at the data end, then shuffle them to the beginning
618  static const qint8 shufflecontrol[] = {
619  1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
620  -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
621  };
622  __m128i control = _mm_loadu_si128(reinterpret_cast<const __m128i *>(shufflecontrol + 15 - len));
623  data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p + len) - 1);
624  data = _mm_shuffle_epi8(data, control);
625  }
626 
627  hash16bytes(state0, data);
628  }
629 
630  // extract state0
631 # if QT_POINTER_SIZE == 8
632  return _mm_cvtsi128_si64(state0);
633 # else
634  return _mm_cvtsi128_si32(state0);
635 # endif
636 }
637 #endif
638 
639 #if defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
641 static size_t aeshash(const uchar *p, size_t len, size_t seed, size_t seed2) noexcept
642 {
643  uint8x16_t key;
644 # if QT_POINTER_SIZE == 8
645  uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seed2));
646  key = vreinterpretq_u8_u64(vseed);
647 # else
648 
649  uint32x2_t vseed = vmov_n_u32(seed);
650  vseed = vset_lane_u32(seed2, vseed, 1);
651  key = vreinterpretq_u8_u32(vcombine_u32(vseed, vseed));
652 # endif
653 
654  // Compared to x86 AES, ARM splits each round into two instructions
655  // and includes the pre-xor instead of the post-xor.
656  const auto hash16bytes = [](uint8x16_t &state0, uint8x16_t data) {
657  auto state1 = state0;
658  state0 = vaeseq_u8(state0, data);
659  state0 = vaesmcq_u8(state0);
660  auto state2 = state0;
661  state0 = vaeseq_u8(state0, state1);
662  state0 = vaesmcq_u8(state0);
663  auto state3 = state0;
664  state0 = vaeseq_u8(state0, state2);
665  state0 = vaesmcq_u8(state0);
666  state0 = veorq_u8(state0, state3);
667  };
668 
669  uint8x16_t state0 = key;
670 
671  if (len < 8)
672  goto lt8;
673  if (len < 16)
674  goto lt16;
675  if (len < 32)
676  goto lt32;
677 
678  // rounds of 32 bytes
679  {
680  // Make state1 = ~state0:
681  uint8x16_t state1 = veorq_u8(state0, vdupq_n_u8(255));
682 
683  // do simplified rounds of 32 bytes: unlike the Go code, we only
684  // scramble twice and we keep 256 bits of state
685  const auto *e = p + len - 31;
686  while (p < e) {
687  uint8x16_t data0 = vld1q_u8(p);
688  uint8x16_t data1 = vld1q_u8(p + 16);
689  auto oldstate0 = state0;
690  auto oldstate1 = state1;
691  state0 = vaeseq_u8(state0, data0);
692  state1 = vaeseq_u8(state1, data1);
693  state0 = vaesmcq_u8(state0);
694  state1 = vaesmcq_u8(state1);
695  auto laststate0 = state0;
696  auto laststate1 = state1;
697  state0 = vaeseq_u8(state0, oldstate0);
698  state1 = vaeseq_u8(state1, oldstate1);
699  state0 = vaesmcq_u8(state0);
700  state1 = vaesmcq_u8(state1);
701  state0 = veorq_u8(state0, laststate0);
702  state1 = veorq_u8(state1, laststate1);
703  p += 32;
704  }
705  state0 = veorq_u8(state0, state1);
706  }
707  len &= 0x1f;
708 
709  // do we still have 16 or more bytes?
710  if (len & 0x10) {
711 lt32:
712  uint8x16_t data = vld1q_u8(p);
713  hash16bytes(state0, data);
714  p += 16;
715  }
716  len &= 0xf;
717 
718  if (len & 0x08) {
719 lt16:
720  uint8x8_t data8 = vld1_u8(p);
721  uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
722  hash16bytes(state0, data);
723  p += 8;
724  }
725  len &= 0x7;
726 
727 lt8:
728  if (len) {
729  // load the last chunk of data
730  // We're going to load 8 bytes and mask zero the part we don't care
731  // (the hash of a short string is different from the hash of a longer
732  // including NULLs at the end because the length is in the key)
733  // WARNING: this may produce valgrind warnings, but it's safe
734 
735  uint8x8_t data8;
736 
737  if (Q_LIKELY(quintptr(p + 8) & 0xff8)) {
738  // same page, we definitely can't fault:
739  // load all 8 bytes and mask off the bytes past the end of the source
740  static const qint8 maskarray[] = {
741  -1, -1, -1, -1, -1, -1, -1,
742  0, 0, 0, 0, 0, 0, 0,
743  };
744  uint8x8_t mask = vld1_u8(reinterpret_cast<const quint8 *>(maskarray) + 7 - len);
745  data8 = vld1_u8(p);
746  data8 = vand_u8(data8, mask);
747  } else {
748  // too close to the end of the page, it could fault:
749  // load 8 bytes ending at the data end, then shuffle them to the beginning
750  static const qint8 shufflecontrol[] = {
751  1, 2, 3, 4, 5, 6, 7,
752  -1, -1, -1, -1, -1, -1, -1,
753  };
754  uint8x8_t control = vld1_u8(reinterpret_cast<const quint8 *>(shufflecontrol) + 7 - len);
755  data8 = vld1_u8(p - 8 + len);
756  data8 = vtbl1_u8(data8, control);
757  }
758  uint8x16_t data = vcombine_u8(data8, vdup_n_u8(0));
759  hash16bytes(state0, data);
760  }
761 
762  // extract state0
763 # if QT_POINTER_SIZE == 8
764  return vgetq_lane_u64(vreinterpretq_u64_u8(state0), 0);
765 # else
766  return vgetq_lane_u32(vreinterpretq_u32_u8(state0), 0);
767 # endif
768 }
769 #endif
770 
771 size_t qHashBits(const void *p, size_t size, size_t seed) noexcept
772 {
773 #ifdef QT_BOOTSTRAPPED
774  // the seed is always 0 in bootstrapped mode (no seed generation code),
775  // so help the compiler do dead code elimination
776  seed = 0;
777 #endif
778  // mix in the length as a secondary seed. For seed == 0, seed2 must be
779  // size, to match what we used to do prior to Qt 6.2.
780  size_t seed2 = size;
781  if (seed)
782  seed2 = qt_qhash_seed.currentSeed(1);
783 #ifdef AESHASH
784  if (seed && qCpuHasFeature(AES) && qCpuHasFeature(SSE4_2))
785  return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
786 #elif defined(Q_PROCESSOR_ARM) && QT_COMPILER_SUPPORTS_HERE(AES) && !defined(QHASH_AES_SANITIZER_BUILD) && !defined(QT_BOOTSTRAPPED)
787 # if defined(Q_OS_LINUX)
788  // Do specific runtime-only check as Yocto hard enables Crypto extension for
789  // all armv8 configs
790  if (seed && (qCpuFeatures() & CpuFeatureAES))
791 # else
792  if (seed && qCpuHasFeature(AES))
793 # endif
794  return aeshash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
795 #endif
796  if (size <= QT_POINTER_SIZE)
797  return murmurhash(p, size, seed);
798 
799  return siphash(reinterpret_cast<const uchar *>(p), size, seed, seed2);
800 }
801 
802 size_t qHash(const QByteArray &key, size_t seed) noexcept
803 {
804  return qHashBits(key.constData(), size_t(key.size()), seed);
805 }
806 
807 size_t qHash(const QByteArrayView &key, size_t seed) noexcept
808 {
809  return qHashBits(key.constData(), size_t(key.size()), seed);
810 }
811 
812 size_t qHash(QStringView key, size_t seed) noexcept
813 {
814  return qHashBits(key.data(), key.size()*sizeof(QChar), seed);
815 }
816 
817 size_t qHash(const QBitArray &bitArray, size_t seed) noexcept
818 {
819  qsizetype m = bitArray.d.size() - 1;
820  size_t result = qHashBits(reinterpret_cast<const uchar *>(bitArray.d.constData()), size_t(qMax(0, m)), seed);
821 
822  // deal with the last 0 to 7 bits manually, because we can't trust that
823  // the padding is initialized to 0 in bitArray.d
824  qsizetype n = bitArray.size();
825  if (n & 0x7)
826  result = ((result << 4) + bitArray.d.at(m)) & ((1 << n) - 1);
827  return result;
828 }
829 
830 size_t qHash(QLatin1String key, size_t seed) noexcept
831 {
832  return qHashBits(reinterpret_cast<const uchar *>(key.data()), size_t(key.size()), seed);
833 }
834 
889 {
890  return qt_qhash_seed.currentSeed(0);
891 }
892 
903 {
904  qt_qhash_seed.clearSeed();
905 }
906 
923 {
924  qt_qhash_seed.resetSeed();
925 }
926 
927 #if QT_DEPRECATED_SINCE(6,6)
939 int qGlobalQHashSeed()
940 {
941  return int(QHashSeed::globalSeed() & INT_MAX);
942 }
943 
968 void qSetGlobalQHashSeed(int newSeed)
969 {
970  if (Q_LIKELY(newSeed == 0 || newSeed == -1)) {
971  if (newSeed == 0)
973  else
975  } else {
976  // can't use qWarning here (reentrancy)
977  fprintf(stderr, "qSetGlobalQHashSeed: forced seed value is not 0; ignoring call\n");
978  }
979 }
980 #endif // QT_DEPRECATED_SINCE(6,6)
981 
997 uint qt_hash(QStringView key, uint chained) noexcept
998 {
999  auto n = key.size();
1000  auto p = key.utf16();
1001 
1002  uint h = chained;
1003 
1004  while (n--) {
1005  h = (h << 4) + *p++;
1006  h ^= (h & 0xf0000000) >> 23;
1007  h &= 0x0fffffff;
1008  }
1009  return h;
1010 }
1011 
1277 size_t qHash(double key, size_t seed) noexcept
1278 {
1279  // ensure -0 gets mapped to 0
1280  key += 0.0;
1281  if constexpr (sizeof(double) == sizeof(size_t)) {
1282  size_t k;
1283  memcpy(&k, &key, sizeof(double));
1284  return QHashPrivate::hash(k, seed);
1285  } else {
1286  return murmurhash(&key, sizeof(key), seed);
1287  }
1288 }
1289 
1290 #if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
1296 size_t qHash(long double key, size_t seed) noexcept
1297 {
1298  // ensure -0 gets mapped to 0
1299  key += static_cast<long double>(0.0);
1300  if constexpr (sizeof(long double) == sizeof(size_t)) {
1301  size_t k;
1302  memcpy(&k, &key, sizeof(long double));
1303  return QHashPrivate::hash(k, seed);
1304  } else {
1305  return murmurhash(&key, sizeof(key), seed);
1306  }
1307 }
1308 #endif
1309 
small capitals from c petite p scientific i
[1]
Definition: afcover.h:80
void storeRelaxed(T newValue) noexcept
Definition: qbasicatomic.h:91
T loadRelaxed() const noexcept
Definition: qbasicatomic.h:90
The QBitArray class provides an array of bits.
Definition: qbitarray.h:49
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:85
char * data()
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:84
template< typename Enum > size_t qHash(QFlags< Enum > flags, size_t seed=0) noexcept
size_t qHashBits(const void *p, size_t len, size_t seed=0)
Definition: qhash.cpp:771
size_t qHash(double key, size_t seed) noexcept
Definition: qhash.cpp:1277
size_t qHash(long double key, size_t seed) noexcept
Definition: qhash.cpp:1296
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
Definition: qstring.h:84
The QRandomGenerator class allows one to obtain random values from a high-quality Random Number Gener...
Definition: qrandom.h:57
static Q_DECL_CONST_FUNCTION QRandomGenerator * system()
Definition: qrandom.h:306
quint32 generate()
Definition: qrandom.h:84
quint64 generate64()
Definition: qrandom.h:89
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
Definition: qstringview.h:122
double e
else opt state
[0]
constexpr Q_DECL_CONST_FUNCTION size_t hash(size_t key, size_t seed) noexcept
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_LIKELY(x)
#define Q_DECL_COLD_FUNCTION
#define QT_WARNING_DISABLE_GCC(text)
#define Q_UINT64_C(c)
Definition: qglobal.h:296
unsigned int quint32
Definition: qglobal.h:288
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
Definition: qglobal.h:332
size_t quintptr
Definition: qglobal.h:310
ptrdiff_t qsizetype
Definition: qglobal.h:308
unsigned int uint
Definition: qglobal.h:334
QT_BEGIN_NAMESPACE typedef signed char qint8
Definition: qglobal.h:283
unsigned char quint8
Definition: qglobal.h:284
#define dROUNDS
Definition: qhash.cpp:415
#define cROUNDS
Definition: qhash.cpp:414
#define SIPROUND
Definition: qhash.cpp:419
#define Q_DECL_HOT_FUNCTION
Definition: qhash.cpp:77
uint qt_hash(QStringView key, uint chained) noexcept
Definition: qhash.cpp:997
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLuint64 key
GLboolean r
[2]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLuint end
GLenum src
GLint left
GLint GLfloat v0
GLint GLfloat GLfloat v1
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLfloat GLfloat GLfloat GLfloat v3
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat n
GLfloat GLfloat GLfloat GLfloat h
GLenum GLsizei len
Definition: qopenglext.h:3292
GLuint in
Definition: qopenglext.h:8870
GLuint64EXT * result
[6]
Definition: qopenglext.h:10932
GLfloat GLfloat p
[1]
Definition: qopenglext.h:12698
#define QT_POINTER_SIZE
QRandomGenerator::InitialRandomData qt_initial_random_value() noexcept
Definition: qrandom.cpp:1324
#define QT_FUNCTION_TARGET(x)
Definition: qsimd_p.h:182
#define CpuFeatureAES
Definition: qsimd_x86_p.h:85
#define k0
#define k1
Q_UNUSED(salary)
[21]
QRandomGenerator generator(sseq)
socketLayer initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)
static Q_CORE_EXPORT void setDeterministicGlobalSeed()
Definition: qhash.cpp:902
static Q_CORE_EXPORT void resetRandomGlobalSeed()
Definition: qhash.cpp:922
static Q_CORE_EXPORT QHashSeed globalSeed() noexcept
Definition: qhash.cpp:888
QThreadStorage< int * > dummy[8]