summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2020-08-25 11:58:09 +0200
committerUlf Hermann <ulf.hermann@qt.io>2020-09-01 13:35:39 +0200
commit4fbb2f66d6144953837361e808845edb181b124e (patch)
tree86d2c9222560c8e3c547277e60553afe8ed43356 /src
parent83ad54c1241efa359355f531dabb4de5be33aa32 (diff)
Add a QMetaSequence interface
This is in line with QMetaType and will be used to implement a mutable QSequentialIterable. Later on, a QMetaAssociation will be added as well, to implement a mutable QAssociativeIterable. The code here represents the minimal set of functionality needed to have a practical sequential container. The functionality is not completely orthogonal. In particular, the index based operations could be implemented in terms of iterator-based operations. Task-number: QTBUG-81716 Change-Id: Ibd41eb7db248a774673c701549d9a03cbf2e48b6 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/.prev_CMakeLists.txt2
-rw-r--r--src/corelib/CMakeLists.txt2
-rw-r--r--src/corelib/global/global.pri1
-rw-r--r--src/corelib/global/qcontainerinfo.h150
-rw-r--r--src/corelib/kernel/kernel.pri2
-rw-r--r--src/corelib/kernel/qmetacontainer.cpp697
-rw-r--r--src/corelib/kernel/qmetacontainer.h594
-rw-r--r--src/tools/bootstrap/.prev_CMakeLists.txt1
-rw-r--r--src/tools/bootstrap/CMakeLists.txt1
-rw-r--r--src/tools/bootstrap/bootstrap.pro1
10 files changed, 1451 insertions, 0 deletions
diff --git a/src/corelib/.prev_CMakeLists.txt b/src/corelib/.prev_CMakeLists.txt
index 747a0d75df..91e73b6c5d 100644
--- a/src/corelib/.prev_CMakeLists.txt
+++ b/src/corelib/.prev_CMakeLists.txt
@@ -11,6 +11,7 @@ qt_add_module(Core
SOURCES
global/archdetect.cpp
global/qcompilerdetection.h
+ global/qcontainerinfo.h
global/qendian.cpp global/qendian.h global/qendian_p.h
global/qflags.h
global/qfloat16.cpp global/qfloat16.h
@@ -80,6 +81,7 @@ qt_add_module(Core
kernel/qeventloop.cpp kernel/qeventloop.h
kernel/qfunctions_p.h
kernel/qmath.cpp kernel/qmath.h
+ kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h
kernel/qmetaobject_moc_p.h
kernel/qmetaobjectbuilder.cpp kernel/qmetaobjectbuilder_p.h
diff --git a/src/corelib/CMakeLists.txt b/src/corelib/CMakeLists.txt
index 8181250692..04021c8d29 100644
--- a/src/corelib/CMakeLists.txt
+++ b/src/corelib/CMakeLists.txt
@@ -33,6 +33,7 @@ qt_add_module(Core
SOURCES
global/archdetect.cpp
global/qcompilerdetection.h
+ global/qcontainerinfo.h
global/qendian.cpp global/qendian.h global/qendian_p.h
global/qflags.h
global/qfloat16.cpp global/qfloat16.h
@@ -103,6 +104,7 @@ qt_add_module(Core
kernel/qeventloop.cpp kernel/qeventloop.h
kernel/qfunctions_p.h
kernel/qmath.cpp kernel/qmath.h
+ kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h
kernel/qmetaobject_moc_p.h
kernel/qmetaobjectbuilder.cpp kernel/qmetaobjectbuilder_p.h
diff --git a/src/corelib/global/global.pri b/src/corelib/global/global.pri
index 6ba39d41bd..e799e13e4c 100644
--- a/src/corelib/global/global.pri
+++ b/src/corelib/global/global.pri
@@ -6,6 +6,7 @@ HEADERS += \
global/qoperatingsystemversion_p.h \
global/qsystemdetection.h \
global/qcompilerdetection.h \
+ global/qcontainerinfo.h \
global/qprocessordetection.h \
global/qmemory_p.h \
global/qnamespace.h \
diff --git a/src/corelib/global/qcontainerinfo.h b/src/corelib/global/qcontainerinfo.h
new file mode 100644
index 0000000000..ad3ef301e4
--- /dev/null
+++ b/src/corelib/global/qcontainerinfo.h
@@ -0,0 +1,150 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCONTAINERINFO_H
+#define QCONTAINERINFO_H
+
+#include <QtCore/qglobal.h>
+#include <type_traits>
+
+QT_BEGIN_NAMESPACE
+
+namespace QContainerTraits
+{
+
+template<typename C>
+using value_type = typename C::value_type;
+
+template<typename C>
+using iterator = typename C::iterator;
+
+template<typename C>
+using const_iterator = typename C::const_iterator;
+
+// Some versions of Apple clang warn about the constexpr variables below being unused.
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wunused-const-variable")
+
+template<typename C, typename = void>
+constexpr bool has_size_v = false;
+template<typename C>
+constexpr bool has_size_v<C, std::void_t<decltype(C().size())>> = true;
+
+template<typename C, typename = void>
+constexpr bool has_clear_v = false;
+template<typename C>
+constexpr bool has_clear_v<C, std::void_t<decltype(C().clear())>> = true;
+
+template<typename, typename = void>
+constexpr bool has_at_v = false;
+template<typename C>
+constexpr bool has_at_v<C, std::void_t<decltype(C().at(0))>> = true;
+
+template<typename, typename = void>
+constexpr bool can_get_at_index_v = false;
+template<typename C>
+constexpr bool can_get_at_index_v<C, std::void_t<value_type<C>(decltype(C()[0]))>> = true;
+
+template<typename, typename = void>
+constexpr bool can_set_at_index_v = false;
+template<typename C>
+constexpr bool can_set_at_index_v<C, std::void_t<decltype(C()[0] = value_type<C>())>> = true;
+
+template<typename, typename = void>
+constexpr bool has_push_front_v = false;
+template<typename C>
+constexpr bool has_push_front_v<C, std::void_t<decltype(C().push_front(value_type<C>()))>> = true;
+
+template<typename, typename = void>
+constexpr bool has_push_back_v = false;
+template<typename C>
+constexpr bool has_push_back_v<C, std::void_t<decltype(C().push_back(value_type<C>()))>> = true;
+
+template<typename, typename = void>
+constexpr bool has_insert_v = false;
+template<typename C>
+constexpr bool has_insert_v<C, std::void_t<decltype(C().insert(value_type<C>()))>> = true;
+
+template<typename, typename = void>
+constexpr bool has_pop_front_v = false;
+template<typename C>
+constexpr bool has_pop_front_v<C, std::void_t<decltype(C().pop_front())>> = true;
+
+template<typename, typename = void>
+constexpr bool has_pop_back_v = false;
+template<typename C>
+constexpr bool has_pop_back_v<C, std::void_t<decltype(C().pop_back())>> = true;
+
+template<typename, typename = void>
+constexpr bool has_iterator_v = false;
+template<typename C>
+constexpr bool has_iterator_v<C, std::void_t<iterator<C>>> = true;
+
+template<typename, typename = void>
+constexpr bool has_const_iterator_v = false;
+template<typename C>
+constexpr bool has_const_iterator_v<C, std::void_t<const_iterator<C>>> = true;
+
+template<typename, typename = void>
+constexpr bool can_get_at_iterator_v = false;
+template<typename C>
+constexpr bool can_get_at_iterator_v<C, std::void_t<value_type<C>(decltype(*C().begin()))>> = true;
+
+template<typename, typename = void>
+constexpr bool can_set_at_iterator_v = false;
+template<typename C>
+constexpr bool can_set_at_iterator_v<C, std::void_t<decltype(*C().begin() = value_type<C>())>> = true;
+
+template<typename, typename = void>
+constexpr bool can_insert_at_iterator_v = false;
+template<typename C>
+constexpr bool can_insert_at_iterator_v<C, std::void_t<decltype(C().insert(C().begin(), value_type<C>()))>> = true;
+
+template<typename, typename = void>
+constexpr bool can_erase_at_iterator_v = false;
+template<typename C>
+constexpr bool can_erase_at_iterator_v<C, std::void_t<decltype(C().erase(C().begin()))>> = true;
+
+QT_WARNING_POP
+
+}
+
+QT_END_NAMESPACE
+
+#endif // QCONTAINERINFO_H
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 036230e11f..420f0222e4 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -12,6 +12,7 @@ HEADERS += \
kernel/qcorecmdlineargs_p.h \
kernel/qcoreapplication.h \
kernel/qcoreevent.h \
+ kernel/qmetacontainer.h \
kernel/qmetaobject.h \
kernel/qmetatype.h \
kernel/qmimedata.h \
@@ -56,6 +57,7 @@ SOURCES += \
kernel/qeventloop.cpp \
kernel/qcoreapplication.cpp \
kernel/qcoreevent.cpp \
+ kernel/qmetacontainer.cpp \
kernel/qmetaobject.cpp \
kernel/qmetatype.cpp \
kernel/qmetaobjectbuilder.cpp \
diff --git a/src/corelib/kernel/qmetacontainer.cpp b/src/corelib/kernel/qmetacontainer.cpp
new file mode 100644
index 0000000000..cfe837bef8
--- /dev/null
+++ b/src/corelib/kernel/qmetacontainer.cpp
@@ -0,0 +1,697 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qmetacontainer.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QMetaSequence
+ \inmodule QtCore
+ \since 6.0
+ \brief The QMetaSequence class allows type erased access to sequential containers.
+
+ \ingroup objectmodel
+
+ The class provides a number of primitive container operations, using void*
+ as operands. This way, you can manipulate a generic container retrieved from
+ a Variant without knowing its type.
+
+ The void* arguments to the various methods are typically created by using
+ a \l QVariant of the respective container or element type, and calling
+ its \l QVariant::data() or \l QVariant::constData() methods. However, you
+ can also pass plain pointers to objects of the container or element type.
+
+ Iterator invalidation follows the rules given by the underlying containers
+ and is not expressed in the API. Therefore, for a truly generic container,
+ any iterators should be considered invalid after any write operation.
+*/
+
+/*!
+ \fn template<typename C> QMetaSequence QMetaSequence::fromContainer()
+ \since 6.0
+
+ Returns the QMetaSequence corresponding to the type given as template parameter.
+*/
+
+/*!
+ Returns \c true if the underlying container provides at least a forward
+ iterator as defined by std::forward_iterator_tag, otherwise returns
+ \c false. Bi-directional iterators and random access iterators are
+ specializations of forward iterators. This method will also return
+ \c true if the container provides one of those.
+
+ QMetaSequence assumes that const and non-const iterators for the same
+ container have the same iterator traits.
+ */
+bool QMetaSequence::hasForwardIterator() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->iteratorCapabilities & QtMetaContainerPrivate::ForwardCapability;
+}
+
+/*!
+ Returns \c true if the underlying container provides a bi-directional
+ iterator or a random access iterator as defined by
+ std::bidirectional_iterator_tag and std::random_access_iterator_tag,
+ respectively. Otherwise returns \c false.
+
+ QMetaSequence assumes that const and non-const iterators for the same
+ container have the same iterator traits.
+ */
+bool QMetaSequence::hasBidirectionalIterator() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->iteratorCapabilities & QtMetaContainerPrivate::BiDirectionalCapability;
+}
+
+/*!
+ Returns \c true if the underlying container provides a random access
+ iterator as defined by std::random_access_iterator_tag, otherwise returns
+ \c false.
+
+ QMetaSequence assumes that const and non-const iterators for the same
+ container have the same iterator traits.
+ */
+bool QMetaSequence::hasRandomAccessIterator() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->iteratorCapabilities & QtMetaContainerPrivate::RandomAccessCapability;
+}
+
+/*!
+ Returns the meta type for values stored in the container.
+ */
+QMetaType QMetaSequence::valueMetaType() const
+{
+ return d_ptr ? d_ptr->valueMetaType : QMetaType();
+}
+
+/*!
+ Returns \c true if the underlying container is ordered, otherwise returns
+ \c false. A container is considered ordered if elements added to it are
+ placed in a defined location. Inserting into or adding to an ordered
+ container will always succeed. Inserting into or adding to an unordered
+ container may not succeed, for example if the container is a QSet that
+ already contains the value being inserted.
+
+ \sa addElement(), insertElementAtIterator(), addsAndRemovesElementsAtBegin(),
+ addsAndRemovesElementsAtEnd()
+ */
+bool QMetaSequence::isOrdered() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->addRemovePosition != QtMetaContainerPrivate::QMetaSequenceInterface::Random;
+}
+
+/*!
+ Returns \c true if elements added using \l addElement() are placed at the
+ beginning of the container, otherwise returns \c false. Likewise
+ \l removeElement() removes an element from the beginning of the container
+ if this method returns \c true.
+
+ \sa addElement(), removeElement(), addsAndRemovesElementsAtEnd()
+ */
+bool QMetaSequence::addsAndRemovesElementsAtBegin() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->addRemovePosition == QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin;
+}
+
+/*!
+ Returns \c true if elements added using \l addElement() are placed at the
+ end of the container, otherwise returns \c false. Likewise
+ \l removeElement() removes an element from the end of the container
+ if this method returns \c true.
+
+ \sa addElement(), removeElement(), addsAndRemovesElementsAtBegin()
+ */
+bool QMetaSequence::addsAndRemovesElementsAtEnd() const
+{
+ if (!d_ptr)
+ return false;
+ return d_ptr->addRemovePosition == QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd;
+}
+
+/*!
+ Returns \c true if the container can be queried for its size, \c false
+ otherwise.
+
+ \sa size()
+ */
+bool QMetaSequence::hasSize() const
+{
+ return d_ptr && d_ptr->sizeFn;
+}
+
+/*!
+ Returns the number of elements in the given \a container if it can be
+ queried for its size. Otherwise returns \c -1.
+
+ \sa hasSize()
+ */
+qsizetype QMetaSequence::size(const void *container) const
+{
+ return hasSize() ? d_ptr->sizeFn(container) : -1;
+}
+
+/*!
+ Returns \c true if the container can be cleared, \c false otherwise.
+
+ \sa clear()
+ */
+bool QMetaSequence::canClear() const
+{
+ return d_ptr && d_ptr->clearFn;
+}
+
+/*!
+ Clears the given \a container if it can be cleared.
+
+ \sa canClear()
+ */
+void QMetaSequence::clear(void *container) const
+{
+ if (canClear())
+ d_ptr->clearFn(container);
+}
+
+/*!
+ Returns \c true if elements can be retrieved from the container by index,
+ otherwise \c false.
+
+ \sa elementAtIndex()
+ */
+bool QMetaSequence::canGetElementAtIndex() const
+{
+ return d_ptr && d_ptr->elementAtIndexFn;
+}
+
+/*!
+ Retrieves the element at \a index in the \a container and places it in the
+ memory location pointed to by \a result, if that is possible.
+
+ \sa canGetElementAtIndex()
+ */
+void QMetaSequence::elementAtIndex(const void *container, qsizetype index, void *result) const
+{
+ if (canGetElementAtIndex())
+ d_ptr->elementAtIndexFn(container, index, result);
+}
+
+/*!
+ Returns \c true if an element can be written to the container by index,
+ otherwise \c false.
+
+ \sa setElementAtIndex()
+*/
+bool QMetaSequence::canSetElementAtIndex() const
+{
+ return d_ptr && d_ptr->setElementAtIndexFn;
+}
+
+/*!
+ Overwrites the element at \a index in the \a container using the \a element
+ passed as parameter if that is possible.
+
+ \sa canSetElementAtIndex()
+ */
+void QMetaSequence::setElementAtIndex(void *container, qsizetype index, const void *element) const
+{
+ if (canSetElementAtIndex())
+ d_ptr->setElementAtIndexFn(container, index, element);
+}
+
+/*!
+ Returns \c true if elements can be added to the container, \c false
+ otherwise.
+
+ \sa addElement(), isOrdered()
+ */
+bool QMetaSequence::canAddElement() const
+{
+ return d_ptr && d_ptr->addElementFn;
+}
+
+/*!
+ Adds \a element to the \a container if possible. If \l canAddElement()
+ returns \c false, the \a element is not added. Else, if
+ \l addsAndRemovesElementsAtBegin() returns \c true, the \a element is added
+ to the beginning of the \a container. Else, if
+ \l addsAndRemovesElementsAtEnd() returns \c true, the \a element is added to
+ the end of the container. Else, the element is added in an unspecified
+ place or not at all. The latter is the case for adding elements to an
+ unordered container, for example \l QSet.
+
+ \sa canAddElement(), addsAndRemovesElementsAtBegin(),
+ addsAndRemovesElementsAtEnd(), isOrdered(), removeElement()
+ */
+void QMetaSequence::addElement(void *container, const void *element) const
+{
+ if (canAddElement())
+ d_ptr->addElementFn(container, element);
+}
+
+/*!
+ Returns \c true if elements can be removed from the container, \c false
+ otherwise.
+
+ \sa removeElement(), isOrdered()
+ */
+bool QMetaSequence::canRemoveElement() const
+{
+ return d_ptr && d_ptr->removeElementFn;
+}
+
+/*!
+ Removes an element from the \a container if possible. If
+ \l canRemoveElement() returns \c false, no element is removed. Else, if
+ \l addsAndRemovesElementsAtBegin() returns \c true, the first element in
+ the \a container is removed. Else, if \l addsAndRemovesElementsAtEnd()
+ returns \c true, the last element in the \a container is removed. Else,
+ an unspecified element or nothing is removed.
+
+ \sa canRemoveElement(), addsAndRemovesElementsAtBegin(),
+ addsAndRemovesElementsAtEnd(), isOrdered(), addElement()
+ */
+void QMetaSequence::removeElement(void *container) const
+{
+ if (canRemoveElement())
+ d_ptr->removeElementFn(container);
+}
+
+/*!
+ Returns \c true if the underlying container offers a non-const iterator,
+ \c false otherwise.
+
+ \sa begin(), end(), destroyIterator(), compareIterator(), diffIterator(),
+ advanceIterator(), copyIterator()
+ */
+bool QMetaSequence::hasIterator() const
+{
+ if (!d_ptr || !d_ptr->createIteratorFn)
+ return false;
+ Q_ASSERT(d_ptr->destroyIteratorFn);
+ Q_ASSERT(d_ptr->compareIteratorFn);
+ Q_ASSERT(d_ptr->copyIteratorFn);
+ Q_ASSERT(d_ptr->advanceIteratorFn);
+ Q_ASSERT(d_ptr->diffIteratorFn);
+ return true;
+}
+
+/*!
+ Creates and returns a non-const iterator pointing to the beginning of
+ \a container. The iterator is allocated on the heap using new. It has to be
+ destroyed using \l destroyIterator eventually, to reclaim the memory.
+
+ Returns \c nullptr if the container doesn't offer any non-const iterators.
+
+ \sa end(), constBegin(), constEnd(), destroyIterator()
+ */
+void *QMetaSequence::begin(void *container) const
+{
+ return hasIterator()
+ ? d_ptr->createIteratorFn(
+ container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin)
+ : nullptr;
+}
+
+/*!
+ Creates and returns a non-const iterator pointing to the end of
+ \a container. The iterator is allocated on the heap using new. It has to be
+ destroyed using \l destroyIterator eventually, to reclaim the memory.
+
+ Returns \c nullptr if the container doesn't offer any non-const iterators.
+
+ \sa hasIterator(), end(), constBegin(), constEnd(), destroyIterator()
+ */
+void *QMetaSequence::end(void *container) const
+{
+ return hasIterator()
+ ? d_ptr->createIteratorFn(
+ container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd)
+ : nullptr;
+}
+
+/*!
+ Destroys a non-const \a iterator previously created using \l begin() or
+ \l end().
+
+ \sa begin(), end(), destroyConstIterator()
+ */
+void QMetaSequence::destroyIterator(const void *iterator) const
+{
+ if (hasIterator())
+ d_ptr->destroyIteratorFn(iterator);
+}
+
+/*!
+ Returns \c true if the non-const iterators \a i and \a j point to the same
+ element in the container they are iterating over, otherwise returns \c
+ false.
+
+ \sa begin(), end()
+ */
+bool QMetaSequence::compareIterator(const void *i, const void *j) const
+{
+ return hasIterator() ? d_ptr->compareIteratorFn(i, j) : false;
+}
+
+/*!
+ Copies the non-const iterator \a source into the non-const iterator
+ \a target. Afterwards compareIterator(target, source) returns \c true.
+
+ \sa begin(), end()
+ */
+void QMetaSequence::copyIterator(void *target, const void *source) const
+{
+ if (hasIterator())
+ d_ptr->copyIteratorFn(target, source);
+}
+
+/*!
+ Advances the non-const \a iterator by \a step steps. If \a steps is negative
+ the \a iterator is moved backwards, towards the beginning of the container.
+ The behavior is unspecified for negative values of \a step if
+ \l hasBidirectionalIterator() returns false.
+
+ \sa begin(), end()
+ */
+void QMetaSequence::advanceIterator(void *iterator, qsizetype step) const
+{
+ if (hasIterator())
+ d_ptr->advanceIteratorFn(iterator, step);
+}
+
+/*!
+ Returns the distance between the non-const iterators \a i and \a j, the
+ equivalent of \a i \c - \a j. If \a j is closer to the end of the container
+ than \a i, the returned value is negative. The behavior is unspecified in
+ this case if \l hasBidirectionalIterator() returns false.
+
+ \sa begin(), end()
+ */
+qsizetype QMetaSequence::diffIterator(const void *i, const void *j) const
+{
+ return hasIterator() ? d_ptr->diffIteratorFn(i, j) : 0;
+}
+
+/*!
+ Returns \c true if the underlying container can retrieve the value pointed
+ to by a non-const iterator, \c false otherwise.
+
+ \sa hasIterator(), elementAtIterator()
+ */
+bool QMetaSequence::canGetElementAtIterator() const
+{
+ return d_ptr && d_ptr->elementAtIteratorFn;
+}
+
+/*!
+ Retrieves the element pointed to by the non-const \a iterator and stores it
+ in the memory location pointed to by \a result, if possible.
+
+ \sa canGetElementAtIterator(), begin(), end()
+ */
+void QMetaSequence::elementAtIterator(const void *iterator, void *result) const
+{
+ if (canGetElementAtIterator())
+ d_ptr->elementAtIteratorFn(iterator, result);
+}
+
+/*!
+ Returns \c true if the underlying container can write to the value pointed
+ to by a non-const iterator, \c false otherwise.
+
+ \sa hasIterator(), setElementAtIterator()
+ */
+bool QMetaSequence::canSetElementAtIterator() const
+{
+ return d_ptr && d_ptr->setElementAtIteratorFn;
+}
+
+/*!
+ Writes \a element to the value pointed to by the non-const \a iterator, if
+ possible.
+
+ \sa canSetElementAtIterator(), begin(), end()
+ */
+void QMetaSequence::setElementAtIterator(const void *iterator, const void *element) const
+{
+ if (canSetElementAtIterator())
+ d_ptr->setElementAtIteratorFn(iterator, element);
+}
+
+/*!
+ Returns \c true if the underlying container can insert a new element, taking
+ the location pointed to by a non-const iterator into account.
+
+ \sa hasIterator(), insertElementAtIterator()
+ */
+bool QMetaSequence::canInsertElementAtIterator() const
+{
+ return d_ptr && d_ptr->insertElementAtIteratorFn;
+}
+
+/*!
+ Inserts \a element into the \a container, if possible, taking the non-const
+ \a iterator into account. If \l canInsertElementAtIterator() returns
+ \c false, the \a element is not inserted. Else if \l isOrdered() returns
+ \c true, the element is inserted before the element pointed to by
+ \a iterator. Else, the \a element is inserted at an unspecified place or not
+ at all. In the latter case, the \a iterator is taken as a hint. If it points
+ to the correct place for the \a element, the operation may be faster than a
+ \l addElement() without iterator.
+
+ \sa canInsertElementAtIterator(), isOrdered(), begin(), end()
+ */
+void QMetaSequence::insertElementAtIterator(void *container, const void *iterator,
+ const void *element) const
+{
+ if (canInsertElementAtIterator())
+ d_ptr->insertElementAtIteratorFn(container, iterator, element);
+}
+
+/*!
+ Returns \c true if the element pointed to by a non-const iterator can be
+ erased, \c false otherwise.
+
+ \sa hasIterator(), eraseElementAtIterator()
+ */
+bool QMetaSequence::canEraseElementAtIterator() const
+{
+ return d_ptr && d_ptr->eraseElementAtIteratorFn;
+}
+
+/*!
+ Erases the element pointed to by the non-const \a iterator from the
+ \a container, if possible.
+
+ \sa canEraseElementAtIterator(), begin(), end()
+ */
+void QMetaSequence::eraseElementAtIterator(void *container, const void *iterator) const
+{
+ if (canEraseElementAtIterator())
+ d_ptr->eraseElementAtIteratorFn(container, iterator);
+}
+
+/*!
+ Returns \c true if the underlying container offers a const iterator,
+ \c false otherwise.
+
+ \sa constBegin(), constEnd(), destroyConstIterator(),
+ compareConstIterator(), diffConstIterator(), advanceConstIterator(),
+ copyConstIterator()
+ */
+bool QMetaSequence::hasConstIterator() const
+{
+ if (!d_ptr || !d_ptr->createConstIteratorFn)
+ return false;
+ Q_ASSERT(d_ptr->destroyConstIteratorFn);
+ Q_ASSERT(d_ptr->compareConstIteratorFn);
+ Q_ASSERT(d_ptr->copyConstIteratorFn);
+ Q_ASSERT(d_ptr->advanceConstIteratorFn);
+ Q_ASSERT(d_ptr->diffConstIteratorFn);
+ return true;
+}
+
+/*!
+ Creates and returns a const iterator pointing to the beginning of
+ \a container. The iterator is allocated on the heap using new. It has to be
+ destroyed using \l destroyConstIterator eventually, to reclaim the memory.
+
+ Returns \c nullptr if the container doesn't offer any const iterators.
+
+ \sa constEnd(), begin(), end(), destroyConstIterator()
+ */
+void *QMetaSequence::constBegin(const void *container) const
+{
+ return hasConstIterator()
+ ? d_ptr->createConstIteratorFn(
+ container, QtMetaContainerPrivate::QMetaSequenceInterface::AtBegin)
+ : nullptr;
+}
+
+/*!
+ Creates and returns a const iterator pointing to the end of
+ \a container. The iterator is allocated on the heap using new. It has to be
+ destroyed using \l destroyConstIterator eventually, to reclaim the memory.
+
+ Returns \c nullptr if the container doesn't offer any const iterators.
+
+ \sa constBegin(), begin(), end(), destroyConstIterator()
+ */
+void *QMetaSequence::constEnd(const void *container) const
+{
+ return hasConstIterator()
+ ? d_ptr->createConstIteratorFn(
+ container, QtMetaContainerPrivate::QMetaSequenceInterface::AtEnd)
+ : nullptr;
+}
+
+/*!
+ Destroys a const \a iterator previously created using \l constBegin() or
+ \l constEnd().
+
+ \sa constBegin(), constEnd(), destroyIterator()
+ */
+void QMetaSequence::destroyConstIterator(const void *iterator) const
+{
+ if (hasConstIterator())
+ d_ptr->destroyConstIteratorFn(iterator);
+}
+
+/*!
+ Returns \c true if the const iterators \a i and \a j point to the same
+ element in the container they are iterating over, otherwise returns \c
+ false.
+
+ \sa constBegin(), constEnd()
+ */
+bool QMetaSequence::compareConstIterator(const void *i, const void *j) const
+{
+ return hasConstIterator() ? d_ptr->compareConstIteratorFn(i, j) : false;
+}
+
+/*!
+ Copies the const iterator \a source into the const iterator
+ \a target. Afterwards compareConstIterator(target, source) returns \c true.
+
+ \sa constBegin(), constEnd()
+ */
+void QMetaSequence::copyConstIterator(void *target, const void *source) const
+{
+ if (hasConstIterator())
+ d_ptr->copyConstIteratorFn(target, source);
+}
+
+/*!
+ Advances the const \a iterator by \a step steps. If \a steps is negative
+ the \a iterator is moved backwards, towards the beginning of the container.
+ The behavior is unspecified for negative values of \a step if
+ \l hasBidirectionalIterator() returns false.
+
+ \sa constBegin(), constEnd()
+ */
+void QMetaSequence::advanceConstIterator(void *iterator, qsizetype step) const
+{
+ if (hasConstIterator())
+ d_ptr->advanceConstIteratorFn(iterator, step);
+}
+
+/*!
+ Returns the distance between the const iterators \a i and \a j, the
+ equivalent of \a i \c - \a j. If \a j is closer to the end of the container
+ than \a i, the returned value is negative. The behavior is unspecified in
+ this case if \l hasBidirectionalIterator() returns false.
+
+ \sa constBegin(), constEnd()
+ */
+qsizetype QMetaSequence::diffConstIterator(const void *i, const void *j) const
+{
+ return hasConstIterator() ? d_ptr->diffConstIteratorFn(i, j) : 0;
+}
+
+/*!
+ Returns \c true if the underlying container can retrieve the value pointed
+ to by a const iterator, \c false otherwise.
+
+ \sa hasConstIterator(), elementAtConstIterator()
+ */
+bool QMetaSequence::canGetElementAtConstIterator() const
+{
+ return d_ptr && d_ptr->elementAtConstIteratorFn;
+}
+
+/*!
+ Retrieves the element pointed to by the const \a iterator and stores it
+ in the memory location pointed to by \a result, if possible.
+
+ \sa canGetElementAtConstIterator(), constBegin(), constEnd()
+ */
+void QMetaSequence::elementAtConstIterator(const void *iterator, void *result) const
+{
+ if (canGetElementAtConstIterator())
+ d_ptr->elementAtConstIteratorFn(iterator, result);
+}
+
+/*!
+ \fn bool operator==(QMetaSequence a, QMetaSequence b)
+ \since 6.0
+ \relates QMetaSequence
+
+ Returns \c true if the QMetaSequence \a a represents the same container type
+ as the QMetaSequence \a b, otherwise returns \c false.
+*/
+
+/*!
+ \fn bool operator!=(QMetaSequence a, QMetaSequence b)
+ \since 6.0
+ \relates QMetaSequence
+
+ Returns \c true if the QMetaSequence \a a represents a different container
+ type than the QMetaSequence \a b, otherwise returns \c false.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qmetacontainer.h b/src/corelib/kernel/qmetacontainer.h
new file mode 100644
index 0000000000..c663d1ce24
--- /dev/null
+++ b/src/corelib/kernel/qmetacontainer.h
@@ -0,0 +1,594 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QMETACONTAINER_H
+#define QMETACONTAINER_H
+
+#include <QtCore/qcontainerinfo.h>
+#include <QtCore/qflags.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QtMetaContainerPrivate {
+
+enum IteratorCapability : quint8 {
+ ForwardCapability = 1 << 0,
+ BiDirectionalCapability = 1 << 1,
+ RandomAccessCapability = 1 << 2,
+};
+
+Q_DECLARE_FLAGS(IteratorCapabilities, IteratorCapability)
+Q_DECLARE_OPERATORS_FOR_FLAGS(IteratorCapabilities)
+
+class QMetaSequenceInterface
+{
+public:
+ enum Position : quint8 { AtBegin, AtEnd, Random };
+
+ ushort revision;
+ IteratorCapabilities iteratorCapabilities;
+ Position addRemovePosition;
+ QMetaType valueMetaType;
+
+ using SizeFn = qsizetype(*)(const void *);
+ SizeFn sizeFn;
+ using ClearFn = void(*)(void *);
+ ClearFn clearFn;
+
+ using ElementAtIndexFn = void(*)(const void *, qsizetype, void *);
+ ElementAtIndexFn elementAtIndexFn;
+ using SetElementAtIndexFn = void(*)(void *, qsizetype, const void *);
+ SetElementAtIndexFn setElementAtIndexFn;
+
+ using AddElementFn = void(*)(void *, const void *);
+ AddElementFn addElementFn;
+ using RemoveElementFn = void(*)(void *);
+ RemoveElementFn removeElementFn;
+
+ using CreateIteratorFn = void *(*)(void *, Position);
+ CreateIteratorFn createIteratorFn;
+ using DestroyIteratorFn = void(*)(const void *);
+ DestroyIteratorFn destroyIteratorFn;
+ using CompareIteratorFn = bool(*)(const void *, const void *);
+ CompareIteratorFn compareIteratorFn;
+ using CopyIteratorFn = void(*)(void *, const void *);
+ CopyIteratorFn copyIteratorFn;
+ using AdvanceIteratorFn = void(*)(void *, qsizetype);
+ AdvanceIteratorFn advanceIteratorFn;
+ using DiffIteratorFn = qsizetype(*)(const void *, const void *);
+ DiffIteratorFn diffIteratorFn;
+ using ElementAtIteratorFn = void(*)(const void *, void *);
+ ElementAtIteratorFn elementAtIteratorFn;
+ using SetElementAtIteratorFn = void(*)(const void *, const void *);
+ SetElementAtIteratorFn setElementAtIteratorFn;
+ using InsertElementAtIteratorFn = void(*)(void *, const void *, const void *);
+ InsertElementAtIteratorFn insertElementAtIteratorFn;
+ using EraseElementAtIteratorFn = void(*)(void *, const void *);
+ EraseElementAtIteratorFn eraseElementAtIteratorFn;
+
+ using CreateConstIteratorFn = void *(*)(const void *, Position);
+ CreateConstIteratorFn createConstIteratorFn;
+ DestroyIteratorFn destroyConstIteratorFn;
+ CompareIteratorFn compareConstIteratorFn;
+ CopyIteratorFn copyConstIteratorFn;
+ AdvanceIteratorFn advanceConstIteratorFn;
+ DiffIteratorFn diffConstIteratorFn;
+ ElementAtIteratorFn elementAtConstIteratorFn;
+};
+
+template<typename C>
+class QMetaSequenceForContainer
+{
+ template <typename Iterator>
+ static constexpr IteratorCapabilities capabilitiesForIterator()
+ {
+ using Tag = typename std::iterator_traits<Iterator>::iterator_category;
+ IteratorCapabilities caps {};
+ if constexpr (std::is_base_of_v<std::forward_iterator_tag, Tag>)
+ caps |= ForwardCapability;
+ if constexpr (std::is_base_of_v<std::bidirectional_iterator_tag, Tag>)
+ caps |= BiDirectionalCapability;
+ if constexpr (std::is_base_of_v<std::random_access_iterator_tag, Tag>)
+ caps |= RandomAccessCapability;
+ return caps;
+ }
+
+ static constexpr IteratorCapabilities getIteratorCapabilities()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>)
+ return capabilitiesForIterator<QContainerTraits::iterator<C>>();
+ else if constexpr (QContainerTraits::has_const_iterator_v<C>)
+ return capabilitiesForIterator<QContainerTraits::const_iterator<C>>();
+ else
+ return {};
+ }
+
+ static constexpr QMetaSequenceInterface::Position getAddRemovePosition()
+ {
+ if constexpr (QContainerTraits::has_push_back_v<C> && QContainerTraits::has_pop_back_v<C>)
+ return QMetaSequenceInterface::AtEnd;
+ if constexpr (QContainerTraits::has_push_front_v<C> && QContainerTraits::has_pop_front_v<C>)
+ return QMetaSequenceInterface::AtBegin;
+ return QMetaSequenceInterface::Random;
+ }
+
+ static constexpr QMetaType getValueMetaType()
+ {
+ return QMetaType::fromType<typename C::value_type>();
+ }
+
+ static constexpr QMetaSequenceInterface::SizeFn getSizeFn()
+ {
+ if constexpr (QContainerTraits::has_size_v<C>) {
+ return [](const void *c) -> qsizetype { return static_cast<const C *>(c)->size(); };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::ClearFn getClearFn()
+ {
+ if constexpr (QContainerTraits::has_clear_v<C>) {
+ return [](void *c) { return static_cast<C *>(c)->clear(); };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::ElementAtIndexFn getElementAtIndexFn()
+ {
+ if constexpr (QContainerTraits::has_at_v<C>) {
+ return [](const void *c, qsizetype i, void *r) {
+ *static_cast<QContainerTraits::value_type<C> *>(r)
+ = static_cast<const C *>(c)->at(i);
+ };
+ } else if constexpr (QContainerTraits::can_get_at_index_v<C>) {
+ return [](const void *c, qsizetype i, void *r) {
+ *static_cast<QContainerTraits::value_type<C> *>(r)
+ = (*static_cast<const C *>(c))[i];
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::SetElementAtIndexFn getSetElementAtIndexFn()
+ {
+ if constexpr (QContainerTraits::can_set_at_index_v<C>) {
+ return [](void *c, qsizetype i, const void *e) {
+ (*static_cast<C *>(c))[i]
+ = *static_cast<const QContainerTraits::value_type<C> *>(e);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::AddElementFn getAddElementFn()
+ {
+ if constexpr (QContainerTraits::has_push_back_v<C>) {
+ return [](void *c, const void *v) {
+ static_cast<C *>(c)->push_back(
+ *static_cast<const QContainerTraits::value_type<C> *>(v));
+ };
+ } else if constexpr (QContainerTraits::has_push_front_v<C>) {
+ return [](void *c, const void *v) {
+ static_cast<C *>(c)->push_front(
+ *static_cast<const QContainerTraits::value_type<C> *>(v));
+ };
+ } else if constexpr (QContainerTraits::has_insert_v<C>) {
+ return [](void *c, const void *v) {
+ static_cast<C *>(c)->insert(
+ *static_cast<const QContainerTraits::value_type<C> *>(v));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::RemoveElementFn getRemoveElementFn()
+ {
+ if constexpr (QContainerTraits::has_pop_back_v<C>) {
+ return [](void *c) { static_cast<C *>(c)->pop_back(); };
+ } else if constexpr (QContainerTraits::has_pop_front_v<C>) {
+ return [](void *c) { static_cast<C *>(c)->pop_front(); };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CreateIteratorFn getCreateIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](void *c, QMetaSequenceInterface::Position p) -> void* {
+ using Iterator = QContainerTraits::iterator<C>;
+ switch (p) {
+ case QMetaSequenceInterface::AtBegin:
+ case QMetaSequenceInterface::Random:
+ return new Iterator(static_cast<C *>(c)->begin());
+ break;
+ case QMetaSequenceInterface::AtEnd:
+ return new Iterator(static_cast<C *>(c)->end());
+ break;
+ }
+ return nullptr;
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::DestroyIteratorFn getDestroyIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](const void *i) {
+ using Iterator = QContainerTraits::iterator<C>;
+ delete static_cast<const Iterator *>(i);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CompareIteratorFn getCompareIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](const void *i, const void *j) {
+ using Iterator = QContainerTraits::iterator<C>;
+ return *static_cast<const Iterator *>(i) == *static_cast<const Iterator *>(j);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CopyIteratorFn getCopyIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](void *i, const void *j) {
+ using Iterator = QContainerTraits::iterator<C>;
+ *static_cast<Iterator *>(i) = *static_cast<const Iterator *>(j);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::AdvanceIteratorFn getAdvanceIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](void *i, qsizetype step) {
+ std::advance(*static_cast<QContainerTraits::iterator<C> *>(i), step);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::DiffIteratorFn getDiffIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C> && !std::is_const_v<C>) {
+ return [](const void *i, const void *j) -> qsizetype {
+ return std::distance(*static_cast<const QContainerTraits::iterator<C> *>(j),
+ *static_cast<const QContainerTraits::iterator<C> *>(i));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::ElementAtIteratorFn getElementAtIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C>
+ && QContainerTraits::can_get_at_iterator_v<C> && !std::is_const_v<C>) {
+ return [](const void *i, void *r) {
+ *static_cast<QContainerTraits::value_type<C> *>(r) =
+ *(*static_cast<const QContainerTraits::iterator<C> *>(i));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::SetElementAtIteratorFn getSetElementAtIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C>
+ && QContainerTraits::can_set_at_iterator_v<C> && !std::is_const_v<C>) {
+ return [](const void *i, const void *e) {
+ *(*static_cast<const QContainerTraits::iterator<C> *>(i))
+ = *static_cast<const QContainerTraits::value_type<C> *>(e);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::InsertElementAtIteratorFn getInsertElementAtIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C>
+ && QContainerTraits::can_insert_at_iterator_v<C> && !std::is_const_v<C>) {
+ return [](void *c, const void *i, const void *e) {
+ static_cast<C *>(c)->insert(
+ *static_cast<const QContainerTraits::iterator<C> *>(i),
+ *static_cast<const QContainerTraits::value_type<C> *>(e));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::EraseElementAtIteratorFn getEraseElementAtIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_iterator_v<C>
+ && QContainerTraits::can_erase_at_iterator_v<C> && !std::is_const_v<C>) {
+ return [](void *c, const void *i) {
+ static_cast<C *>(c)->erase(*static_cast<const QContainerTraits::iterator<C> *>(i));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CreateConstIteratorFn getCreateConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](const void *c, QMetaSequenceInterface::Position p) -> void* {
+ using Iterator = QContainerTraits::const_iterator<C>;
+ switch (p) {
+ case QMetaSequenceInterface::AtBegin:
+ case QMetaSequenceInterface::Random:
+ return new Iterator(static_cast<const C *>(c)->begin());
+ break;
+ case QMetaSequenceInterface::AtEnd:
+ return new Iterator(static_cast<const C *>(c)->end());
+ break;
+ }
+ return nullptr;
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::DestroyIteratorFn getDestroyConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](const void *i) {
+ using Iterator = QContainerTraits::const_iterator<C>;
+ delete static_cast<const Iterator *>(i);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CompareIteratorFn getCompareConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](const void *i, const void *j) {
+ using Iterator = QContainerTraits::const_iterator<C>;
+ return *static_cast<const Iterator *>(i) == *static_cast<const Iterator *>(j);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::CopyIteratorFn getCopyConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](void *i, const void *j) {
+ using Iterator = QContainerTraits::const_iterator<C>;
+ *static_cast<Iterator *>(i) = *static_cast<const Iterator *>(j);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::AdvanceIteratorFn getAdvanceConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](void *i, qsizetype step) {
+ std::advance(*static_cast<QContainerTraits::const_iterator<C> *>(i), step);
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::DiffIteratorFn getDiffConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>) {
+ return [](const void *i, const void *j) -> qsizetype {
+ return std::distance(*static_cast<const QContainerTraits::const_iterator<C> *>(j),
+ *static_cast<const QContainerTraits::const_iterator<C> *>(i));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+ static constexpr QMetaSequenceInterface::ElementAtIteratorFn getElementAtConstIteratorFn()
+ {
+ if constexpr (QContainerTraits::has_const_iterator_v<C>
+ && QContainerTraits::can_get_at_iterator_v<C>) {
+ return [](const void *i, void *r) {
+ *static_cast<QContainerTraits::value_type<C> *>(r) =
+ *(*static_cast<const QContainerTraits::const_iterator<C> *>(i));
+ };
+ } else {
+ return nullptr;
+ }
+ }
+
+public:
+ static QMetaSequenceInterface metaSequence;
+};
+
+template<typename C>
+QMetaSequenceInterface QMetaSequenceForContainer<C>::metaSequence = {
+ /*.revision=*/ 0,
+ /*.iteratorCapabilities=*/ getIteratorCapabilities(),
+ /*.addRemovePosition=*/ getAddRemovePosition(),
+ /*.valueMetaType=*/ getValueMetaType(),
+ /*.sizeFn=*/ getSizeFn(),
+ /*.clearFn=*/ getClearFn(),
+ /*.elementAtIndexFn=*/ getElementAtIndexFn(),
+ /*.setElementAtIndexFn=*/ getSetElementAtIndexFn(),
+ /*.addElementFn=*/ getAddElementFn(),
+ /*.removeLastElementFn=*/ getRemoveElementFn(),
+ /*.createIteratorFn=*/ getCreateIteratorFn(),
+ /*.destroyIteratorFn=*/ getDestroyIteratorFn(),
+ /*.equalIteratorFn=*/ getCompareIteratorFn(),
+ /*.copyIteratorFn=*/ getCopyIteratorFn(),
+ /*.advanceIteratorFn=*/ getAdvanceIteratorFn(),
+ /*.diffIteratorFn=*/ getDiffIteratorFn(),
+ /*.elementAtIteratorFn=*/ getElementAtIteratorFn(),
+ /*.setElementAtIteratorFn=*/ getSetElementAtIteratorFn(),
+ /*.insertElementAtIteratorFn=*/ getInsertElementAtIteratorFn(),
+ /*.eraseElementAtIteratorFn=*/ getEraseElementAtIteratorFn(),
+ /*.createConstIteratorFn=*/ getCreateConstIteratorFn(),
+ /*.destroyConstIteratorFn=*/ getDestroyConstIteratorFn(),
+ /*.equalConstIteratorFn=*/ getCompareConstIteratorFn(),
+ /*.copyConstIteratorFn=*/ getCopyConstIteratorFn(),
+ /*.advanceConstIteratorFn=*/ getAdvanceConstIteratorFn(),
+ /*.diffConstIteratorFn=*/ getDiffConstIteratorFn(),
+ /*.elementAtConstIteratorFn=*/ getElementAtConstIteratorFn(),
+};
+
+template<typename C>
+constexpr QMetaSequenceInterface *qMetaSequenceInterfaceForContainer()
+{
+ return &QMetaSequenceForContainer<C>::metaSequence;
+}
+
+} // namespace QtMetaContainerPrivate
+
+class Q_CORE_EXPORT QMetaSequence
+{
+public:
+ QMetaSequence() = default;
+ explicit QMetaSequence(QtMetaContainerPrivate::QMetaSequenceInterface *d) : d_ptr(d) {}
+
+ template<typename T>
+ static constexpr QMetaSequence fromContainer()
+ {
+ return QMetaSequence(QtMetaContainerPrivate::qMetaSequenceInterfaceForContainer<T>());
+ }
+
+ bool hasForwardIterator() const;
+ bool hasBidirectionalIterator() const;
+ bool hasRandomAccessIterator() const;
+
+ QMetaType valueMetaType() const;
+
+ bool isOrdered() const;
+ bool addsAndRemovesElementsAtBegin() const;
+ bool addsAndRemovesElementsAtEnd() const;
+
+ bool hasSize() const;
+ qsizetype size(const void *container) const;
+
+ bool canClear() const;
+ void clear(void *container) const;
+
+ bool canGetElementAtIndex() const;
+ void elementAtIndex(const void *container, qsizetype index, void *result) const;
+
+ bool canSetElementAtIndex() const;
+ void setElementAtIndex(void *container, qsizetype index, const void *element) const;
+
+ bool canAddElement() const;
+ void addElement(void *container, const void *element) const;
+
+ bool canRemoveElement() const;
+ void removeElement(void *container) const;
+
+ bool hasIterator() const;
+ void *begin(void *container) const;
+ void *end(void *container) const;
+ void destroyIterator(const void *iterator) const;
+ bool compareIterator(const void *i, const void *j) const;
+ void copyIterator(void *target, const void *source) const;
+ void advanceIterator(void *iterator, qsizetype step) const;
+ qsizetype diffIterator(const void *i, const void *j) const;
+
+ bool canGetElementAtIterator() const;
+ void elementAtIterator(const void *iterator, void *result) const;
+
+ bool canSetElementAtIterator() const;
+ void setElementAtIterator(const void *iterator, const void *element) const;
+
+ bool canInsertElementAtIterator() const;
+ void insertElementAtIterator(void *container, const void *iterator, const void *element) const;
+
+ bool canEraseElementAtIterator() const;
+ void eraseElementAtIterator(void *container, const void *iterator) const;
+
+ bool hasConstIterator() const;
+ void *constBegin(const void *container) const;
+ void *constEnd(const void *container) const;
+ void destroyConstIterator(const void *iterator) const;
+ bool compareConstIterator(const void *i, const void *j) const;
+ void copyConstIterator(void *target, const void *source) const;
+ void advanceConstIterator(void *iterator, qsizetype step) const;
+ qsizetype diffConstIterator(const void *i, const void *j) const;
+
+ bool canGetElementAtConstIterator() const;
+ void elementAtConstIterator(const void *iterator, void *result) const;
+
+ friend bool operator==(const QMetaSequence &a, const QMetaSequence &b)
+ {
+ return a.d_ptr == b.d_ptr;
+ }
+ friend bool operator!=(const QMetaSequence &a, const QMetaSequence &b)
+ {
+ return a.d_ptr != b.d_ptr;
+ }
+
+private:
+ QtMetaContainerPrivate::QMetaSequenceInterface *d_ptr = nullptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QMETACONTAINER_H
diff --git a/src/tools/bootstrap/.prev_CMakeLists.txt b/src/tools/bootstrap/.prev_CMakeLists.txt
index a69351a167..a4bb4f6aac 100644
--- a/src/tools/bootstrap/.prev_CMakeLists.txt
+++ b/src/tools/bootstrap/.prev_CMakeLists.txt
@@ -75,6 +75,7 @@ qt_add_module(Bootstrap
../../corelib/io/qurlrecode.cpp
../../corelib/kernel/qcoreapplication.cpp
../../corelib/kernel/qcoreglobaldata.cpp
+ ../../corelib/kernel/qmetacontainer.cpp
../../corelib/kernel/qmetatype.cpp
../../corelib/kernel/qsharedmemory.cpp
../../corelib/kernel/qsystemerror.cpp
diff --git a/src/tools/bootstrap/CMakeLists.txt b/src/tools/bootstrap/CMakeLists.txt
index 56b1bcbbcf..f5b1c38c39 100644
--- a/src/tools/bootstrap/CMakeLists.txt
+++ b/src/tools/bootstrap/CMakeLists.txt
@@ -76,6 +76,7 @@ qt_extend_target(Bootstrap
../../corelib/io/qurlrecode.cpp
../../corelib/kernel/qcoreapplication.cpp
../../corelib/kernel/qcoreglobaldata.cpp
+ ../../corelib/kernel/qmetacontainer.cpp
../../corelib/kernel/qmetatype.cpp
../../corelib/kernel/qsharedmemory.cpp
../../corelib/kernel/qsystemerror.cpp
diff --git a/src/tools/bootstrap/bootstrap.pro b/src/tools/bootstrap/bootstrap.pro
index 999ceea840..1853ab74b4 100644
--- a/src/tools/bootstrap/bootstrap.pro
+++ b/src/tools/bootstrap/bootstrap.pro
@@ -62,6 +62,7 @@ SOURCES += \
../../corelib/io/qurlrecode.cpp \
../../corelib/kernel/qcoreapplication.cpp \
../../corelib/kernel/qcoreglobaldata.cpp \
+ ../../corelib/kernel/qmetacontainer.cpp \
../../corelib/kernel/qmetatype.cpp \
../../corelib/kernel/qvariant.cpp \
../../corelib/kernel/qsystemerror.cpp \