Base QList::setSharable on RefCount::setSharable
Change-Id: I2acccdf9ee595a0eee33c9f7ddded9cc121412c1 Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
parent
362bde8e8e
commit
7e4f329934
@ -59,7 +59,7 @@ QT_BEGIN_NAMESPACE
|
||||
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)
|
||||
{
|
||||
@ -88,7 +88,6 @@ QListData::Data *QListData::detach_grow(int *idx, int num)
|
||||
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,
|
||||
@ -130,7 +129,6 @@ QListData::Data *QListData::detach(int alloc)
|
||||
Q_CHECK_PTR(t);
|
||||
|
||||
t->ref.initializeOwned();
|
||||
t->sharable = true;
|
||||
t->alloc = alloc;
|
||||
if (!alloc) {
|
||||
t->begin = 0;
|
||||
|
@ -71,7 +71,6 @@ struct Q_CORE_EXPORT QListData {
|
||||
struct Data {
|
||||
QtPrivate::RefCount ref;
|
||||
int alloc, begin, end;
|
||||
uint sharable : 1;
|
||||
void *array[1];
|
||||
};
|
||||
enum { DataHeaderSize = sizeof(Data) - sizeof(void *) };
|
||||
@ -114,7 +113,7 @@ class QList
|
||||
|
||||
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
|
||||
@ -142,7 +141,15 @@ public:
|
||||
}
|
||||
|
||||
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(); }
|
||||
@ -702,6 +709,28 @@ Q_OUTOFLINE_TEMPLATE void QList<T>::detach_helper()
|
||||
detach_helper(d->alloc);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -54,6 +54,9 @@ class tst_QList : public QObject
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void init();
|
||||
void cleanup();
|
||||
|
||||
void length() const;
|
||||
void lengthSignature() const;
|
||||
void append() const;
|
||||
@ -90,8 +93,100 @@ private slots:
|
||||
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. */
|
||||
@ -696,5 +791,82 @@ void tst_QList::const_shared_null() const
|
||||
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"
|
||||
|
Loading…
Reference in New Issue
Block a user