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>
This commit is contained in:
Ulf Hermann 2020-08-25 11:58:09 +02:00
parent 83ad54c124
commit 4fbb2f66d6
20 changed files with 1979 additions and 1 deletions

View File

@ -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

View File

@ -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

View File

@ -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) $<

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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 \

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 \

View File

@ -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)

View File

@ -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)

View File

@ -6,6 +6,7 @@ SUBDIRS=\
qeventdispatcher \
qeventloop \
qmath \
qmetacontainer \
qmetaobject \
qmetaobjectbuilder \
qmetamethod \

View File

@ -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}
)

View File

@ -0,0 +1,7 @@
CONFIG += testcase
TARGET = tst_qmetacontainer
QT = core-private testlib
SOURCES = tst_qmetacontainer.cpp
TESTDATA=./typeFlags.bin

View File

@ -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"