the number of elements in the list.
*/
-const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, true, { 0 } };
+const QListData::Data QListData::shared_null = { Q_REFCOUNT_INITIALIZE_STATIC, 0, 0, 0, { 0 } };
static int grow(int size)
{
Q_CHECK_PTR(t);
t->ref.initializeOwned();
- t->sharable = true;
t->alloc = alloc;
// The space reservation algorithm's optimization is biased towards appending:
// Something which looks like an append will put the data at the beginning,
Q_CHECK_PTR(t);
t->ref.initializeOwned();
- t->sharable = true;
t->alloc = alloc;
if (!alloc) {
t->begin = 0;
struct Data {
QtPrivate::RefCount ref;
int alloc, begin, end;
- uint sharable : 1;
void *array[1];
};
enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
public:
inline QList() : d(const_cast<QListData::Data *>(&QListData::shared_null)) { }
- inline QList(const QList<T> &l) : d(l.d) { d->ref.ref(); if (!d->sharable) detach_helper(); }
+ QList(const QList<T> &l);
~QList();
QList<T> &operator=(const QList<T> &l);
#ifdef Q_COMPILER_RVALUE_REFS
}
inline bool isDetached() const { return !d->ref.isShared(); }
- inline void setSharable(bool sharable) { if (!sharable) detach(); if (d != &QListData::shared_null) d->sharable = sharable; }
+ inline void setSharable(bool sharable)
+ {
+ if (sharable == d->ref.isSharable())
+ return;
+ if (!sharable)
+ detach();
+ if (d != &QListData::shared_null)
+ d->ref.setSharable(sharable);
+ }
inline bool isSharedWith(const QList<T> &other) const { return d == other.d; }
inline bool isEmpty() const { return p.isEmpty(); }
}
template <typename T>
+Q_OUTOFLINE_TEMPLATE QList<T>::QList(const QList<T> &l)
+ : d(l.d)
+{
+ if (!d->ref.ref()) {
+ p.detach(d->alloc);
+
+ struct Cleanup
+ {
+ Cleanup(QListData::Data *d) : d_(d) {}
+ ~Cleanup() { if (d_) qFree(d_); }
+
+ QListData::Data *d_;
+ } tryCatch(d);
+
+ node_copy(reinterpret_cast<Node *>(p.begin()),
+ reinterpret_cast<Node *>(p.end()),
+ reinterpret_cast<Node *>(l.p.begin()));
+ tryCatch.d_ = 0;
+ }
+}
+
+template <typename T>
Q_OUTOFLINE_TEMPLATE QList<T>::~QList()
{
if (!d->ref.deref())
Q_OBJECT
private slots:
+ void init();
+ void cleanup();
+
void length() const;
void lengthSignature() const;
void append() const;
void initializeList() const;
void const_shared_null() const;
+ void setSharable1_data() const;
+ void setSharable1() const;
+ void setSharable2_data() const;
+ void setSharable2() const;
+
+private:
+ int dummyForGuard;
+};
+
+struct Complex
+{
+ Complex(int val)
+ : value(val)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex(Complex const &other)
+ : value(other.value)
+ , checkSum(this)
+ {
+ ++liveCount;
+ }
+
+ Complex &operator=(Complex const &other)
+ {
+ check(); other.check();
+
+ value = other.value;
+ return *this;
+ }
+
+ ~Complex()
+ {
+ --liveCount;
+ check();
+ }
+
+ operator int() const { return value; }
+
+ bool operator==(Complex const &other) const
+ {
+ check(); other.check();
+ return value == other.value;
+ }
+
+ bool check() const
+ {
+ if (this != checkSum) {
+ ++errorCount;
+ return false;
+ }
+ return true;
+ }
+
+ struct Guard
+ {
+ Guard() : initialLiveCount(liveCount) {}
+ ~Guard() { if (liveCount != initialLiveCount) ++errorCount; }
+
+ private:
+ Q_DISABLE_COPY(Guard);
+ int initialLiveCount;
+ };
+
+ static void resetErrors() { errorCount = 0; }
+ static int errors() { return errorCount; }
+
+private:
+ static int errorCount;
+ static int liveCount;
+
+ int value;
+ void *checkSum;
};
+int Complex::errorCount = 0;
+int Complex::liveCount = 0;
+
+void tst_QList::init()
+{
+ Complex::resetErrors();
+ new (&dummyForGuard) Complex::Guard();
+}
+
+void tst_QList::cleanup()
+{
+ QCOMPARE(Complex::errors(), 0);
+
+ reinterpret_cast<Complex::Guard *>(&dummyForGuard)->~Guard();
+ QCOMPARE(Complex::errors(), 0);
+}
+
void tst_QList::length() const
{
/* Empty list. */
QVERIFY(!list2.isDetached());
}
+Q_DECLARE_METATYPE(QList<int>);
+Q_DECLARE_METATYPE(QList<Complex>);
+
+template <class T>
+void generateSetSharableData()
+{
+ QTest::addColumn<QList<T> >("list");
+ QTest::addColumn<int>("size");
+
+ QTest::newRow("null") << QList<T>() << 0;
+ QTest::newRow("non-empty") << (QList<T>() << T(0) << T(1) << T(2) << T(3) << T(4)) << 5;
+}
+
+template <class T>
+void runSetSharableTest()
+{
+ QFETCH(QList<T>, list);
+ QFETCH(int, size);
+
+ QVERIFY(!list.isDetached()); // Shared with QTest
+
+ list.setSharable(true);
+
+ QCOMPARE(list.size(), size);
+
+ {
+ QList<T> copy(list);
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ list.setSharable(false);
+ QVERIFY(list.isDetached() || list.isSharedWith(QList<T>()));
+
+ {
+ QList<T> copy(list);
+
+ QVERIFY(copy.isDetached() || copy.isSharedWith(QList<T>()));
+ QCOMPARE(copy.size(), size);
+ QCOMPARE(copy, list);
+ }
+
+ list.setSharable(true);
+
+ {
+ QList<T> copy(list);
+
+ QVERIFY(!copy.isDetached());
+ QVERIFY(copy.isSharedWith(list));
+ }
+
+ for (int i = 0; i < list.size(); ++i)
+ QCOMPARE(int(list[i]), i);
+
+ QCOMPARE(list.size(), size);
+}
+
+void tst_QList::setSharable1_data() const
+{
+ generateSetSharableData<int>();
+}
+
+void tst_QList::setSharable2_data() const
+{
+ generateSetSharableData<Complex>();
+}
+
+void tst_QList::setSharable1() const
+{
+ runSetSharableTest<int>();
+}
+
+void tst_QList::setSharable2() const
+{
+ runSetSharableTest<Complex>();
+}
+
QTEST_APPLESS_MAIN(tst_QList)
#include "tst_qlist.moc"