QSet: add insert(T&&)

We already have all we need in QHash to support this, so the addition
is simple enough.

Add test checking how many copies and/or moves are needed for a single
insert.

As a drive-by: remove some unneeded static_cast

Change-Id: Iaf768657644afa45f78f5c81ffcf89ba9607be96
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Mårten Nordheim 2020-11-26 15:43:17 +01:00
parent 6364194456
commit 734c8aa9d9
3 changed files with 82 additions and 6 deletions

View File

@ -184,7 +184,9 @@ public:
typedef const_iterator ConstIterator;
inline qsizetype count() const { return q_hash.count(); }
inline iterator insert(const T &value)
{ return static_cast<typename Hash::iterator>(q_hash.insert(value, QHashDummyValue())); }
{ return q_hash.insert(value, QHashDummyValue()); }
inline iterator insert(T &&value)
{ return q_hash.emplace(std::move(value), QHashDummyValue()); }
iterator find(const T &value) { return q_hash.find(value); }
const_iterator find(const T &value) const { return q_hash.find(value); }
inline const_iterator constFind(const T &value) const { return find(value); }

View File

@ -177,13 +177,8 @@ void tst_QDuplicateTracker::appendTo_special()
a.reserve(3);
tracker.appendTo(a);
for (const auto &counter : a) {
#if QT_HAS_INCLUDE(<memory_resource>) && __cplusplus > 201402L // uses pmr::unordered_set
QCOMPARE(counter.moves, 1);
QCOMPARE(counter.copies, 1);
#else // Uses QSet
QCOMPARE(counter.moves, 1);
QCOMPARE(counter.copies, 2);
#endif
}
}

View File

@ -59,6 +59,7 @@ private slots:
void begin();
void end();
void insert();
void insertConstructionCounted();
void setOperations();
void stlIterator();
void stlMutableIterator();
@ -579,6 +580,84 @@ void tst_QSet::insert()
}
}
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);
std::swap(*this, moved);
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;
std::swap(*this, 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); }
int i;
int copies = 0;
int moves = 0;
};
size_t qHash(const ConstructionCounted &c, std::size_t seed = 0)
{
return qHash(c.i, seed);
}
void tst_QSet::insertConstructionCounted()
{
QSet<ConstructionCounted> set;
// copy-insert
ConstructionCounted toCopy(7);
auto inserted = set.insert(toCopy);
QCOMPARE(set.size(), 1);
auto element = set.begin();
QCOMPARE(inserted, element);
QCOMPARE(inserted->copies, 1);
QCOMPARE(inserted->moves, 1);
QCOMPARE(inserted->i, 7);
// move-insert
ConstructionCounted toMove(8);
inserted = set.insert(std::move(toMove));
element = set.find(8);
QCOMPARE(set.size(), 2);
QVERIFY(element != set.end());
QCOMPARE(inserted, element);
QCOMPARE(inserted->copies, 0);
QCOMPARE(inserted->moves, 1);
QCOMPARE(inserted->i, 8);
inserted = set.insert(std::move(toCopy)); // move-insert an existing value
QCOMPARE(set.size(), 2);
// The previously existing key is used as they compare equal:
QCOMPARE(inserted->copies, 1);
QCOMPARE(inserted->moves, 1);
}
void tst_QSet::setOperations()
{
QSet<QString> set1, set2;