From fb51a10ee0451274a430227566ae26efb2ac4474 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 25 Jun 2009 20:52:36 +0200 Subject: Add support for creating the object alongside the Data structure in one go. This avoids one memory allocation. Currently, we only support calling the default constructors. I will *NOT* implement argument passing for C++03. I will implement it with rvalue references for C++0x-capable compilers. --- src/corelib/tools/qsharedpointer_impl.h | 47 +++++++++++ tests/auto/qsharedpointer/tst_qsharedpointer.cpp | 102 ++++++++++++++++++++++- 2 files changed, 147 insertions(+), 2 deletions(-) diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index df31fec..cb78f29 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -48,6 +48,7 @@ #pragma qt_sync_stop_processing #endif +#include #include #include // for qobject_cast @@ -190,6 +191,34 @@ namespace QtSharedPointer { }; template + struct ExternalRefCountWithContiguousData: public ExternalRefCountData + { +#ifdef Q_DECL_ALIGN +# ifdef Q_ALIGNOF +# define QSP_ALIGNOF(T) Q_ALIGNOF(T) +# else +# define QSP_ALIGNOF(T) (sizeof(T) >= 16 ? 16 : sizeof(T) >= 8 ? 8 : sizeof(T) >= 4 ? 4 : sizeof(T) >= 2 ? 2 : 1) +# endif + + char data[sizeof(T)] Q_DECL_ALIGN(QSP_ALIGNOF(T)); + inline T *pointer() { return reinterpret_cast(data); } + +# undef QSP_ALIGNOF +#else + union { + char data[sizeof(T) + 16]; + double dummy1; +# ifndef Q_OS_DARWIN + long double dummy2; +# endif + }; + inline T *pointer() { return reinterpret_cast(data + 16 - (quintptr(data) & 0xf)); } +#endif + + inline bool destroy() { this->pointer()->~T(); return true; } + }; + + template class ExternalRefCount: public Basic { typedef ExternalRefCountData Data; @@ -220,6 +249,16 @@ namespace QtSharedPointer { d = new ExternalRefCountWithSpecializedDeleter(ptr, deleter); } + inline void internalCreate() + { + ExternalRefCountWithContiguousData *dd = new ExternalRefCountWithContiguousData; + T *ptr = dd->pointer(); + new (ptr) T(); // create + + Basic::internalConstruct(ptr); + d = dd; + } + inline ExternalRefCount() : d(0) { } inline ~ExternalRefCount() { if (d && !deref()) delete d; } inline ExternalRefCount(const ExternalRefCount &other) : Basic(other), d(other.d) @@ -347,6 +386,14 @@ public: inline void clear() { *this = QSharedPointer(); } QWeakPointer toWeakRef() const; + +public: + static QSharedPointer create() + { + QSharedPointer result; + result.internalCreate(); + return result; + } }; template diff --git a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp index 57ebdce..d6321c7 100644 --- a/tests/auto/qsharedpointer/tst_qsharedpointer.cpp +++ b/tests/auto/qsharedpointer/tst_qsharedpointer.cpp @@ -65,8 +65,9 @@ private slots: void dynamicCastVirtualBase(); void dynamicCastFailure(); #endif - void customDeleter(); void constCorrectness(); + void customDeleter(); + void creating(); void validConstructs(); void invalidConstructs_data(); void invalidConstructs(); @@ -104,6 +105,8 @@ public: { delete this; } + + virtual int classLevel() { return 1; } }; int Data::generationCounter = 0; int Data::destructorCounter = 0; @@ -311,6 +314,8 @@ public: { delete this; } + + virtual int classLevel() { return 2; } }; int DerivedData::derivedDestructorCounter = 0; @@ -318,15 +323,23 @@ class Stuffing { public: char buffer[16]; + Stuffing() { for (uint i = 0; i < sizeof buffer; ++i) buffer[i] = 16 - i; } virtual ~Stuffing() { } }; class DiffPtrDerivedData: public Stuffing, public Data { +public: + virtual int classLevel() { return 3; } }; class VirtualDerived: virtual public Data { +public: + int moreData; + + VirtualDerived() : moreData(0xc0ffee) { } + virtual int classLevel() { return 4; } }; void tst_QSharedPointer::downCast() @@ -972,6 +985,82 @@ void tst_QSharedPointer::customDeleter() QCOMPARE(derivedDataDeleter.callCount, 1); } +void tst_QSharedPointer::creating() +{ + Data::generationCounter = Data::destructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QVERIFY(ptr.data()); + QCOMPARE(Data::generationCounter, 1); + QCOMPARE(ptr->generation, 1); + QCOMPARE(Data::destructorCounter, 0); + + QCOMPARE(ptr->classLevel(), 1); + + ptr.clear(); + QCOMPARE(Data::destructorCounter, 1); + } + + Data::generationCounter = Data::destructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QWeakPointer weakptr = ptr; + QtSharedPointer::ExternalRefCountData *d = ptr.d; + + ptr.clear(); + QVERIFY(ptr.isNull()); + QCOMPARE(Data::destructorCounter, 1); + + // valgrind will complain here if something happened to the pointer + QVERIFY(d->weakref == 1); + QVERIFY(d->strongref == 0); + } + + Data::generationCounter = Data::destructorCounter = 0; + DerivedData::derivedDestructorCounter = 0; + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 2); + QCOMPARE(ptr.staticCast()->moreData, 0); + ptr.clear(); + + QCOMPARE(Data::destructorCounter, 1); + QCOMPARE(DerivedData::derivedDestructorCounter, 1); + } + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 3); + QCOMPARE(ptr.staticCast()->buffer[7]+0, 16-7); + QCOMPARE(ptr.staticCast()->buffer[3]+0, 16-3); + QCOMPARE(ptr.staticCast()->buffer[0]+0, 16); + } + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->classLevel(), 4); + QCOMPARE(ptr->moreData, 0xc0ffee); + + QSharedPointer baseptr = ptr; + QCOMPARE(baseptr->classLevel(), 4); + } + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->metaObject(), &QObject::staticMetaObject); + + QPointer qptr = ptr.data(); + ptr.clear(); + + QVERIFY(qptr.isNull()); + } + + { + QSharedPointer ptr = QSharedPointer::create(); + QCOMPARE(ptr->metaObject(), &OtherObject::staticMetaObject); + } +} + void tst_QSharedPointer::validConstructs() { { @@ -1021,6 +1110,9 @@ void tst_QSharedPointer::invalidConstructs_data() QTest::newRow("forward-declaration") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer ptr;"; + QTest::newRow("creating-forward-declaration") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer::create();"; // upcast without cast operator: QTest::newRow("upcast1") @@ -1053,10 +1145,16 @@ void tst_QSharedPointer::invalidConstructs_data() << "QSharedPointer baseptr = QSharedPointer(new Data);\n" "qSharedPointerDynamicCast(baseptr);"; #endif - QTest::newRow("const-dropping-object-cast") + QTest::newRow("const-dropping-object-cast1") << &QTest::QExternalTest::tryCompileFail << "QSharedPointer baseptr = QSharedPointer(new QObject);\n" "qSharedPointerObjectCast(baseptr);"; +#ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION + QTest::newRow("const-dropping-object-cast2") + << &QTest::QExternalTest::tryCompileFail + << "QSharedPointer baseptr = QSharedPointer(new QObject);\n" + "qobject_cast(baseptr);"; +#endif // arithmethics through automatic cast operators QTest::newRow("arithmethic1") -- cgit v0.12