QHostAddress: Improve code generation
Mostly related to IPv6, because Q_IPV6ADDR is an array of char, so the compilers were generating byte access to each value. Instead, force access as 32- and 64-bit in most places that make sense (64-bit access decays to 32-bit on 32-bit machines). In one isLoopback(), this is now a 128-bit access for best improvement. Some smaller improvements relating to SpecialAddress by combining the three IPv4 special addresses. Change-Id: I7de033f80b0e4431b7f1ffff13f932b1cd7b5d21 Reviewed-by: Richard J. Moore <rich@kde.org>
This commit is contained in:
parent
b479d5befb
commit
dd92002416
@ -46,6 +46,9 @@
|
||||
#ifndef QT_NO_DATASTREAM
|
||||
#include <qdatastream.h>
|
||||
#endif
|
||||
#ifdef __SSE2__
|
||||
# include <private/qsimd_p.h>
|
||||
#endif
|
||||
|
||||
#ifdef QT_LINUXBASE
|
||||
# include <arpa/inet.h>
|
||||
@ -106,7 +109,11 @@ public:
|
||||
QString scopeId;
|
||||
|
||||
quint32 a; // IPv4 address
|
||||
Q_IPV6ADDR a6; // IPv6 address
|
||||
union {
|
||||
Q_IPV6ADDR a6; // IPv6 address
|
||||
struct { quint64 c[2]; } a6_64;
|
||||
struct { quint32 c[4]; } a6_32;
|
||||
};
|
||||
QAbstractSocket::NetworkLayerProtocol protocol;
|
||||
|
||||
bool isParsed;
|
||||
@ -123,24 +130,17 @@ QHostAddressPrivate::QHostAddressPrivate()
|
||||
void QHostAddressPrivate::setAddress(quint32 a_)
|
||||
{
|
||||
a = a_;
|
||||
//create mapped address, except for a_ == 0 (any)
|
||||
memset(&a6, 0, sizeof(a6));
|
||||
if (a) {
|
||||
a6[11] = 0xFF;
|
||||
a6[10] = 0xFF;
|
||||
} else {
|
||||
a6[11] = 0;
|
||||
a6[10] = 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i=15; a_ != 0; i--) {
|
||||
a6[i] = a_ & 0xFF;
|
||||
a_ >>=8;
|
||||
}
|
||||
Q_ASSERT(i >= 11);
|
||||
protocol = QAbstractSocket::IPv4Protocol;
|
||||
isParsed = true;
|
||||
|
||||
//create mapped address, except for a_ == 0 (any)
|
||||
a6_64.c[0] = 0;
|
||||
if (a) {
|
||||
a6_32.c[2] = qToBigEndian(0xffff);
|
||||
a6_32.c[3] = qToBigEndian(a);
|
||||
} else {
|
||||
a6_64.c[1] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// parses v4-mapped addresses or the AnyIPv6 address and stores in \a a;
|
||||
@ -163,21 +163,16 @@ static bool convertToIpv4(quint32& a, const Q_IPV6ADDR &a6)
|
||||
|
||||
void QHostAddressPrivate::setAddress(const quint8 *a_)
|
||||
{
|
||||
for (int i = 0; i < 16; i++)
|
||||
a6[i] = a_[i];
|
||||
a = 0;
|
||||
convertToIpv4(a, a6);
|
||||
protocol = QAbstractSocket::IPv6Protocol;
|
||||
isParsed = true;
|
||||
memcpy(a6.c, a_, sizeof(a6));
|
||||
a = 0;
|
||||
convertToIpv4(a, a6);
|
||||
}
|
||||
|
||||
void QHostAddressPrivate::setAddress(const Q_IPV6ADDR &a_)
|
||||
{
|
||||
a6 = a_;
|
||||
a = 0;
|
||||
convertToIpv4(a, a6);
|
||||
protocol = QAbstractSocket::IPv6Protocol;
|
||||
isParsed = true;
|
||||
setAddress(a_.c);
|
||||
}
|
||||
|
||||
static bool parseIp6(const QString &address, QIPAddressUtils::IPv6Address &addr, QString *scopeId)
|
||||
@ -486,31 +481,35 @@ QHostAddress::QHostAddress(SpecialAddress address)
|
||||
{
|
||||
Q_IPV6ADDR ip6;
|
||||
memset(&ip6, 0, sizeof ip6);
|
||||
quint32 ip4 = INADDR_ANY;
|
||||
|
||||
switch (address) {
|
||||
case Null:
|
||||
break;
|
||||
return;
|
||||
|
||||
case Broadcast:
|
||||
d->setAddress(quint32(-1));
|
||||
ip4 = INADDR_BROADCAST;
|
||||
break;
|
||||
case LocalHost:
|
||||
d->setAddress(0x7f000001);
|
||||
break;
|
||||
case LocalHostIPv6:
|
||||
ip6[15] = 1;
|
||||
d->setAddress(ip6);
|
||||
ip4 = INADDR_LOOPBACK;
|
||||
break;
|
||||
case AnyIPv4:
|
||||
setAddress(0u);
|
||||
break;
|
||||
|
||||
case LocalHostIPv6:
|
||||
ip6[15] = 1;
|
||||
// fall through
|
||||
case AnyIPv6:
|
||||
d->setAddress(ip6);
|
||||
break;
|
||||
return;
|
||||
|
||||
case Any:
|
||||
d->clear();
|
||||
d->protocol = QAbstractSocket::AnyIPProtocol;
|
||||
break;
|
||||
return;
|
||||
}
|
||||
|
||||
// common IPv4 part
|
||||
d->setAddress(ip4);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -837,34 +836,36 @@ bool QHostAddress::operator==(const QHostAddress &other) const
|
||||
bool QHostAddress::operator ==(SpecialAddress other) const
|
||||
{
|
||||
QT_ENSURE_PARSED(this);
|
||||
quint32 ip4 = INADDR_ANY;
|
||||
switch (other) {
|
||||
case Null:
|
||||
return d->protocol == QAbstractSocket::UnknownNetworkLayerProtocol;
|
||||
|
||||
case Broadcast:
|
||||
return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_BROADCAST;
|
||||
ip4 = INADDR_BROADCAST;
|
||||
break;
|
||||
|
||||
case LocalHost:
|
||||
return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_LOOPBACK;
|
||||
ip4 = INADDR_LOOPBACK;
|
||||
break;
|
||||
|
||||
case Any:
|
||||
return d->protocol == QAbstractSocket::AnyIPProtocol;
|
||||
|
||||
case AnyIPv4:
|
||||
return d->protocol == QAbstractSocket::IPv4Protocol && d->a == INADDR_ANY;
|
||||
break;
|
||||
|
||||
case LocalHostIPv6:
|
||||
case AnyIPv6:
|
||||
if (d->protocol == QAbstractSocket::IPv6Protocol) {
|
||||
Q_IPV6ADDR ip6 = { { 0 } };
|
||||
ip6[15] = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
|
||||
return memcmp(&d->a6, &ip6, sizeof ip6) == 0;
|
||||
quint64 second = quint8(other == LocalHostIPv6); // 1 for localhost, 0 for any
|
||||
return d->a6_64.c[0] == 0 && d->a6_64.c[1] == qToBigEndian(second);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
return false;
|
||||
// common IPv4 part
|
||||
return d->protocol == QAbstractSocket::IPv4Protocol && d->a == ip4;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -1086,11 +1087,15 @@ bool QHostAddress::isLoopback() const
|
||||
if ((d->a & 0xFF000000) == 0x7F000000)
|
||||
return true; // v4 range (including IPv6 wrapped IPv4 addresses)
|
||||
if (d->protocol == QAbstractSocket::IPv6Protocol) {
|
||||
if (d->a6.c[15] != 1)
|
||||
#ifdef __SSE2__
|
||||
const __m128i loopback = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
|
||||
__m128i ipv6 = _mm_loadu_si128((const __m128i *)d->a6.c);
|
||||
__m128i cmp = _mm_cmpeq_epi8(ipv6, loopback);
|
||||
return _mm_movemask_epi8(cmp) == 0xffff;
|
||||
#else
|
||||
if (d->a6_64.c[0] != 0 || qFromBigEndian(d->a6_64.c[1]) != 1)
|
||||
return false;
|
||||
for (int i = 0; i < 15; i++)
|
||||
if (d->a6[i] != 0)
|
||||
return false;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -642,10 +642,12 @@ void tst_QHostAddress::isLoopback_data()
|
||||
QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << false;
|
||||
QTest::newRow("Broadcast") << QHostAddress(QHostAddress::Broadcast) << false;
|
||||
QTest::newRow("Null") << QHostAddress(QHostAddress::Null) << false;
|
||||
QTest::newRow("ipv6-all-ffff") << QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") << false;
|
||||
|
||||
QTest::newRow("::ffff:127.0.0.1") << QHostAddress("::ffff:127.0.0.1") << true;
|
||||
QTest::newRow("::ffff:127.0.0.2") << QHostAddress("::ffff:127.0.0.2") << true;
|
||||
QTest::newRow("::ffff:127.3.2.1") << QHostAddress("::ffff:127.3.2.1") << true;
|
||||
|
||||
}
|
||||
|
||||
void tst_QHostAddress::isLoopback()
|
||||
|
Loading…
Reference in New Issue
Block a user