// Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include #include #include #include class tst_QDuplicateTracker : public QObject { Q_OBJECT private slots: void hasSeen(); void clear(); void appendTo(); void appendTo_special(); }; void tst_QDuplicateTracker::hasSeen() { { QDuplicateTracker tracker; QVERIFY(!tracker.hasSeen(0)); QVERIFY(tracker.hasSeen(0)); QVERIFY(!tracker.hasSeen(1)); QVERIFY(tracker.hasSeen(1)); // past the prealloc amount QVERIFY(!tracker.hasSeen(2)); QVERIFY(tracker.hasSeen(2)); } { QDuplicateTracker tracker; QString string1("string1"); QString string2("string2"); QString string2_2("string2"); QString string3("string3"); // Move when seen QVERIFY(!tracker.hasSeen(string1)); QVERIFY(tracker.hasSeen(std::move(string1))); // Move when unseen QVERIFY(!tracker.hasSeen(std::move(string2))); QVERIFY(tracker.hasSeen(string2_2)); // Past the prealloc amount QVERIFY(!tracker.hasSeen(string3)); QVERIFY(tracker.hasSeen(string3)); } } void tst_QDuplicateTracker::clear() { QDuplicateTracker tracker; QVERIFY(!tracker.hasSeen(0)); QVERIFY(tracker.hasSeen(0)); QVERIFY(!tracker.hasSeen(1)); QVERIFY(tracker.hasSeen(1)); tracker.clear(); QVERIFY(!tracker.hasSeen(0)); QVERIFY(tracker.hasSeen(0)); QVERIFY(!tracker.hasSeen(1)); QVERIFY(tracker.hasSeen(1)); } void tst_QDuplicateTracker::appendTo() { QDuplicateTracker tracker; QVERIFY(!tracker.hasSeen(0)); QVERIFY(!tracker.hasSeen(1)); QList a; a.append(-1); tracker.appendTo(a); std::sort(a.begin(), a.end()); QCOMPARE(a, QList({ -1, 0, 1 })); QList b; tracker.appendTo(b); std::sort(b.begin(), b.end()); QCOMPARE(b, QList({ 0, 1 })); QVERIFY(!tracker.hasSeen(2)); QList c; std::move(tracker).appendTo(c); std::sort(c.begin(), c.end()); QCOMPARE(c, QList({ 0, 1, 2 })); if (QDuplicateTracker::uses_pmr) { // the following is only true if we use the std container QVERIFY(!tracker.hasSeen(0)); QVERIFY(!tracker.hasSeen(1)); QVERIFY(!tracker.hasSeen(2)); } } struct ConstructionCounted { ConstructionCounted(int i) : i(i) { } ConstructionCounted(ConstructionCounted &&other) noexcept : i(other.i), copies(other.copies), moves(other.moves + 1) { // set to some easily noticeable values other.i = -64; other.copies = -64; other.moves = -64; } ConstructionCounted &operator=(ConstructionCounted &&other) noexcept { ConstructionCounted moved = std::move(other); swap(moved); // set to some easily noticeable values other.i = -64; other.copies = -64; other.moves = -64; return *this; } ConstructionCounted(const ConstructionCounted &other) noexcept : i(other.i), copies(other.copies + 1), moves(other.moves) { } ConstructionCounted &operator=(const ConstructionCounted &other) noexcept { ConstructionCounted copy = other; swap(copy); return *this; } ~ConstructionCounted() = default; friend bool operator==(const ConstructionCounted &lhs, const ConstructionCounted &rhs) { return lhs.i == rhs.i; } QString toString() { return QString::number(i); } void swap(ConstructionCounted &other) { std::swap(copies, other.copies); std::swap(i, other.i); std::swap(moves, other.moves); } int i; int copies = 0; int moves = 0; }; // for std::unordered_set namespace std { template<> struct hash { std::size_t operator()(const ConstructionCounted &c) const noexcept { return c.i; } }; } // for QSet size_t qHash(const ConstructionCounted &c, std::size_t seed = 0) { return qHash(c.i, seed); } void tst_QDuplicateTracker::appendTo_special() { QDuplicateTracker tracker(3); QVERIFY(!tracker.hasSeen(1)); QVERIFY(!tracker.hasSeen(2)); QVERIFY(!tracker.hasSeen(3)); QVERIFY(tracker.hasSeen(1)); QVERIFY(tracker.hasSeen(2)); QVERIFY(tracker.hasSeen(3)); { QList a; a.reserve(3); tracker.appendTo(a); for (const auto &counter : a) { QCOMPARE(counter.moves, 1); QCOMPARE(counter.copies, 1); } } QVERIFY(tracker.hasSeen(1)); QVERIFY(tracker.hasSeen(2)); QVERIFY(tracker.hasSeen(3)); { QList a; a.reserve(3); std::move(tracker).appendTo(a); if (QDuplicateTracker::uses_pmr) { // the following is only true if we use the std container for (const auto &counter : a) { QCOMPARE(counter.moves, 2); QCOMPARE(counter.copies, 0); } QVERIFY(!tracker.hasSeen(1)); QVERIFY(!tracker.hasSeen(2)); QVERIFY(!tracker.hasSeen(3)); } } } QTEST_MAIN(tst_QDuplicateTracker) #include "tst_qduplicatetracker.moc"