diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2023-10-31 14:05:29 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2024-02-16 14:20:50 +0100 |
commit | 73bf1c1a9bcc2615370d6a199420da0c6f380a44 (patch) | |
tree | 1149bd05cbd874ef008279e20883f9e27b8e6e8c /src/corelib/tools | |
parent | 277d77029d7fe8f46c6ee101869dcff389426cb1 (diff) |
QList: add uninitialized resizes
Creating a QList of a given size, or resizing it to a given size, will
always value-initialize its elements. This commit adds support for
uninitialized construction and resizes. The intended use case is using a
QList as storage-to-be-overwritten:
QList<int> list(size, Qt::Uninitialized);
fillWithData(list.data(), list.size);
How do we define "uninitialized":
1) if T is constructible using Qt::Uninitialized, use that;
2) otherwise, default-construct T.
In detail:
1) covers (Qt-ish) datatypes that have a default constructor that
initializes them, but also a dedicated constructor that doesn't
initialize (e.g. QPoint, QQuaternion, ...).
2) covers everything else. Default initialization of scalars and
trivially constructible datatypes will leave them uninitialized.
A type which isn't trivially constructible will still get its default
constructor called (and possibly actually gets initialized); we can't
really do better than that, as we still have to construct objects and
start their lifetimes.
[ChangeLog][QtCore][QList] Added support for uninitialized construction
and resizing.
Change-Id: I32c285c7dddbf7e01475943f24e14e824bb13090
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qarraydataops.h | 19 | ||||
-rw-r--r-- | src/corelib/tools/qlist.h | 14 | ||||
-rw-r--r-- | src/corelib/tools/qlist.qdoc | 36 |
3 files changed, 69 insertions, 0 deletions
diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index 78b0107655..c3e9821e81 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -7,6 +7,7 @@ #include <QtCore/qarraydata.h> #include <QtCore/qcontainertools_impl.h> +#include <QtCore/qnamespace.h> #include <memory> #include <new> @@ -960,6 +961,24 @@ public: // b might be updated so use [b, n) this->copyAppend(b, b + n); } + + void appendUninitialized(qsizetype newSize) + { + Q_ASSERT(this->isMutable()); + Q_ASSERT(!this->isShared()); + Q_ASSERT(newSize > this->size); + Q_ASSERT(newSize - this->size <= this->freeSpaceAtEnd()); + + T *const b = this->begin(); + do { + auto ptr = b + this->size; + + if constexpr (std::is_constructible_v<T, Qt::Initialization>) + new (ptr) T(Qt::Uninitialized); + else + new (ptr) T; // not T() -- default-construct + } while (++this->size != newSize); + } }; } // namespace QtPrivate diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index a0f29aadf6..684922cf08 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -10,6 +10,7 @@ #include <QtCore/qhashfunctions.h> #include <QtCore/qiterator.h> #include <QtCore/qcontainertools_impl.h> +#include <QtCore/qnamespace.h> #include <functional> #include <limits> @@ -324,6 +325,13 @@ public: inline explicit QList(const String &str) { append(str); } + QList(qsizetype size, Qt::Initialization) + : d(size) + { + if (size) + d->appendUninitialized(size); + } + // compiler-generated special member functions are fine! void swap(QList &other) noexcept { d.swap(other.d); } @@ -404,6 +412,12 @@ public: if (size > this->size()) d->copyAppend(size - this->size(), c); } + void resizeForOverwrite(qsizetype size) + { + resize_internal(size); + if (size > this->size()) + d->appendUninitialized(size); + } inline qsizetype capacity() const { return qsizetype(d->constAllocatedCapacity()); } void reserve(qsizetype size); diff --git a/src/corelib/tools/qlist.qdoc b/src/corelib/tools/qlist.qdoc index 5596813505..bf0f52eb6b 100644 --- a/src/corelib/tools/qlist.qdoc +++ b/src/corelib/tools/qlist.qdoc @@ -247,6 +247,31 @@ \sa resize() */ +/*! \fn template <typename T> QList<T>::QList(qsizetype size, Qt::Initialization) + \since 6.8 + + Constructs a list with an initial size of \a size elements. + + QList will make an attempt at \b{not initializing} the elements. + +//! [qlist-uninitialized-strategy] + Specifically: + + \list + + \li if \c{T} has a constructor that accepts \c{Qt::Uninitialized}, + that constructor will be used to initialize the elements; + + \li otherwise, each element is default constructed. For + trivially constructible types (such as \c{int}, \c{float}, etc.) + this is equivalent to not initializing them. + + \endlist +//! [qlist-uninitialized-strategy] + + \sa resizeForOverwrite() +*/ + /*! \fn template <typename T> QList<T>::QList(qsizetype size, parameter_type value) Constructs a list with an initial size of \a size elements. @@ -444,6 +469,17 @@ \sa size() */ +/*! \fn template <typename T> void QList<T>::resizeForOverwrite(qsizetype size) + \since 6.8 + + Sets the size of the list to \a size. If \a size is less than the + current size, elements are removed from the end. If \a size is + greater than the current size, elements are added to the end; QList + will make an attempt at \b{not initializing} these new elements. + + \include qlist.qdoc qlist-uninitialized-strategy +*/ + /*! \fn template <typename T> qsizetype QList<T>::capacity() const Returns the maximum number of items that can be stored in the |