summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSérgio Martins <sergio.martins@kdab.com>2015-05-25 18:32:35 +0100
committerMarc Mutz <marc.mutz@kdab.com>2015-05-30 07:15:24 +0000
commit9eff0dd19d6507ec400f036dd27efe960e4e5f78 (patch)
treeed9cd2e3bffc0df9e6fcbb1daa4b52210aec347b
parentfda08f3971e854ad1623fb99212746143c27e412 (diff)
QSet: Introduce intersects().
The pattern "mySet.intersect(other).isEmpty()" has been spotted in the wild and in Qt codebase. intersects() is much cheaper because it bails out as soon as we find one common item and doesn't do any allocations. [ChangeLog][QtCore][QSet] Added intersects(). Change-Id: I44a350dc4cdb9deb835a23eee99fc99d6ca24c82 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
-rw-r--r--src/corelib/tools/qhash.h1
-rw-r--r--src/corelib/tools/qset.h30
-rw-r--r--src/corelib/tools/qset.qdoc12
-rw-r--r--tests/auto/corelib/tools/qset/tst_qset.cpp27
4 files changed, 69 insertions, 1 deletions
diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h
index 3d713146fe..2080a22e23 100644
--- a/src/corelib/tools/qhash.h
+++ b/src/corelib/tools/qhash.h
@@ -353,6 +353,7 @@ public:
class const_iterator
{
friend class iterator;
+ friend class QSet<Key>;
QHashData::Node *i;
public:
diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h
index e4688711d6..5a9c75fe07 100644
--- a/src/corelib/tools/qset.h
+++ b/src/corelib/tools/qset.h
@@ -137,6 +137,7 @@ public:
typedef QHash<T, QHashDummyValue> Hash;
typename Hash::const_iterator i;
friend class iterator;
+ friend class QSet<T>;
public:
typedef std::bidirectional_iterator_tag iterator_category;
@@ -191,6 +192,7 @@ public:
inline const_iterator constFind(const T &value) const { return find(value); }
QSet<T> &unite(const QSet<T> &other);
QSet<T> &intersect(const QSet<T> &other);
+ bool intersects(const QSet<T> &other) const;
QSet<T> &subtract(const QSet<T> &other);
// STL compatibility
@@ -284,6 +286,34 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other)
}
template <class T>
+Q_INLINE_TEMPLATE bool QSet<T>::intersects(const QSet<T> &other) const
+{
+ const bool otherIsBigger = other.size() > size();
+ const QSet &smallestSet = otherIsBigger ? *this : other;
+ const QSet &biggestSet = otherIsBigger ? other : *this;
+ const bool equalSeeds = q_hash.d->seed == other.q_hash.d->seed;
+ typename QSet::const_iterator i = smallestSet.cbegin();
+ typename QSet::const_iterator e = smallestSet.cend();
+
+ if (Q_LIKELY(equalSeeds)) {
+ // If seeds are equal we take the fast path so no hash is recalculated.
+ while (i != e) {
+ if (*biggestSet.q_hash.findNode(*i, i.i.i->h) != biggestSet.q_hash.e)
+ return true;
+ ++i;
+ }
+ } else {
+ while (i != e) {
+ if (biggestSet.contains(*i))
+ return true;
+ ++i;
+ }
+ }
+
+ return false;
+}
+
+template <class T>
Q_INLINE_TEMPLATE QSet<T> &QSet<T>::subtract(const QSet<T> &other)
{
QSet<T> copy1(*this);
diff --git a/src/corelib/tools/qset.qdoc b/src/corelib/tools/qset.qdoc
index 94cfa729f5..c4f33deed6 100644
--- a/src/corelib/tools/qset.qdoc
+++ b/src/corelib/tools/qset.qdoc
@@ -490,7 +490,17 @@
Removes all items from this set that are not contained in the
\a other set. A reference to this set is returned.
- \sa operator&=(), unite(), subtract()
+ \sa intersects(), operator&=(), unite(), subtract()
+*/
+
+/*!
+ \fn bool QSet::intersects(const QSet<T> &other) const
+ \since 5.6
+
+ Returns \c true if this set has at least one item in common with
+ \a other.
+
+ \sa contains(), intersect()
*/
/*!
diff --git a/tests/auto/corelib/tools/qset/tst_qset.cpp b/tests/auto/corelib/tools/qset/tst_qset.cpp
index f13d69514a..ef0ebabd66 100644
--- a/tests/auto/corelib/tools/qset/tst_qset.cpp
+++ b/tests/auto/corelib/tools/qset/tst_qset.cpp
@@ -73,6 +73,7 @@ private slots:
void makeSureTheComfortFunctionsCompile();
void initializerList();
void qhash();
+ void intersects();
};
struct IdentityTracker {
@@ -1030,6 +1031,32 @@ void tst_QSet::qhash()
}
}
+void tst_QSet::intersects()
+{
+ QSet<int> s1;
+ QSet<int> s2;
+
+ QVERIFY(!s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 100;
+ QVERIFY(s1.intersects(s1));
+ QVERIFY(!s1.intersects(s2));
+
+ s2 << 200;
+ QVERIFY(!s1.intersects(s2));
+
+ s1 << 200;
+ QVERIFY(s1.intersects(s2));
+
+ const QtQHashSeedSaver seedSaver(0x10101010);
+ QSet<int> s3;
+ s3 << 500;
+ QVERIFY(!s1.intersects(s3));
+ s3 << 200;
+ QVERIFY(s1.intersects(s3));
+}
+
QTEST_APPLESS_MAIN(tst_QSet)
#include "tst_qset.moc"