summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--qmake/.prev_CMakeLists.txt2
-rw-r--r--qmake/CMakeLists.txt2
-rw-r--r--qmake/Makefile.unix6
-rw-r--r--qmake/qmake.pro3
-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
-rw-r--r--tests/auto/corelib/kernel/.prev_CMakeLists.txt1
-rw-r--r--tests/auto/corelib/kernel/CMakeLists.txt1
-rw-r--r--tests/auto/corelib/kernel/kernel.pro1
-rw-r--r--tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt16
-rw-r--r--tests/auto/corelib/kernel/qmetacontainer/qmetacontainer.pro7
-rw-r--r--tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp490
20 files changed, 1979 insertions, 1 deletions
diff --git a/qmake/.prev_CMakeLists.txt b/qmake/.prev_CMakeLists.txt
index 127da3d71f..8719a3eb54 100644
--- a/qmake/.prev_CMakeLists.txt
+++ b/qmake/.prev_CMakeLists.txt
@@ -38,6 +38,7 @@ qt_add_tool(${target_name}
../src/3rdparty/pcre2/src/pcre2_ucp.h
../src/3rdparty/pcre2/src/pcre2_valid_utf.c
../src/3rdparty/pcre2/src/pcre2_xclass.c
+ ../src/corelib/global/qcontainerinfo.h
../src/corelib/global/qglobal.cpp ../src/corelib/global/qglobal.h
../src/corelib/global/qlibraryinfo.cpp
../src/corelib/global/qlogging.cpp
@@ -57,6 +58,7 @@ qt_add_tool(${target_name}
../src/corelib/io/qiodevice.cpp ../src/corelib/io/qiodevice.h
../src/corelib/io/qsettings.cpp
../src/corelib/io/qtemporaryfile.cpp ../src/corelib/io/qtemporaryfile.h
+ ../src/corelib/kernel/qmetacontainer.cpp ../src/corelib/kernel/qmetacontainer.h
../src/corelib/kernel/qmetatype.cpp ../src/corelib/kernel/qmetatype.h
../src/corelib/kernel/qsystemerror.cpp ../src/corelib/kernel/qsystemerror_p.h
../src/corelib/kernel/qvariant.cpp
diff --git a/qmake/CMakeLists.txt b/qmake/CMakeLists.txt
index 15c85b3400..fc5d488c49 100644
--- a/qmake/CMakeLists.txt
+++ b/qmake/CMakeLists.txt
@@ -41,6 +41,7 @@ qt_add_tool(${target_name}
../src/3rdparty/pcre2/src/pcre2_ucp.h
../src/3rdparty/pcre2/src/pcre2_valid_utf.c
../src/3rdparty/pcre2/src/pcre2_xclass.c
+ ../src/corelib/global/qcontainerinfo.h
../src/corelib/global/qendian.cpp # special case
../src/corelib/global/qglobal.cpp ../src/corelib/global/qglobal.h
../src/corelib/global/qlibraryinfo.cpp
@@ -65,6 +66,7 @@ qt_add_tool(${target_name}
../src/corelib/io/qiodevice.cpp ../src/corelib/io/qiodevice.h
../src/corelib/io/qsettings.cpp
../src/corelib/io/qtemporaryfile.cpp ../src/corelib/io/qtemporaryfile.h
+ ../src/corelib/kernel/qmetacontainer.cpp ../src/corelib/kernel/qmetacontainer.h
../src/corelib/kernel/qmetatype.cpp ../src/corelib/kernel/qmetatype.h
../src/corelib/kernel/qsystemerror.cpp ../src/corelib/kernel/qsystemerror_p.h
../src/corelib/kernel/qvariant.cpp
diff --git a/qmake/Makefile.unix b/qmake/Makefile.unix
index da49bb3177..822150f246 100644
--- a/qmake/Makefile.unix
+++ b/qmake/Makefile.unix
@@ -25,7 +25,7 @@ QOBJS = \
qiodevice.o qsettings.o qtemporaryfile.o qtextstream.o \
qcborstreamwriter.o qcborvalue.o \
qjsoncbor.o qjsonarray.o qjsondocument.o qjsonobject.o qjsonparser.o qjsonvalue.o \
- qmetatype.o qsystemerror.o qvariant.o \
+ qmetacontainer.o qmetatype.o qsystemerror.o qvariant.o \
quuid.o \
qarraydata.o qbitarray.o qbytearray.o qbytearraylist.o qbytearraymatcher.o \
qcalendar.o qgregoriancalendar.o qromancalendar.o \
@@ -96,6 +96,7 @@ DEPEND_SRC = \
$(SOURCE_PATH)/src/corelib/io/qiodevice.cpp \
$(SOURCE_PATH)/src/corelib/io/qsettings.cpp \
$(SOURCE_PATH)/src/corelib/io/qtemporaryfile.cpp \
+ $(SOURCE_PATH)/src/corelib/kernel/qmetacontainer.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qvariant.cpp \
@@ -354,6 +355,9 @@ qvsnprintf.o: $(SOURCE_PATH)/src/corelib/text/qvsnprintf.cpp
qbytearraymatcher.o: $(SOURCE_PATH)/src/corelib/text/qbytearraymatcher.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
+qmetacontainer.o: $(SOURCE_PATH)/src/corelib/kernel/qmetacontainer.cpp
+ $(CXX) -c -o $@ $(CXXFLAGS) $<
+
qmetatype.o: $(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
diff --git a/qmake/qmake.pro b/qmake/qmake.pro
index 4ba7a41fad..9decc10edc 100644
--- a/qmake/qmake.pro
+++ b/qmake/qmake.pro
@@ -148,6 +148,7 @@ SOURCES += \
qlocale_tools.cpp \
qlogging.cpp \
qmalloc.cpp \
+ qmetacontainer.cpp \
qmetatype.cpp \
qnumeric.cpp \
qregularexpression.cpp \
@@ -181,6 +182,7 @@ HEADERS += \
qcborvalue.h \
qcborvalue_p.h \
qchar.h \
+ qcontainerinfo.h \
qcryptographichash.h \
qdatetime.h \
qdatetime_p.h \
@@ -204,6 +206,7 @@ HEADERS += \
qlocale.h \
qlocale_tools_p.h \
qmap.h \
+ qmetacontainer.h \
qmetatype.h \
qnumeric.h \
qregularexpression.h \
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 \
diff --git a/tests/auto/corelib/kernel/.prev_CMakeLists.txt b/tests/auto/corelib/kernel/.prev_CMakeLists.txt
index 39438deb5b..154cc8e766 100644
--- a/tests/auto/corelib/kernel/.prev_CMakeLists.txt
+++ b/tests/auto/corelib/kernel/.prev_CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(qdeadlinetimer)
add_subdirectory(qelapsedtimer)
add_subdirectory(qeventdispatcher)
add_subdirectory(qmath)
+add_subdirectory(qmetacontainer)
add_subdirectory(qmetaobject)
add_subdirectory(qmetaobjectbuilder)
add_subdirectory(qmetamethod)
diff --git a/tests/auto/corelib/kernel/CMakeLists.txt b/tests/auto/corelib/kernel/CMakeLists.txt
index 622b4175a5..e1b2db64c0 100644
--- a/tests/auto/corelib/kernel/CMakeLists.txt
+++ b/tests/auto/corelib/kernel/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory(qdeadlinetimer)
add_subdirectory(qelapsedtimer)
add_subdirectory(qeventdispatcher)
add_subdirectory(qmath)
+add_subdirectory(qmetacontainer)
add_subdirectory(qmetaobject)
add_subdirectory(qmetaobjectbuilder)
add_subdirectory(qmetamethod)
diff --git a/tests/auto/corelib/kernel/kernel.pro b/tests/auto/corelib/kernel/kernel.pro
index 7c4fd2ec3d..ba39070933 100644
--- a/tests/auto/corelib/kernel/kernel.pro
+++ b/tests/auto/corelib/kernel/kernel.pro
@@ -6,6 +6,7 @@ SUBDIRS=\
qeventdispatcher \
qeventloop \
qmath \
+ qmetacontainer \
qmetaobject \
qmetaobjectbuilder \
qmetamethod \
diff --git a/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt b/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt
new file mode 100644
index 0000000000..6f0192155d
--- /dev/null
+++ b/tests/auto/corelib/kernel/qmetacontainer/CMakeLists.txt
@@ -0,0 +1,16 @@
+# Generated from qmetacontainer.pro.
+
+#####################################################################
+## tst_qmetacontainer Test:
+#####################################################################
+
+# Collect test data
+list(APPEND test_data "./typeFlags.bin")
+
+qt_add_test(tst_qmetacontainer
+ SOURCES
+ tst_qmetacontainer.cpp
+ PUBLIC_LIBRARIES
+ Qt::CorePrivate
+ TESTDATA ${test_data}
+)
diff --git a/tests/auto/corelib/kernel/qmetacontainer/qmetacontainer.pro b/tests/auto/corelib/kernel/qmetacontainer/qmetacontainer.pro
new file mode 100644
index 0000000000..65f3eaa10b
--- /dev/null
+++ b/tests/auto/corelib/kernel/qmetacontainer/qmetacontainer.pro
@@ -0,0 +1,7 @@
+CONFIG += testcase
+TARGET = tst_qmetacontainer
+QT = core-private testlib
+SOURCES = tst_qmetacontainer.cpp
+TESTDATA=./typeFlags.bin
+
+
diff --git a/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp
new file mode 100644
index 0000000000..84343c4a14
--- /dev/null
+++ b/tests/auto/corelib/kernel/qmetacontainer/tst_qmetacontainer.cpp
@@ -0,0 +1,490 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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 General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** 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-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/qtest.h>
+#include <QtCore/qcontainerinfo.h>
+#include <QtCore/qmetacontainer.h>
+
+#include <QtCore/qvector.h>
+#include <QtCore/qset.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+
+#include <vector>
+#include <set>
+#include <forward_list>
+
+namespace CheckContainerTraits
+{
+struct NotAContainer {};
+
+static_assert(QContainerTraits::has_size_v<QVector<int>>);
+static_assert(QContainerTraits::has_size_v<QSet<int>>);
+static_assert(!QContainerTraits::has_size_v<NotAContainer>);
+static_assert(QContainerTraits::has_size_v<std::vector<int>>);
+static_assert(QContainerTraits::has_size_v<std::set<int>>);
+static_assert(!QContainerTraits::has_size_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_clear_v<QVector<int>>);
+static_assert(QContainerTraits::has_clear_v<QSet<int>>);
+static_assert(!QContainerTraits::has_clear_v<NotAContainer>);
+static_assert(QContainerTraits::has_clear_v<std::vector<int>>);
+static_assert(QContainerTraits::has_clear_v<std::set<int>>);
+static_assert(QContainerTraits::has_clear_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_at_v<QVector<int>>);
+static_assert(!QContainerTraits::has_at_v<QSet<int>>);
+static_assert(!QContainerTraits::has_at_v<NotAContainer>);
+static_assert(QContainerTraits::has_at_v<std::vector<int>>);
+static_assert(!QContainerTraits::has_at_v<std::set<int>>);
+static_assert(!QContainerTraits::has_at_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::can_get_at_index_v<QVector<int>>);
+static_assert(!QContainerTraits::can_get_at_index_v<QSet<int>>);
+static_assert(!QContainerTraits::can_get_at_index_v<NotAContainer>);
+static_assert(QContainerTraits::can_get_at_index_v<std::vector<int>>);
+static_assert(!QContainerTraits::can_get_at_index_v<std::set<int>>);
+static_assert(!QContainerTraits::can_get_at_index_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::can_set_at_index_v<QVector<int>>);
+static_assert(!QContainerTraits::can_set_at_index_v<QSet<int>>);
+static_assert(!QContainerTraits::can_set_at_index_v<NotAContainer>);
+static_assert(QContainerTraits::can_set_at_index_v<std::vector<int>>);
+static_assert(!QContainerTraits::can_set_at_index_v<std::set<int>>);
+static_assert(!QContainerTraits::can_set_at_index_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_push_back_v<QVector<int>>);
+static_assert(!QContainerTraits::has_push_back_v<QSet<int>>);
+static_assert(!QContainerTraits::has_push_back_v<NotAContainer>);
+static_assert(QContainerTraits::has_push_back_v<std::vector<int>>);
+static_assert(!QContainerTraits::has_push_back_v<std::set<int>>);
+static_assert(!QContainerTraits::has_push_back_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_push_front_v<QVector<int>>);
+static_assert(!QContainerTraits::has_push_front_v<QSet<int>>);
+static_assert(!QContainerTraits::has_push_front_v<NotAContainer>);
+static_assert(!QContainerTraits::has_push_front_v<std::vector<int>>);
+static_assert(!QContainerTraits::has_push_front_v<std::set<int>>);
+static_assert(QContainerTraits::has_push_front_v<std::forward_list<int>>);
+
+static_assert(!QContainerTraits::has_insert_v<QVector<int>>);
+static_assert(QContainerTraits::has_insert_v<QSet<int>>);
+static_assert(!QContainerTraits::has_insert_v<NotAContainer>);
+static_assert(!QContainerTraits::has_insert_v<std::vector<int>>);
+static_assert(QContainerTraits::has_insert_v<std::set<int>>);
+static_assert(!QContainerTraits::has_insert_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_pop_back_v<QVector<int>>);
+static_assert(!QContainerTraits::has_pop_back_v<QSet<int>>);
+static_assert(!QContainerTraits::has_pop_back_v<NotAContainer>);
+static_assert(QContainerTraits::has_pop_back_v<std::vector<int>>);
+static_assert(!QContainerTraits::has_pop_back_v<std::set<int>>);
+static_assert(!QContainerTraits::has_pop_back_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_pop_front_v<QVector<int>>);
+static_assert(!QContainerTraits::has_pop_front_v<QSet<int>>);
+static_assert(!QContainerTraits::has_pop_front_v<NotAContainer>);
+static_assert(!QContainerTraits::has_pop_front_v<std::vector<int>>);
+static_assert(!QContainerTraits::has_pop_front_v<std::set<int>>);
+static_assert(QContainerTraits::has_pop_front_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_iterator_v<QVector<int>>);
+static_assert(QContainerTraits::has_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::has_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::has_iterator_v<std::vector<int>>);
+static_assert(QContainerTraits::has_iterator_v<std::set<int>>);
+static_assert(QContainerTraits::has_iterator_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::has_const_iterator_v<QVector<int>>);
+static_assert(QContainerTraits::has_const_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::has_const_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::has_const_iterator_v<std::vector<int>>);
+static_assert(QContainerTraits::has_const_iterator_v<std::set<int>>);
+static_assert(QContainerTraits::has_const_iterator_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::can_get_at_iterator_v<QVector<int>>);
+static_assert(QContainerTraits::can_get_at_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::can_get_at_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::can_get_at_iterator_v<std::vector<int>>);
+static_assert(QContainerTraits::can_get_at_iterator_v<std::set<int>>);
+static_assert(QContainerTraits::can_get_at_iterator_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::can_set_at_iterator_v<QVector<int>>);
+static_assert(!QContainerTraits::can_set_at_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::can_get_at_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::can_set_at_iterator_v<std::vector<int>>);
+static_assert(!QContainerTraits::can_set_at_iterator_v<std::set<int>>);
+static_assert(QContainerTraits::can_set_at_iterator_v<std::forward_list<int>>);
+
+static_assert(QContainerTraits::can_insert_at_iterator_v<QVector<int>>);
+static_assert(!QContainerTraits::can_insert_at_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::can_insert_at_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::can_insert_at_iterator_v<std::vector<int>>);
+static_assert(!QContainerTraits::can_insert_at_iterator_v<std::forward_list<int>>);
+
+// The iterator is only a hint, but syntactically indistinguishable from others.
+// It's explicitly there to be signature compatible with std::vector::insert, though.
+// Also, inserting into a set is not guaranteed to actually do anything.
+static_assert(QContainerTraits::can_insert_at_iterator_v<std::set<int>>);
+
+static_assert(QContainerTraits::can_erase_at_iterator_v<QVector<int>>);
+static_assert(QContainerTraits::can_erase_at_iterator_v<QSet<int>>);
+static_assert(!QContainerTraits::can_erase_at_iterator_v<NotAContainer>);
+static_assert(QContainerTraits::can_erase_at_iterator_v<std::vector<int>>);
+static_assert(QContainerTraits::can_erase_at_iterator_v<std::set<int>>);
+static_assert(!QContainerTraits::can_erase_at_iterator_v<std::forward_list<int>>);
+
+}
+
+class tst_QMetaContainer: public QObject
+{
+ Q_OBJECT
+
+private:
+ QVector<QMetaType> qvector;
+ std::vector<QString> stdvector;
+ QSet<QByteArray> qset;
+ std::set<int> stdset;
+ std::forward_list<QMetaSequence> forwardList;
+
+private slots:
+ void init();
+ void testSequence_data();
+ void testSequence();
+ void cleanup();
+};
+
+void tst_QMetaContainer::init()
+{
+ qvector = { QMetaType(), QMetaType::fromType<QString>(), QMetaType::fromType<int>() };
+ stdvector = { QStringLiteral("foo"), QStringLiteral("bar"), QStringLiteral("baz") };
+ qset = { "aaa", "bbb", "ccc" };
+ stdset = { 1, 2, 3, 42, 45, 11 };
+ forwardList = {
+ QMetaSequence::fromContainer<QVector<QMetaType>>(),
+ QMetaSequence::fromContainer<std::vector<QString>>(),
+ QMetaSequence::fromContainer<QSet<QByteArray>>(),
+ QMetaSequence::fromContainer<std::set<int>>(),
+ QMetaSequence::fromContainer<std::forward_list<QMetaSequence>>()
+ };
+}
+
+void tst_QMetaContainer::cleanup()
+{
+ qvector.clear();
+ stdvector.clear();
+ qset.clear();
+ stdset.clear();
+ forwardList.clear();
+}
+
+void tst_QMetaContainer::testSequence_data()
+{
+ QTest::addColumn<void *>("container");
+ QTest::addColumn<QMetaSequence>("metaSequence");
+ QTest::addColumn<QMetaType>("metaType");
+ QTest::addColumn<bool>("hasSize");
+ QTest::addColumn<bool>("isIndexed");
+ QTest::addColumn<bool>("canRemove");
+ QTest::addColumn<bool>("hasBidirectionalIterator");
+ QTest::addColumn<bool>("hasRandomAccessIterator");
+ QTest::addColumn<bool>("canInsertAtIterator");
+ QTest::addColumn<bool>("canEraseAtIterator");
+ QTest::addColumn<bool>("isOrdered");
+
+ QTest::addRow("QVector")
+ << static_cast<void *>(&qvector)
+ << QMetaSequence::fromContainer<QVector<QMetaType>>()
+ << QMetaType::fromType<QMetaType>()
+ << true << true << true << true << true << true << true << true;
+ QTest::addRow("std::vector")
+ << static_cast<void *>(&stdvector)
+ << QMetaSequence::fromContainer<std::vector<QString>>()
+ << QMetaType::fromType<QString>()
+ << true << true << true << true << true << true << true << true;
+ QTest::addRow("QSet")
+ << static_cast<void *>(&qset)
+ << QMetaSequence::fromContainer<QSet<QByteArray>>()
+ << QMetaType::fromType<QByteArray>()
+ << true << false << false << false << false << false << true << false;
+ QTest::addRow("std::set")
+ << static_cast<void *>(&stdset)
+ << QMetaSequence::fromContainer<std::set<int>>()
+ << QMetaType::fromType<int>()
+ << true << false << false << true << false << true << true << false;
+ QTest::addRow("std::forward_list")
+ << static_cast<void *>(&forwardList)
+ << QMetaSequence::fromContainer<std::forward_list<QMetaSequence>>()
+ << QMetaType::fromType<QMetaSequence>()
+ << false << false << true << false << false << false << false << true;
+}
+
+void tst_QMetaContainer::testSequence()
+{
+ QFETCH(void *, container);
+ QFETCH(QMetaSequence, metaSequence);
+ QFETCH(QMetaType, metaType);
+ QFETCH(bool, hasSize);
+ QFETCH(bool, isIndexed);
+ QFETCH(bool, canRemove);
+ QFETCH(bool, hasBidirectionalIterator);
+ QFETCH(bool, hasRandomAccessIterator);
+ QFETCH(bool, canInsertAtIterator);
+ QFETCH(bool, canEraseAtIterator);
+ QFETCH(bool, isOrdered);
+
+ QVERIFY(metaSequence.canAddElement());
+ QCOMPARE(metaSequence.hasSize(), hasSize);
+ QCOMPARE(metaSequence.canGetElementAtIndex(), isIndexed);
+ QCOMPARE(metaSequence.canSetElementAtIndex(), isIndexed);
+ QCOMPARE(metaSequence.canRemoveElement(), canRemove);
+ QCOMPARE(metaSequence.hasBidirectionalIterator(), hasBidirectionalIterator);
+ QCOMPARE(metaSequence.hasRandomAccessIterator(), hasRandomAccessIterator);
+ QCOMPARE(metaSequence.canInsertElementAtIterator(), canInsertAtIterator);
+ QCOMPARE(metaSequence.canEraseElementAtIterator(), canEraseAtIterator);
+ QCOMPARE(metaSequence.isOrdered(), isOrdered);
+
+ QVariant var1(metaType);
+ QVariant var2(metaType);
+ QVariant var3(metaType);
+
+ if (hasSize) {
+ const qsizetype size = metaSequence.size(container);
+
+ // var1 is invalid, and our sets do not contain an invalid value so far.
+ metaSequence.addElement(container, var1.constData());
+ QCOMPARE(metaSequence.size(container), size + 1);
+ if (canRemove) {
+ metaSequence.removeElement(container);
+ QCOMPARE(metaSequence.size(container), size);
+ }
+ } else {
+ metaSequence.addElement(container, var1.constData());
+ if (canRemove)
+ metaSequence.removeElement(container);
+ }
+
+ if (isIndexed) {
+ QVERIFY(hasSize);
+ const qsizetype size = metaSequence.size(container);
+ for (qsizetype i = 0; i < size; ++i) {
+ metaSequence.elementAtIndex(container, i, var1.data());
+ metaSequence.elementAtIndex(container, size - i - 1, var2.data());
+
+ metaSequence.setElementAtIndex(container, i, var2.constData());
+ metaSequence.setElementAtIndex(container, size - i - 1, var1.constData());
+
+ metaSequence.elementAtIndex(container, i, var3.data());
+ QCOMPARE(var3, var2);
+
+ metaSequence.elementAtIndex(container, size - i - 1, var3.data());
+ QCOMPARE(var3, var1);
+ }
+ }
+
+ QVERIFY(metaSequence.hasIterator());
+ QVERIFY(metaSequence.hasConstIterator());
+ QVERIFY(metaSequence.canGetElementAtIterator());
+ QVERIFY(metaSequence.canGetElementAtConstIterator());
+
+ void *it = metaSequence.begin(container);
+ void *end = metaSequence.end(container);
+ QVERIFY(it);
+ QVERIFY(end);
+
+ void *constIt = metaSequence.constBegin(container);
+ void *constEnd = metaSequence.constEnd(container);
+ QVERIFY(constIt);
+ QVERIFY(constEnd);
+
+ const qsizetype size = metaSequence.diffIterator(end, it);
+ QCOMPARE(size, metaSequence.diffConstIterator(constEnd, constIt));
+ if (hasSize)
+ QCOMPARE(size, metaSequence.size(container));
+
+ qsizetype count = 0;
+ for (; !metaSequence.compareIterator(it, end);
+ metaSequence.advanceIterator(it, 1), metaSequence.advanceConstIterator(constIt, 1)) {
+ metaSequence.elementAtIterator(it, var1.data());
+ if (isIndexed) {
+ metaSequence.elementAtIndex(container, count, var2.data());
+ QCOMPARE(var1, var2);
+ }
+ metaSequence.elementAtConstIterator(constIt, var3.data());
+ QCOMPARE(var3, var1);
+ ++count;
+ }
+
+ QCOMPARE(count, size);
+ QVERIFY(metaSequence.compareConstIterator(constIt, constEnd));
+
+ metaSequence.destroyIterator(it);
+ metaSequence.destroyIterator(end);
+ metaSequence.destroyConstIterator(constIt);
+ metaSequence.destroyConstIterator(constEnd);
+
+ if (metaSequence.canSetElementAtIterator()) {
+ void *it = metaSequence.begin(container);
+ void *end = metaSequence.end(container);
+ QVERIFY(it);
+ QVERIFY(end);
+
+ for (; !metaSequence.compareIterator(it, end); metaSequence.advanceIterator(it, 1)) {
+ metaSequence.elementAtIterator(it, var1.data());
+ metaSequence.setElementAtIterator(it, var2.constData());
+ metaSequence.elementAtIterator(it, var3.data());
+ QCOMPARE(var2, var3);
+ var2 = var1;
+ }
+
+ metaSequence.destroyIterator(it);
+ metaSequence.destroyIterator(end);
+ }
+
+ if (metaSequence.hasBidirectionalIterator()) {
+ void *it = metaSequence.end(container);
+ void *end = metaSequence.begin(container);
+ QVERIFY(it);
+ QVERIFY(end);
+
+ void *constIt = metaSequence.constEnd(container);
+ void *constEnd = metaSequence.constBegin(container);
+ QVERIFY(constIt);
+ QVERIFY(constEnd);
+
+ qsizetype size = 0;
+ if (metaSequence.hasRandomAccessIterator()) {
+ size = metaSequence.diffIterator(end, it);
+ QCOMPARE(size, metaSequence.diffConstIterator(constEnd, constIt));
+ } else {
+ size = -metaSequence.diffIterator(it, end);
+ }
+
+ if (hasSize)
+ QCOMPARE(size, -metaSequence.size(container));
+
+ qsizetype count = 0;
+ do {
+ metaSequence.advanceIterator(it, -1);
+ metaSequence.advanceConstIterator(constIt, -1);
+ --count;
+
+ metaSequence.elementAtIterator(it, var1.data());
+ if (isIndexed) {
+ metaSequence.elementAtIndex(container, count - size, var2.data());
+ QCOMPARE(var1, var2);
+ }
+ metaSequence.elementAtConstIterator(constIt, var3.data());
+ QCOMPARE(var3, var1);
+ } while (!metaSequence.compareIterator(it, end));
+
+ QCOMPARE(count, size);
+ QVERIFY(metaSequence.compareConstIterator(constIt, constEnd));
+
+ metaSequence.destroyIterator(it);
+ metaSequence.destroyIterator(end);
+ metaSequence.destroyConstIterator(constIt);
+ metaSequence.destroyConstIterator(constEnd);
+ }
+
+ if (canInsertAtIterator) {
+ void *it = metaSequence.begin(container);
+ void *end = metaSequence.end(container);
+
+ const qsizetype size = metaSequence.diffIterator(end, it);
+ metaSequence.destroyIterator(end);
+
+ metaSequence.insertElementAtIterator(container, it, var1.constData());
+ metaSequence.destroyIterator(it);
+ it = metaSequence.begin(container);
+ metaSequence.insertElementAtIterator(container, it, var2.constData());
+ metaSequence.destroyIterator(it);
+ it = metaSequence.begin(container);
+ metaSequence.insertElementAtIterator(container, it, var3.constData());
+
+ metaSequence.destroyIterator(it);
+
+ it = metaSequence.begin(container);
+ end = metaSequence.end(container);
+
+ const qsizetype newSize = metaSequence.diffIterator(end, it);
+
+ if (metaSequence.isOrdered()) {
+ QCOMPARE(newSize, size + 3);
+ QVariant var4(metaType);
+ metaSequence.elementAtIterator(it, var4.data());
+ QCOMPARE(var4, var3);
+ metaSequence.advanceIterator(it, 1);
+ metaSequence.elementAtIterator(it, var4.data());
+ QCOMPARE(var4, var2);
+ metaSequence.advanceIterator(it, 1);
+ metaSequence.elementAtIterator(it, var4.data());
+ QCOMPARE(var4, var1);
+ } else {
+ QVERIFY(newSize >= size);
+ }
+
+ if (canEraseAtIterator) {
+ for (int i = 0; i < newSize; ++i) {
+ metaSequence.destroyIterator(it);
+ it = metaSequence.begin(container);
+ metaSequence.eraseElementAtIterator(container, it);
+ }
+
+ metaSequence.destroyIterator(it);
+ it = metaSequence.begin(container);
+ metaSequence.destroyIterator(end);
+ end = metaSequence.end(container);
+ QVERIFY(metaSequence.compareIterator(it, end));
+
+ metaSequence.addElement(container, var1.constData());
+ metaSequence.addElement(container, var2.constData());
+ metaSequence.addElement(container, var3.constData());
+ }
+
+ metaSequence.destroyIterator(end);
+ metaSequence.destroyIterator(it);
+ }
+
+ QVERIFY(metaSequence.canClear());
+ constIt = metaSequence.constBegin(container);
+ constEnd = metaSequence.constEnd(container);
+ QVERIFY(!metaSequence.compareConstIterator(constIt, constEnd));
+ metaSequence.destroyConstIterator(constIt);
+ metaSequence.destroyConstIterator(constEnd);
+
+ metaSequence.clear(container);
+ constIt = metaSequence.constBegin(container);
+ constEnd = metaSequence.constEnd(container);
+ QVERIFY(metaSequence.compareConstIterator(constIt, constEnd));
+ metaSequence.destroyConstIterator(constIt);
+ metaSequence.destroyConstIterator(constEnd);
+}
+
+QTEST_MAIN(tst_QMetaContainer)
+#include "tst_qmetacontainer.moc"