| Commit message (Collapse) | Author | Age | Files | Lines |
|
|
|
|
|
|
| |
Everywhere, except for ARM.
Change-Id: I50e2158aeade4256ad1dfffd17b11ca2d57ad1fb
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It's the same aeshash() as before, except we're passing a template
parameter to indicate whether to read half and then zero-extend the
data. That is, it will perform a conversion from Latin1 on the fly.
When running in zero-extending mode, the length parameters are actually
doubled (counting the number of UTF-16 code units) and we then divide
again by 2 when advancing.
The implementation should have the following performance
characteristics:
* QLatin1StringView now will be roughly half as fast as Qt 6.7
* QLatin1StringView now will be roughly as fast as QStringView
For the aeshash128() in default builds of QtCore (will use SSE4.1), the
long loop (32 characters or more) is:
QStringView QLatin1StringView
movdqu -0x20(%rax),%xmm4 | pmovzxbw -0x10(%rdx),%xmm2
movdqu -0x10(%rax),%xmm5 | pmovzxbw -0x8(%rdx),%xmm3
add $0x20,%rax | add $0x10,%rdx
pxor %xmm4,%xmm0 | pxor %xmm2,%xmm0
pxor %xmm5,%xmm1 | pxor %xmm3,%xmm1
aesenc %xmm0,%xmm0 aesenc %xmm0,%xmm0
aesenc %xmm1,%xmm1 aesenc %xmm1,%xmm1
aesenc %xmm0,%xmm0 aesenc %xmm0,%xmm0
aesenc %xmm1,%xmm1 aesenc %xmm1,%xmm1
The number of instructions is identical, but there are actually 2 more
uops per iteration. LLVM-MCA simulation shows this should execute in the
same number of cycles on older CPUs that do not have support for VAES
(see <https://analysis.godbolt.org/z/x95Mrfrf7>).
For the VAES version in aeshash256() and the AVX10 version in
aeshash256_256():
QStringView QLatin1StringView
vpxor -0x40(%rax),%ymm1,%ym | vpmovzxbw -0x20(%rax),%ymm3
vpxor -0x20(%rax),%ymm0,%ym | vpmovzxbw -0x10(%rax),%ymm2
add $0x40,%rax | add $0x20,%rax
| vpxor %ymm3,%ymm0,%ymm0
| vpxor %ymm2,%ymm1,%ymm1
vaesenc %ymm1,%ymm1,%ymm1 <
vaesenc %ymm0,%ymm0,%ymm0 vaesenc %ymm0,%ymm0,%ymm0
vaesenc %ymm1,%ymm1,%ymm1 vaesenc %ymm1,%ymm1,%ymm1
vaesenc %ymm0,%ymm0,%ymm0 vaesenc %ymm0,%ymm0,%ymm0
> vaesenc %ymm1,%ymm1,%ymm1
In this case, the increase in number of instructions matches the
increase in number of uops. The LLVM-MCA simulation says that the
QLatin1StringView version is faster at 11 cycles/iteration vs 14 cyc/it
(see <https://analysis.godbolt.org/z/1Gv1coz13>), but that can't be
right.
Measured performance of CPU cycles, on an Intel Core i9-7940X (Skylake,
no VAES support), normalized on the QString performance (QByteArray is
used as a stand-in for the performance in Qt 6.7):
aeshash | siphash
QByteArray QL1SV QString QByteArray QString
dictionary 94.5% 79.7% 100.0% 150.5%* 159.8%
paths-small 90.2% 93.2% 100.0% 202.8% 290.3%
uuids 81.8% 100.7% 100.0% 215.2% 350.7%
longstrings 42.5% 100.8% 100.0% 185.7% 353.2%
numbers 95.5% 77.9% 100.0% 155.3%* 164.5%
On an Intel Core i7-1165G7 (Tiger Lake, capable of VAES and AVX512VL):
aeshash | siphash
QByteArray QL1SV QString QByteArray QString
dictionary 90.0% 91.1% 100.0% 103.3%* 157.1%
paths-small 99.4% 104.8% 100.0% 237.5% 358.0%
uuids 88.5% 117.6% 100.0% 274.5% 461.7%
longstrings 57.4% 111.2% 100.0% 503.0% 974.3%
numbers 90.6% 89.7% 100.0% 98.7%* 149.9%
On an Intel 4th Generation Xeon Scalable Platinum (Sapphire Rapids, same
Golden Cove core as Alder Lake):
aeshash | siphash
QByteArray QL1SV QString QByteArray QString
dictionary 89.9% 102.1% 100.0% 158.1%* 172.7%
paths-small 78.0% 89.4% 100.0% 159.4% 258.0%
uuids 109.1% 107.9% 100.0% 279.0% 496.3%
longstrings 52.1% 112.4% 100.0% 564.4% 1078.3%
numbers 85.8% 98.9% 100.0% 152.6%* 190.4%
* dictionary contains very short entries (6 characters)
* paths-small contains strings of varying length, but very few over 32
* uuids-list contains fixed-length strings (38 characters)
* longstrings is the same but 304 characters
* numbers also a lot contains very short strings (1 to 6 chars)
What this shows:
* For short strings, the performance difference is negligible between
all three
* For longer strings, QLatin1StringView now costs between 7 and 17% more
than QString on the tested machines instead of up to ~50% less, except on
the older machine (where I think the main QString hashing is suffering
from memory bandwidth limitations)
* The AES hash implementation is anywhere from 1.6 to 11x faster than
Siphash
* Murmurhash (marked with asterisk) is much faster than Siphash, but it
only managed to beat the AES hash in one test
Change-Id: I664b9f014ffc48cbb49bfffd17b045c1811ac0ed
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
|
|
| |
So that it hashes to the same value as QString{,View}.
In order to test this, you must either run on a CPU other than ARM and
x86, or disable the AES hasher. I did that and can confirm siphash and
murmurhash do work with on-the-fly conversion from Latin-1.
Change-Id: I664b9f014ffc48cbb49bfffd17b03e5e62ec4e89
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
|
| |
I didn't do it in a template because the 32-bit code requires a
compatibility hack for Qt 6 and it's using an XOR of the high and low
parts.
Fixes: QTBUG-116080
Change-Id: I5dd50a1a7ca5424d9e7afffd17ae0ba5b9ff52f6
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
If we add the typedefs, we also need to add the qHash() overloads. See
code comments for the explanation of how it works. I chose to use an
addition to merge the upper and lower parts because of the comment in
QHashCombineCommutative's operator(), introduced by commit
91b44afdcba3f4cb2ddc7a80c0cff723b408b447.
Found in 6.6 API-review, but didn't make the cut and then was
forgotten.
Drive-by fix long line nearby.
[ChangeLog][QtCore] Added qHash() overloads for quint128 and qint128.
Fixes: QTBUG-116054
Task-number: QTBUG-116080
Change-Id: If484aed08ba476e0eace800b719f435203100f3e
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
|
|
|
|
|
|
|
|
|
|
|
| |
So we can test more values. Because we are testing more values, we can't
use QEXPECT_FAIL, because we can't guarantee a mismatch.
Pick-to: 6.7
Task-number: QTBUG-116077
Task-number: QTBUG-116080
Change-Id: I664b9f014ffc48cbb49bfffd17b021719e6d612f
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
| |
According to QUIP-18 [1], all tests file should be
LicenseRef-Qt-Commercial OR GPL-3.0-only
[1]: https://contribute.qt-project.org/quips/18
Pick-to: 6.7
Task-number: QTBUG-121787
Change-Id: I9657df5d660820e56c96d511ea49d321c54682e8
Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de>
|
|
|
|
|
|
|
|
|
|
|
|
| |
Commit c0791ac76ec7cfdc3945efa67a6f72ee3623413c didn't explain why it
was #ifdef'ed out. It's just an alias for double. Maybe compilers at the
time used to complain if you used it, but I can't make Apple's clang
produce a warning now.
Pick-to: 6.7
Change-Id: I664b9f014ffc48cbb49bfffd17b02293403e9571
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
|
|
|
|
|
|
|
|
|
|
|
| |
types
Looking good, because all signed integral qHash overloads are implemented
by casting to the unsigned type before hashing.
Pick-to: 6.7 6.6 6.5
Change-Id: I8372eb6d4a57b40c2371db58d1b5aeabe9a3951a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
| |
Amends c86cf385d6d66d8fd3de1666205aaf4b8fcec747.
tst_qhashfunctions.cpp:109:59: warning: converting to ‘qfloat16::NativeType’ {aka ‘_Float16’} from ‘float’ with greater conversion rank
Pick-to: 6.6 6.5
Change-Id: I79e700614d034281bf55fffd178f91775966658f
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There were two problems:
- On platforms where QFLOAT16_IS_NATIVE == true, a qHash(qfloat16{})
call has become ambiguous between the three FP qHash() overloads
(float, double, long double), where it was unambiguously calling the
float one in Qt 6.4. This SiC was caused by the replacement of
operator float() by operator __fp16() in
99c7f0419e66692260be56c0385badeacb3f6760, which is in Qt 6.5.
- On platforms where QFLOAT16_IS_NATIVE == false, qHash(qfloat16{})
would produce a different value from qHash(float{}), and therefore
Qt 6.4, when the seed was != 0, because the former would go via the
one-arg-to-two-arg qHash adapter while the latter one would
not. Since participating functions are inline, this causes old and
new code to produce different hash values for the same qfloat16,
leading to a BiC possibly corrupting QHash etc.
Fix both by adding an explicit qHash(qfloat16). This function is
inline, so it doesn't add a new symbol to 6.5.x.
[ChangeLog][QtCore] Fixed qHash(qfloat16) which was broken from 6.5.0
to 6.5.3, inclusive. If you compiled against one of the affected Qt
versions, you need to recompile against either Qt 6.4 or earlier or
6.5.4 or later, because the problematic code is inline.
Pick-to: 6.6 6.5
Fixes: QTBUG-116064
Fixes: QTBUG-116076
Change-Id: Id02bc29a6c3ec463352f4bef314c040369081e9b
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Because the local `seed` variable shadowed the member one, this test
was run for each QFETCH_GLOBAL with the same data and seed. That
doesn't make sense, so make the test use the member variable `seed`,
as all other tests already do.
Since zero is one of the seeds coming from QFETCH_GLOBAL, drop the
seedless calls to qHash(), too.
Amends 64bfc927b09b46bb7fc0dc6caf1bf1a4d4133ab4.
Pick-to: 6.6 6.5 6.2
Change-Id: I1e22ec0b38341264bcf2d5c26146cbbcab6e0749
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The old code only tested with seed = 0 and seed = 1045982819, the
latter being a "random number", which, however, fits into
32-bits. Since Qt 6.0 increased the seed from uint to size_t, amend
the test to actually test a seed value with some of the upper half of
bits set, too, also in 64-bit mode.
While we're at it, also test with each seed's bits flipped for extra
coverage.
Remove a static assertion that prevented testing seeds with the MSB
set.
Pick-to: 6.6 6.5 6.2
Change-Id: I5ed6ffb5cabaaead0eb9c01f994d15dcbc622509
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Ivan Solovev <ivan.solovev@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
It's ... broken. Found and filed lots of bugs. Add #ifdef'ery and
QEXPECTED_FAIL() to document the state of affairs, hopefully reminding
us to fix these things come Qt 7.
Task-number: QTBUG-116064
Task-number: QTBUG-116076
Task-number: QTBUG-116077
Task-number: QTBUG-116079
Task-number: QTBUG-116080
Pick-to: 6.6 6.5
Change-Id: I29e89fdf995ddf60ef1e03c7af009e80980c9817
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We were only ever testing with a 0 seed, even though the function was
called for all QFETCH_GLOBAL seeds.
Add the seed.
Amends 5e93361888e3d2b03e7b6da19517b44e0239fb47.
Pick-to: 6.6 6.5 6.2 5.15
Change-Id: I3c78714ad6fb3f94233789dd2c8884d9b157fa76
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
qhashfunctions.h defines a catch-all 2-arguments qHash(T, seed)
in order to support datatypes that implement a 1-argument overload
of qHash (i.e. qHash(Type)). The catch-all calls the 1-argument
overload and XORs the result with the seed.
The catch-all is constrained on the existence of such a 1-argument
overload. This is done in order to make the catch-all SFINAE-friendly;
otherwise merely instantiating the catch-all would trigger a hard error.
Such an error would make it impossible to build a type trait that
detects if one can call qHash(T, size_t) for a given type T.
The constraint itself is called HasQHashSingleArgOverload and lives in a
private namespace.
It has been observed that HasQHashSingleArgOverload misbehaves for
some datatypes. For instance, HasQHashSingleArgOverload<int> is actually
false, despite qHash(123) being perfectly callable. (The second argument
of qHash(int, size_t) is defaulted, so the call *is* possible.)
--
Why is HasQHashSingleArgOverload<int> false?
This has to do with how HasQHashSingleArgOverload<T> is implemented: as
a detection trait that checks if qHash(declval<T>()) is callable.
The detection itself is not a problem. Consider this code:
template <typename T>
constexpr bool HasQHashSingleArgOverload = /* magic */;
class MyClass {};
size_t qHash(MyClass);
static_assert(HasQHashSingleArgOverload<MyClass>); // OK
Here, the static_assert passes, even if qHash(MyClass) (and MyClass
itself) were not defined at all when HasQHashSingleArgOverload was
defined.
This is nothing but 2-phase lookup at work ([temp.dep.res]): the
detection inside HasQHashSingleArgOverload takes into account the qHash
overloads available when HasQHashSingleArgOverload was declared, as well
as any other overload declared before the "point of instantiation". This
means that qHash(MyClass) will be visible and detected.
Let's try something slightly different:
template <typename T>
constexpr bool HasQHashSingleArgOverload = /* magic */;
size_t qHash(int);
static_assert(HasQHashSingleArgOverload<int>); // ERROR
This one *does not work*. How is it possible? The answer is that 2-phase
name lookup combines the names found at definition time with the names
_found at instantiation time using argument-dependent lookup only_.
`int` is a fundamental type and does not participate in ADL. In the
example, HasQHashSingleArgOverload has actually no qHash overloads to
even consider, and therefore its detection fails.
You can restore detection by moving the declaration of the qHash(int)
overload *before* the definition of HasQHashSingleArgOverload, so it's
captured at definition time:
size_t qHash(int);
template <typename T>
constexpr bool HasQHashSingleArgOverload = /* magic */;
static_assert(HasQHashSingleArgOverload<int>); // OK!
This is why HasQHashSingleArgOverload<int> is currently returning
`false`: because HasQHashSingleArgOverload is defined *before* all the
qHash(fundamental_type) overloads in qhashfunctions.h.
--
Now consider this variation of the above, where we keep the qHash(int)
overload after the detector (so, it's not found), but also prepend an
Evil class implicitly convertible from int:
struct Evil { Evil(int); };
size_t qHash(Evil);
template <typename T> constexpr bool HasQHashSingleArgOverload = /* magic */;
size_t qHash(int);
static_assert(HasQHashSingleArgOverload<int>); // OK
Now the static_assert passes. HasQHashSingleArgOverload is still not
considering qHash(int) (it's declared after), but it's considering
qHash(Evil). Can you call *that* one with an int? Yes, after a
conversion to Evil.
This is extremely fragile and likely an ODR violation (if not ODR, then
likely falls into [temp.dep.candidate/1]).
--
Does this "really matter" for a type like `int`? The answer is no. If
HasQHashSingleArgOverload<int> is true, then a call like
qHash(42, 123uz);
will have two overloads in its overloads set:
1) qHash(int, size_t)
2) qHash(T, size_t), i.e. the catch-all template. To be pedantic,
qHash<int>(const int &, size_t), that is, the instantiation of the
catch-all after template type deduction for T (= int)
([over.match.funcs.general/8]).
Although it may look like this is ambiguous as both calls have perfect
matches for the arguments, 1) is actually a better match than 2) because
it is not a template specialization ([over.match.best/2.4]).
In other words: qHash(int, size_t) is *always* called when the argument
is `int`, no matter the value of HasQHashSingleArgOverload<int>. The
catch-all template may be added or not to the overload set, but it's
a worse match anyways.
--
Now, let's consider this code:
enum MyEnum { E1, E2, E3 };
qHash(E1, 42uz);
This code compiles, although we do not define any qHash overload
specifically for enumeration types (nor one is defined by MyEnum's
author).
Which qHash overload gets called? Again there are two possible
overloads available:
1) qHash(int, size_t). E1 can be converted to `int` ([conv.prom/3]),
and this overload selected.
2) qHash(T, size_t), which after instantiation, is qHash<MyEnum>(const
MyEnum &, size_t).
In this case, 2) is a better match than 1), because it does not require
any conversion for the arguments.
Is 2) a viable overload? Unfortunately the answer here is "it depends",
because it's subject to what we've learned before: since the catch-all
is constrained by the HasQHashSingleArgOverload trait, names introduced
before the trait may exclude or include the overload.
This code:
#include <qhashfunctions.h>
enum MyEnum { E1, E2, E3 };
qHash(E1, 42uz);
static_assert(HasQHashSingleArgOverload<MyEnum>); // ERROR
will fail the static_assert. This means that only qHash(int, size_t) is
in the overload set.
However, this code:
struct Evil { Evil(int); };
size_t qHash(Evil);
#include <qhashfunctions.h>
enum MyEnum { E1, E2, E3 };
qHash(E1, 42uz);
static_assert(HasQHashSingleArgOverload<MyEnum>); // OK
will pass the static_assert. qHash(Evil) can be called with an object of
type MyEnum after an user-defined conversion sequence
([over.best.ics.general], [over.ics.user]: a standard conversion
sequence, made of a lvalue-to-rvalue conversion + a integral promotion,
followed by a conversion by constructor [class.conv.ctor]).
Therefore, HasQHashSingleArgOverload<MyEnum> is true here; the catch-all
template is added to the overload set; and it's a best match for the
qHash(E1, 42uz) call.
--
Is this a problem? **Yes**, and a huge one: the catch-all template does
not yield the same value as the qHash(int, size_t) overload. This means
that calculating hash values (e.g. QHash, QSet) will have different
results depending on include ordering!
A translation unit TU1 may have
#include <QSet>
#include <Evil>
QSet<MyEnum> calculateSet { /* ... */ }
And another translation unit TU2 may have
#include <Evil>
#include <QSet> // different order
void use() {
QSet<MyEnum> set = calculateSet();
}
And now the two TUs cannot exchange QHash/QSet objects as they would
hash the contents differently.
--
`Evil` actually exists in Qt. The bug report specifies QKeySequence,
which has an implicit constructor from int, but one can concoct infinite
other examples.
--
Congratulations if you've read so far.
=========================
=== PROPOSED SOLUTION ===
=========================
1) Move the HasQHashSingleArgOverload detection after declaring the
overloads for all the fundamental types (which we already do anyways).
This means that HasQHashSingleArgOverload<fundamental_type> will now
be true. It also means that the catch-all becomes available for all
fundamental types, but as discussed before, for all of them we have
better matches anyways.
2) For unscoped enumeration types, this means however an ABI break: the
catch-all template becomes always the best match. Code compiled before
this change would call qHash(int, size_t), and code compiled after this
change would call the catch-all qHash<Enum>(Enum, size_t); as discussed
before, the two don't yield the same results, so mixing old code and new
code will break.
In order to restore the old behavior, add a qHash overload for
enumeration types that forwards the implementation to the integer
overloads (using qToUnderlying¹).
(Here I'm considering the "old", correct behavior the one that one gets
by simply including QHash/QSet, declaring an enumeration and calling
qHash on it. In other words, without having Evil around before including
QHash.)
This avoids an ABI break for most enumeration types, for which one
does not explicitly define a qHash overload. It however *introduces*
an ABI break for enumeration types for which there is a single-argument
qHash(E) overload. This is because
- before this change, the catch-all template was called, and that
in turn called qHash(E) and XOR'ed the result with the seed;
- after this change, the newly introduced qHash overload for
enumerations gets called. It's very likely that it would not give
the same result as before.
I don't have a solution for this, so we'll have to accept the ABI
break.
Note that if one defines a two-arguments overload for an enum type,
then nothing changes there (the overload is still the best match).
3) Make plans to kill the catch-all template, for Qt 7.0 at the latest.
We've asked users to provide a two-args qHash overload for a very long
time, it's time to stop working around that.
4) Make plans to switch from overloading qHash to specializing std::hash
(or equivalent). Specializations don't overload, and we'd get rid of
all these troubles with implicit conversions.
--
¹ To nitpick, qToUnderlying may select a *different* overload than
the one selected by an implicit conversion.
That's because an unscoped enumeration without a fixed underlying type
is allowed to have an underlying type U, and implicitly convert to V,
with U and V being two different types (!).
U is "an integral type that can represent all the enumerator values"
([dcl.enum/7]). V is selected in a specific list in a specific order
([conv.prom]/3). This means that in theory a compiler can take enum E {
E1, E2 }, give it `unsigned long long` as underlying type, and still
allow for a conversion to `int`.
As far as I know, no compiler we use does something as crazy as that,
but if it's a concern, it needs to be fixed.
[ChangeLog][Deprecation Notice] Support for overloads of qHash with only
one argument is going to be removed in Qt 7. Users are encouraged to
upgrade to the two-arguments overload. Please refer to the QHash
documentation for more information.
[ChangeLog][Potentially Binary-Incompatible Changes] If an enumeration
type for which a single-argument qHash overload has been declared is
being used as a key type in QHash, QMultiHash or QSet, then objects of
these types are no longer binary compatible with code compiled against
an earlier version of Qt. It is very unlikely that such qHash overloads
exist, because enumeration types work out of the box as keys Qt
unordered associative containers; users do not need to define qHash
overloads for their custom enumerations. Note that there is no binary
incompatibity if a *two* arguments qHash overload has been declared
instead.
Fixes: QTBUG-108032
Fixes: QTBUG-107033
Pick-to: 6.2 6.4
Change-Id: I2ebffb2820c553e5fdc3a341019433793a58e3ab
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
| |
These functions are marked as deprecated in future Qt releases.
Task-number: QTBUG-104858
Change-Id: I25d2932455d8c9e3e2d722b1c48fc2cfa2d1e679
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Replace the current license disclaimer in files by
a SPDX-License-Identifier.
Files that have to be modified by hand are modified.
License files are organized under LICENSES directory.
Task-number: QTBUG-67283
Change-Id: Id880c92784c40f3bbde861c0d93f58151c18b9f1
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Jörg Bornemann <joerg.bornemann@qt.io>
|
|
|
|
|
| |
Change-Id: Ibc6a948480a904913a5427e6408d4d296784fb4f
Reviewed-by: Sona Kurazyan <sona.kurazyan@qt.io>
|
|
|
|
|
|
|
|
|
|
|
| |
... instead of QT_PREPEND_NAMESPACE(qHash), which is qualified (prepends at least '::'), and therefore disables ADL.
This is not a problem as long as we wrote our qHash() overloads as free functions (incl. non-hidden friends), but it should™ fail for hidden friends, so use the old using-std::swap() trick to bring QT_PREPEND_NAMESPACE(qHash) into scope, proceeding with an unqualified lookup.
Pick-to: 6.2
Change-Id: I00860b2313699849f86bfe3dd9f41db4ce993cd3
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
| |
... extending the existing check for ADL-found qHash()
implementations.
Pick-to: 6.2 5.15
Change-Id: Iac6ed2721db9e95ee921bd1d5170fa8c8d43475d
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There were two problems here: first, qHash(std::pair) must be declared
before qHashMulti that might call back to qHash(std::pair) (i.e., a pair
with one element that is also a pair). But moving the declaration above
causes the second problem: the noexcept expression can't refer to qHash
functions that aren't declared yet. So we forward-declare a constexpr
function for that result, but implement it far below.
Fixes: QTBUG-92910
Change-Id: Ia8e48103a54446509e3bfffd16767ed2e29b026c
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
|
|
|
|
|
|
|
|
|
| |
Complete search and replace of QtTest and QtTest/QtTest with QTest, as
QtTest includes the whole module. Replace all such instances with
correct header includes. See Jira task for more discussion.
Fixes: QTBUG-88831
Change-Id: I981cfae18a1cabcabcabee376016b086d9d01f44
Pick-to: 6.0
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
|
|
|
|
|
|
|
|
| |
Export some private functions from QUtf8 to resolve
undefined symbols in Qt5Compat after moving QStringRef.
Task-number: QTBUG-84437
Change-Id: I9046dcb14ed520d8868a511d79da6e721e26f72b
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
There is no reason for keep using our macro now that we have C++17.
The macro itself is left in for the moment being, as well as its
detection logic, because it's needed for C code (not everything
supports C11 yet). A few more cleanups will arrive in the next few
patches.
Note that this is a mere search/replace; some places were using
double braces to work around the presence of commas in a macro, no
attempt has been done to fix those.
tst_qglobal had just some minor changes to keep testing the macro.
Change-Id: I1c1c397d9f3e63db3338842bf350c9069ea57639
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
|
|
|
|
| |
Change-Id: I2164df19cd17ab96a39020de66a3fe9fec838a36
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The old implementation was either using CRC32 on modern processors
or a trivial, but rather slow implementation.
We can't continue with CRC32, as that implementation can only
give us 32bit hashes, where we now need to support 64bit in Qt 6.
Change the implementation to use MurmurHash, as public domain
implementation that is both very fast and leads to well distributed hashes.
This hash function is about as fast as the SSE optimized CRC32 implementation
but works everywhere and gives us 64 bit hash values.
Here are some numbers (time for 10M hashes):
14 char 16 char
QByteArray QString float
old qHash (non CRC32) 127ms 134ms 48ms
old qHash (using SSE CRC32 instructions 60ms 62ms 46ms
new qHash 52ms 43ms 46ms
Unfortunately MurmurHash is not safe against hash table DoS attacks, as
potential hash collisions are indepenent of the seed. This will get
addressed in followup commit, where we use SipHash or an SSE optimized
AES based hashing algorithm that does not have those issues.
Change-Id: I4fbc0ac299215b6db78c7a0a2a1d7689b0ea848b
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
|
|
| |
This is required, so that QHash and QSet can hold more
than 2^32 items on 64 bit platforms.
The actual hashing functions for strings are still 32bit, this will
be changed in a follow-up commit.
Change-Id: I4372125252486075ff3a0b45ecfa818359fe103b
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
We have a problem. Our types don't play well with the std unordered
containers, because they do not specialize std::hash. We therefore
force our users to come up with an implementation, hindering
interoperability, since any two developers are unlikely to come up
with compatible implementations. So combining libraries written by
different developers will result in ODR violations.
Now that we depend on C++11, and thus the presence of std::hash, we
still face the problem that the standard does not provide us with a
means to compose new hash functions out of old ones. In particular, we
cannot, yet, depend on C++17's std::hash<std::string_view> to
implement std::hash<QByteArray>, say. There's also no std::hash for
std::tuple, which would allow easy composition by using std::tie().
So piggy-back on the work we have done over the years on qHash()
functions, and implement the std::hash specializations for Qt types
using the existing qHash() functions, with a twist: The standard
allows implementations to provide means against predictable hash
values. Qt has this, too, but the seed is managed by the container and
passed to the qHash() function as a separate argument. The standard
does not have this explicit seed, so any protection must be implicit
in the normal use of std::hash.
To reap whatever protection that std library has on offer, if any, we
calculate a seed value by hashing int(0). This will be subject to
constant folding if there's no actual seed, but will produce a value
dependent on the seed if there is one.
Add some tests.
A question that remains is how to document the specialization. Can we
have a \stdhashable QDoc macro that does everything for us?
Task-number: QTBUG-33428
Change-Id: Idfe775f1661f8489587353c4b148d76611ac76f3
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
|
|
|
|
|
|
|
|
|
|
|
|
| |
That's the only value for which we will guarantee a stable result across
Qt versions and across invocations of the same application on different
architectures is zero. For any other value, we reserve the right to
change the algorithm. We'll now print a warning when we detect that.
Task-number: QTBUG-47566
Change-Id: I27b55fdf514247549455fffd14b1135e10d24ab4
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: David Faure <david.faure@kdab.com>
|
|\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Conflicts:
src/corelib/tools/qbytearray.h
src/corelib/tools/qdatetime.h
src/corelib/tools/qstring.h
src/corelib/tools/qversionnumber.h
src/plugins/platforms/android/qandroidplatformintegration.cpp
tests/auto/corelib/tools/qhashfunctions/tst_qhashfunctions.cpp
Change-Id: Iefd92a435e687a76cd593099e40d9a9620a1454d
|
| |
| |
| |
| |
| | |
Change-Id: Ib0e40a7a3ebc44329f23fffd14b2e927021a1a2e
Reviewed-by: David Faure <david.faure@kdab.com>
|
| |
| |
| |
| |
| |
| | |
Change-Id: I64a169fd6c8e2444bfe67e3ecd5375ea7b6a81ee
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
|
|/
|
|
|
| |
Change-Id: I5c41287991f6dd2eeb3d54699da0f653bfac59be
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Remove most type traits from qtypetraits.h, but keep the custom
implementation of is_signed/is_unsigned. This gets rid of
BSD-3 licensed code from Google in a public header (hugh!).
The custom implementations for is_signed/is_unsigned are kept
because the implementations in gcc's standard headers do not
work as we expect for enums - both is_signed and is_unsigned
always returns false there - see also
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59027
[ChangeLog][QtCore][General] Qt now relies on type traits from
the C++ standard library.
Change-Id: I3f2188b46949f04ca4482a6ac9afd3482103f0e1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|\
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
Conflicts:
qmake/library/qmakeevaluator.cpp
One side changed the iterator to use ranged-for, the other changed its
body; they only conflicted because the latter had to add braces around
the body, intruding on the for-line. Trivial resolution.
Change-Id: Ib487bc3bd6e3c5225db15f94b9a8f6caaa33456b
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
In Qt, null QStrings compare equal to empty ones, so add an explicit
check that the corresponding hash values are identical, too.
Ditto for QByteArray.
Change-Id: I190fc95a765305928d9b6b0e4955433865b6b247
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| | |
From Qt 5.7 -> tools & applications are lisenced under GPL v3 with some
exceptions, see
http://blog.qt.io/blog/2016/01/13/new-agreement-with-the-kde-free-qt-foundation/
Updated license headers to use new GPL-EXCEPT header instead of LGPL21 one
(in those files which will be under GPL 3 with exceptions)
Change-Id: I42a473ddc97101492a60b9287d90979d9eb35ae1
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
|
|/
|
|
|
|
|
|
|
|
|
| |
We already include <utility> in <qglobal.h>, so we might
as well provide a qHash() overload for std::pair.
[ChangeLog][QtCore] Added qHash(std::pair), defined in
<QHashFunctions>.
Change-Id: I0f61c513e82e05ce9d2e56bcf18f3be9e2da4da9
Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
In some cases it's not possible to use QT_HASH_SEED, specially when
we need to set the environment variable from inside the application,
as dynamically loaded libraries or plugins may create static QHash
instances. That would set qt_qhash_seed to a value different from
-1 and skip the env var value.
For those cases, and when we still want to set qt_qhash_seed, we
provide a way to enforce its value.
Auto-tests accessing qt_qhash_seed directly have been updated
accordingly. Usage in qdoc, uic and rcc has been left as is
for the time being.
Change-Id: I3b35b4fa0223c83b1348a6508641905a2a63266f
Reviewed-by: Lars Knoll <lars.knoll@theqtcompany.com>
|
|
|
|
|
| |
Change-Id: Ibebe1318d1c2de97601aa07269705c87737083ee
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Qt copyrights are now in The Qt Company, so we could update the source
code headers accordingly. In the same go we should also fix the links to
point to qt.io.
Outdated header.LGPL removed (use header.LGPL21 instead)
Old header.LGPL3 renamed to header.LGPL3-COMM to match actual licensing
combination. New header.LGPL-COMM taken in the use file which were
using old header.LGPL3 (src/plugins/platforms/android/extract.cpp)
Added new header.LGPL3 containing Commercial + LGPLv3 + GPLv2 license
combination
Change-Id: I6f49b819a8a20cc4f88b794a8f6726d975e8ffbe
Reviewed-by: Matti Paaso <matti.paaso@theqtcompany.com>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
qHashRange() takes an (input iterator) range and hashes each element, combining
the hash values using the hash combiner from Boost/N1837 with the magic number
0x9e3779b9, as described here:
http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
qHashRangeCommutative() does the same but with a cummutative combiner (unsigned
addition) to create hash values that are order-independent, e.g. for hashed
containers. The obvious combiner, XOR, is a bad one because it eliminates
duplicate elements. Signed addition cannot be used, since signed overflow
leads to undefined behavior.
[ChangeLog][QtCore] Added qHashRange() and qHashRangeCommutative() functions to aid
implementing qHash() overloads for custom types.
Change-Id: I3c2bbc9ce4bd0455262a70e0cf248486525e534f
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
|
|
This is in preparation of adding more qHash()-related tests.
Change-Id: Iae65bf8b123e1d6ac6d1eb34d74ba4eb9df8173c
Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
|