63 #include <private/qrandom_p.h>
64 #include <private/qsimd_p.h>
66 #ifndef QT_BOOTSTRAPPED
75 # define Q_DECL_HOT_FUNCTION __attribute__((hot))
77 # define Q_DECL_HOT_FUNCTION
84 static_assert(
sizeof(
size_t) ==
QT_POINTER_SIZE,
"size_t and pointers have different size.");
87 struct HashSeedStorage
89 static constexpr
int SeedCount = 2;
92 constexpr HashSeedStorage() =
default;
95 OverriddenByEnvironment = -1,
104 StateResult
state(
int which = -1);
107 return {
state(which).requestedSeed };
129 [[maybe_unused]]
static void ensureConstexprConstructibility()
131 static_assert(std::is_trivially_destructible_v<HashSeedStorage>);
132 static constexpr HashSeedStorage
dummy {};
139 StateResult
result = { 0, OverriddenByEnvironment };
141 int seed = qEnvironmentVariableIntValue(
"QT_HASH_SEED", &
ok);
145 fprintf(stderr,
"QT_HASH_SEED: forced seed value is not 0; ignored.\n");
155 for (
int i = 0;
i < SeedCount; ++
i) {
160 result.state = JustInitialized;
167 StateResult
result = { BadSeed, AlreadyInitialized };
169 #ifndef QT_BOOTSTRAPPED
170 static auto once = [&]() {
176 result = { 0, OverriddenByEnvironment };
179 if (
result.state == AlreadyInitialized && which >= 0)
180 return { seeds[which].
loadRelaxed(), AlreadyInitialized };
188 static HashSeedStorage qt_qhash_seed;
194 #if QT_POINTER_SIZE == 4
201 const unsigned int m = 0x5bd1e995;
206 unsigned int h = seed ^
len;
210 const unsigned char *
data =
reinterpret_cast<const unsigned char *
>(
key);
254 static inline uint64_t murmurhash(
const void *
key, uint64_t
len, uint64_t seed) noexcept
256 const uint64_t
m = 0xc6a4a7935bd1e995ULL;
259 uint64_t
h = seed ^ (
len *
m);
261 const unsigned char *
data =
reinterpret_cast<const unsigned char *
>(
key);
262 const unsigned char *
end =
data + (
len & ~7ul);
266 memcpy(&k,
data,
sizeof(uint64_t));
302 #if QT_POINTER_SIZE == 8
312 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
333 static uint64_t siphash(
const uint8_t *
in, uint64_t inlen, uint64_t seed, uint64_t seed2)
336 uint64_t
v0 = 0x736f6d6570736575ULL;
337 uint64_t
v1 = 0x646f72616e646f6dULL;
338 uint64_t
v2 = 0x6c7967656e657261ULL;
339 uint64_t
v3 = 0x7465646279746573ULL;
344 const uint8_t *
end =
in + (inlen & ~7ULL);
345 const int left = inlen & 7;
353 uint64_t
m = qFromUnaligned<uint64_t>(
in);
363 #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
368 b |= ((uint64_t)
in[6]) << 48;
370 b |= ((uint64_t)
in[5]) << 40;
372 b |= ((uint64_t)
in[4]) << 32;
374 b |= ((uint64_t)
in[3]) << 24;
376 b |= ((uint64_t)
in[2]) << 16;
378 b |= ((uint64_t)
in[1]) << 8;
380 b |= ((uint64_t)
in[0]);
417 #define ROTL(x, b) (uint32_t)(((x) << (b)) | ((x) >> (32 - (b))))
449 const uint8_t *
end =
in + (inlen & ~3ULL);
450 const int left = inlen & 3;
458 uint m = qFromUnaligned<uint>(
in);
467 #if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
499 #if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__)
500 # define QHASH_AES_SANITIZER_BUILD
501 #elif __has_feature(address_sanitizer) || __has_feature(thread_sanitizer)
502 # define QHASH_AES_SANITIZER_BUILD
510 #if QT_COMPILER_SUPPORTS_HERE(AES) && QT_COMPILER_SUPPORTS_HERE(SSE4_2) && \
511 !defined(QHASH_AES_SANITIZER_BUILD)
514 #undef QHASH_AES_SANITIZER_BUILD
517 static size_t aeshash(
const uchar *
p,
size_t len,
size_t seed,
size_t seed2) noexcept
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);
540 const auto hash2x16bytes = [](__m128i &state0, __m128i &state1,
const __m128i *src0,
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);
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);
559 mseed = _mm_cvtsi32_si128(
int(seed));
560 mseed2 = _mm_set1_epi32(
int(seed2));
564 mseed = _mm_insert_epi16(mseed,
short(seed), 4);
566 mseed = _mm_shufflehi_epi16(mseed, 0);
569 __m128i
key = _mm_xor_si128(mseed, mseed2);
572 __m128i state0 = _mm_aesenc_si128(
key,
key);
574 auto src =
reinterpret_cast<const __m128i *
>(
p);
575 if (
len >=
sizeof(__m128i)) {
577 __m128i state1 = _mm_aesenc_si128(state0, mseed2);
579 const auto srcend =
reinterpret_cast<const __m128i *
>(
p +
len);
582 for ( ;
src + 2 < srcend;
src += 2)
583 hash2x16bytes(state0, state1,
src,
src + 1);
585 if (
src + 1 < srcend) {
587 hash2x16bytes(state0, state1,
src, srcend - 1);
588 }
else if (
src != srcend) {
590 __m128i
data = _mm_loadu_si128(srcend - 1);
591 hash16bytes(state0,
data);
595 state0 = _mm_xor_si128(state0, state1);
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,
612 __m128i
mask = _mm_loadu_si128(
reinterpret_cast<const __m128i *
>(maskarray + 15 -
len));
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
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);
627 hash16bytes(state0,
data);
631 # if QT_POINTER_SIZE == 8
632 return _mm_cvtsi128_si64(state0);
634 return _mm_cvtsi128_si32(state0);
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
644 # if QT_POINTER_SIZE == 8
645 uint64x2_t vseed = vcombine_u64(vcreate_u64(seed), vcreate_u64(seed2));
646 key = vreinterpretq_u8_u64(vseed);
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));
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);
669 uint8x16_t state0 =
key;
681 uint8x16_t state1 = veorq_u8(state0, vdupq_n_u8(255));
685 const auto *
e =
p +
len - 31;
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);
705 state0 = veorq_u8(state0, state1);
712 uint8x16_t
data = vld1q_u8(
p);
713 hash16bytes(state0,
data);
720 uint8x8_t data8 = vld1_u8(
p);
721 uint8x16_t
data = vcombine_u8(data8, vdup_n_u8(0));
722 hash16bytes(state0,
data);
740 static const qint8 maskarray[] = {
741 -1, -1, -1, -1, -1, -1, -1,
744 uint8x8_t
mask = vld1_u8(
reinterpret_cast<const quint8 *
>(maskarray) + 7 -
len);
746 data8 = vand_u8(data8,
mask);
750 static const qint8 shufflecontrol[] = {
752 -1, -1, -1, -1, -1, -1, -1,
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);
758 uint8x16_t
data = vcombine_u8(data8, vdup_n_u8(0));
759 hash16bytes(state0,
data);
763 # if QT_POINTER_SIZE == 8
764 return vgetq_lane_u64(vreinterpretq_u64_u8(state0), 0);
766 return vgetq_lane_u32(vreinterpretq_u32_u8(state0), 0);
773 #ifdef QT_BOOTSTRAPPED
782 seed2 = qt_qhash_seed.currentSeed(1);
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)
792 if (seed && qCpuHasFeature(AES))
794 return aeshash(
reinterpret_cast<const uchar *
>(
p),
size, seed, seed2);
797 return murmurhash(
p,
size, seed);
799 return siphash(
reinterpret_cast<const uchar *
>(
p),
size, seed, seed2);
820 size_t result =
qHashBits(
reinterpret_cast<const uchar *
>(bitArray.d.constData()),
size_t(qMax(0,
m)), seed);
890 return qt_qhash_seed.currentSeed(0);
904 qt_qhash_seed.clearSeed();
924 qt_qhash_seed.resetSeed();
927 #if QT_DEPRECATED_SINCE(6,6)
939 int qGlobalQHashSeed()
968 void qSetGlobalQHashSeed(
int newSeed)
970 if (
Q_LIKELY(newSeed == 0 || newSeed == -1)) {
977 fprintf(stderr,
"qSetGlobalQHashSeed: forced seed value is not 0; ignoring call\n");
1000 auto p =
key.utf16();
1005 h = (
h << 4) + *
p++;
1006 h ^= (
h & 0xf0000000) >> 23;
1281 if constexpr (
sizeof(
double) ==
sizeof(
size_t)) {
1283 memcpy(&k, &
key,
sizeof(
double));
1286 return murmurhash(&
key,
sizeof(
key), seed);
1290 #if !defined(Q_OS_DARWIN) || defined(Q_CLANG_QDOC)
1299 key +=
static_cast<long double>(0.0);
1300 if constexpr (
sizeof(
long double) ==
sizeof(
size_t)) {
1302 memcpy(&k, &
key,
sizeof(
long double));
1305 return murmurhash(&
key,
sizeof(
key), seed);
small capitals from c petite p scientific i
[1]
void storeRelaxed(T newValue) noexcept
T loadRelaxed() const noexcept
The QBitArray class provides an array of bits.
The QByteArray class provides an array of bytes.
The QChar class provides a 16-bit Unicode character.
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)
size_t qHash(double key, size_t seed) noexcept
size_t qHash(long double key, size_t seed) noexcept
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal.
The QRandomGenerator class allows one to obtain random values from a high-quality Random Number Gener...
static Q_DECL_CONST_FUNCTION QRandomGenerator * system()
The QStringView class provides a unified view on UTF-16 strings with a read-only subset of the QStrin...
constexpr Q_DECL_CONST_FUNCTION size_t hash(size_t key, size_t seed) noexcept
#define Q_BASIC_ATOMIC_INITIALIZER(a)
#define Q_DECL_COLD_FUNCTION
#define QT_WARNING_DISABLE_GCC(text)
QT_BEGIN_INCLUDE_NAMESPACE typedef unsigned char uchar
QT_BEGIN_NAMESPACE typedef signed char qint8
#define Q_DECL_HOT_FUNCTION
uint qt_hash(QStringView key, uint chained) noexcept
GLint GLfloat GLfloat GLfloat v2
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLint GLfloat GLfloat GLfloat GLfloat v3
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLfloat GLfloat GLfloat GLfloat h
QRandomGenerator::InitialRandomData qt_initial_random_value() noexcept
#define QT_FUNCTION_TARGET(x)
QRandomGenerator generator(sseq)
socketLayer initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)
static Q_CORE_EXPORT void setDeterministicGlobalSeed()
static Q_CORE_EXPORT void resetRandomGlobalSeed()
static Q_CORE_EXPORT QHashSeed globalSeed() noexcept
QThreadStorage< int * > dummy[8]