Add qHash(QRegExp) and qHash(QRegularExpression)

QReg*Exp*s can be compared for equality,
so qHash should be overloaded, too.

There was a (poor) private implementation of qHash(QRegExpEngineKey)
already, which has now been replaced with a better one (the old one
didn't take into account all the fields that make up equality,
producing unnecessary collisions).

[ChangeLog][QtCore][QRegExp] Added qHash(QRegExp).
[ChangeLog][QtCore][QRegularExpression] Added qHash(QRegularExpression).

Change-Id: I1d22fbcc0508018a3f94b4c24571b13ba6e07df2
Reviewed-by: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
This commit is contained in:
Marc Mutz 2015-04-08 19:44:48 +02:00
parent 85d9403a12
commit 87155a8d65
6 changed files with 58 additions and 5 deletions

View File

@ -38,6 +38,7 @@
#include "qcache.h"
#include "qdatastream.h"
#include "qdebug.h"
#include "qhashfunctions.h"
#include "qlist.h"
#include "qmap.h"
#include "qmutex.h"
@ -882,6 +883,15 @@ static bool operator==(const QRegExpEngineKey &key1, const QRegExpEngineKey &key
&& key1.cs == key2.cs;
}
static uint qHash(const QRegExpEngineKey &key, uint seed = 0) Q_DECL_NOTHROW
{
QtPrivate::QHashCombine hash;
seed = hash(seed, key.pattern);
seed = hash(seed, key.patternSyntax);
seed = hash(seed, key.cs);
return seed;
}
class QRegExpEngine;
//Q_DECLARE_TYPEINFO(QVector<int>, Q_MOVABLE_TYPE);
@ -3807,11 +3817,6 @@ struct QRegExpPrivate
};
#if !defined(QT_NO_REGEXP_OPTIM)
uint qHash(const QRegExpEngineKey &key, uint seed = 0) Q_DECL_NOTHROW
{
return qHash(key.pattern, seed);
}
typedef QCache<QRegExpEngineKey, QRegExpEngine> EngineCache;
Q_GLOBAL_STATIC(EngineCache, globalEngineCache)
static QBasicMutex globalEngineCacheMutex;
@ -4032,6 +4037,21 @@ bool QRegExp::operator==(const QRegExp &rx) const
return priv->engineKey == rx.priv->engineKey && priv->minimal == rx.priv->minimal;
}
/*!
\since 5.6
\relates QRegExp
Returns the hash value for \a key, using
\a seed to seed the calculation.
*/
uint qHash(const QRegExp &key, uint seed) Q_DECL_NOTHROW
{
QtPrivate::QHashCombine hash;
seed = hash(seed, key.priv->engineKey);
seed = hash(seed, key.priv->minimal);
return seed;
}
/*!
\fn bool QRegExp::operator!=(const QRegExp &rx) const

View File

@ -45,6 +45,9 @@ QT_BEGIN_NAMESPACE
struct QRegExpPrivate;
class QStringList;
class QRegExp;
Q_CORE_EXPORT uint qHash(const QRegExp &key, uint seed = 0) Q_DECL_NOTHROW;
class Q_CORE_EXPORT QRegExp
{
@ -104,6 +107,8 @@ public:
static QString escape(const QString &str);
friend Q_CORE_EXPORT uint qHash(const QRegExp &key, uint seed) Q_DECL_NOTHROW;
private:
QRegExpPrivate *priv;
};

View File

@ -38,6 +38,7 @@
#ifndef QT_NO_REGULAREXPRESSION
#include <QtCore/qcoreapplication.h>
#include <QtCore/qhashfunctions.h>
#include <QtCore/qmutex.h>
#include <QtCore/qvector.h>
#include <QtCore/qstringlist.h>
@ -1837,6 +1838,21 @@ bool QRegularExpression::operator==(const QRegularExpression &re) const
\sa operator==()
*/
/*!
\since 5.6
\relates QRegularExpression
Returns the hash value for \a key, using
\a seed to seed the calculation.
*/
uint qHash(const QRegularExpression &key, uint seed) Q_DECL_NOTHROW
{
QtPrivate::QHashCombine hash;
seed = hash(seed, key.d->pattern);
seed = hash(seed, key.d->patternOptions);
return seed;
}
/*!
Escapes all characters of \a str so that they no longer have any special
meaning when used as a regular expression pattern string, and returns

View File

@ -49,6 +49,9 @@ QT_BEGIN_NAMESPACE
class QRegularExpressionMatch;
class QRegularExpressionMatchIterator;
struct QRegularExpressionPrivate;
class QRegularExpression;
Q_CORE_EXPORT uint qHash(const QRegularExpression &key, uint seed = 0) Q_DECL_NOTHROW;
class Q_CORE_EXPORT QRegularExpression
{
@ -139,6 +142,7 @@ private:
friend class QRegularExpressionMatch;
friend struct QRegularExpressionMatchPrivate;
friend class QRegularExpressionMatchIterator;
friend Q_CORE_EXPORT uint qHash(const QRegularExpression &key, uint seed) Q_DECL_NOTHROW;
QRegularExpression(QRegularExpressionPrivate &dd);
QExplicitlySharedDataPointer<QRegularExpressionPrivate> d;

View File

@ -1224,6 +1224,9 @@ void tst_QRegExp::operator_eq()
for (int j = 0; j < I * J * K * ELL; ++j) {
QCOMPARE(rxtable[i] == rxtable[j], i / ELL == j / ELL);
QCOMPARE(rxtable[i] != rxtable[j], i / ELL != j / ELL);
// this just happens to have no hash collisions. If at some point
// we get collisions, restrict the test to only equal elements:
QCOMPARE(qHash(rxtable[i]) == qHash(rxtable[j]), i / ELL == j / ELL);
}
}
}

View File

@ -1424,6 +1424,7 @@ static void verifyEquality(const QRegularExpression &re1, const QRegularExpressi
{
QVERIFY(re1 == re2);
QVERIFY(re2 == re1);
QCOMPARE(qHash(re1), qHash(re2));
QVERIFY(!(re1 != re2));
QVERIFY(!(re2 != re1));
@ -1431,22 +1432,26 @@ static void verifyEquality(const QRegularExpression &re1, const QRegularExpressi
QVERIFY(re1 == re3);
QVERIFY(re3 == re1);
QCOMPARE(qHash(re1), qHash(re3));
QVERIFY(!(re1 != re3));
QVERIFY(!(re3 != re1));
QVERIFY(re2 == re3);
QVERIFY(re3 == re2);
QCOMPARE(qHash(re2), qHash(re3));
QVERIFY(!(re2 != re3));
QVERIFY(!(re3 != re2));
re3 = re2;
QVERIFY(re1 == re3);
QVERIFY(re3 == re1);
QCOMPARE(qHash(re1), qHash(re3));
QVERIFY(!(re1 != re3));
QVERIFY(!(re3 != re1));
QVERIFY(re2 == re3);
QVERIFY(re3 == re2);
QCOMPARE(qHash(re2), qHash(re3));
QVERIFY(!(re2 != re3));
QVERIFY(!(re3 != re2));
}