Reimplement QSequentialIterable using QMetaSequence

Change-Id: Ie721a5f0caa697c4bf15a81f3762cf79d3c54f5a
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
bb10
Ulf Hermann 2020-08-25 17:41:42 +02:00
parent 0e0149c64d
commit 53fde3c573
19 changed files with 592 additions and 631 deletions

View File

@ -58,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/qiterable.cpp ../src/corelib/kernel/qiterable.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

View File

@ -66,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/qiterable.cpp ../src/corelib/kernel/qiterable.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

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 \
qmetacontainer.o qmetatype.o qsystemerror.o qvariant.o \
qiterable.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/qiterable.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qmetacontainer.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qmetatype.cpp \
$(SOURCE_PATH)/src/corelib/kernel/qsystemerror.cpp \
@ -355,6 +356,9 @@ qvsnprintf.o: $(SOURCE_PATH)/src/corelib/text/qvsnprintf.cpp
qbytearraymatcher.o: $(SOURCE_PATH)/src/corelib/text/qbytearraymatcher.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qiterable.o: $(SOURCE_PATH)/src/corelib/kernel/qiterable.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<
qmetacontainer.o: $(SOURCE_PATH)/src/corelib/kernel/qmetacontainer.cpp
$(CXX) -c -o $@ $(CXXFLAGS) $<

View File

@ -114,6 +114,8 @@ QTOBJS= \
qsettings.obj \
qvariant.obj \
qsettings_win.obj \
qiterable.obj \
qmetacontainer.obj \
qmetatype.obj \
qnumeric.obj \
qlogging.obj \

View File

@ -137,6 +137,7 @@ SOURCES += \
qgregoriancalendar.cpp \
qhash.cpp \
qiodevice.cpp \
qiterable.cpp \
qjsonarray.cpp \
qjsoncbor.cpp \
qjsondocument.cpp \
@ -195,6 +196,7 @@ HEADERS += \
qgregoriancalendar_p.h \
qhash.h \
qiodevice.h \
qiterable.h \
qjson_p.h \
qjsonarray.h \
qjsondocument.h \

View File

@ -80,6 +80,7 @@ qt_add_module(Core
kernel/qelapsedtimer.cpp kernel/qelapsedtimer.h
kernel/qeventloop.cpp kernel/qeventloop.h
kernel/qfunctions_p.h
kernel/qiterable.cpp kernel/qiterable.h
kernel/qmath.cpp kernel/qmath.h
kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h

View File

@ -103,6 +103,7 @@ qt_add_module(Core
kernel/qelapsedtimer.cpp kernel/qelapsedtimer.h
kernel/qeventloop.cpp kernel/qeventloop.h
kernel/qfunctions_p.h
kernel/qiterable.cpp kernel/qiterable.h
kernel/qmath.cpp kernel/qmath.h
kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h

View File

@ -35,6 +35,7 @@ HEADERS += \
kernel/qmetaobjectbuilder_p.h \
kernel/qobject_p.h \
kernel/qcoreglobaldata_p.h \
kernel/qiterable.h \
kernel/qsharedmemory.h \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
@ -70,6 +71,7 @@ SOURCES += \
kernel/qtranslator.cpp \
kernel/qvariant.cpp \
kernel/qcoreglobaldata.cpp \
kernel/qiterable.cpp \
kernel/qsharedmemory.cpp \
kernel/qsystemsemaphore.cpp \
kernel/qpointer.cpp \

View File

@ -0,0 +1,368 @@
/****************************************************************************
**
** 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 <QtCore/qiterable.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
/*!
\class QSequentialIterable
\since 5.2
\inmodule QtCore
\brief The QSequentialIterable class is an iterable interface for a container in a QVariant.
This class allows several methods of accessing the elements of a container held within
a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can
be converted to a QVariantList.
\snippet code/src_corelib_kernel_qvariant.cpp 9
The container itself is not copied before iterating over it.
\sa QVariant
*/
QSequentialIterable::const_iterator::const_iterator(const QSequentialIterable *iterable, void *iterator)
: m_iterable(iterable), m_iterator(iterator), m_ref(new QAtomicInt(0))
{
m_ref->ref();
}
/*! \fn QSequentialIterable::const_iterator QSequentialIterable::begin() const
Returns a QSequentialIterable::const_iterator for the beginning of the container. This
can be used in stl-style iteration.
\sa end()
*/
QSequentialIterable::const_iterator QSequentialIterable::begin() const
{
return const_iterator(this, m_metaSequence.constBegin(m_iterable));
}
/*!
Returns a QSequentialIterable::const_iterator for the end of the container. This
can be used in stl-style iteration.
\sa begin()
*/
QSequentialIterable::const_iterator QSequentialIterable::end() const
{
return const_iterator(this, m_metaSequence.constEnd(m_iterable));
}
/*!
Returns the element at position \a idx in the container.
*/
QVariant QSequentialIterable::at(qsizetype idx) const
{
QVariant v(m_metaSequence.valueMetaType());
void *dataPtr;
if (m_metaSequence.valueMetaType() == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
const QMetaSequence metaSequence = m_metaSequence;
if (metaSequence.canGetElementAtIndex()) {
metaSequence.elementAtIndex(m_iterable, idx, dataPtr);
} else if (metaSequence.canGetElementAtConstIterator()) {
void *iterator = metaSequence.constBegin(m_iterable);
metaSequence.advanceConstIterator(iterator, idx);
metaSequence.elementAtConstIterator(iterator, dataPtr);
metaSequence.destroyConstIterator(iterator);
}
return v;
}
/*!
Returns the number of elements in the container.
*/
qsizetype QSequentialIterable::size() const
{
const QMetaSequence metaSequence = m_metaSequence;
const void *container = m_iterable;
if (metaSequence.hasSize())
return metaSequence.size(container);
if (!metaSequence.hasConstIterator())
return -1;
const void *begin = metaSequence.constBegin(container);
const void *end = metaSequence.constEnd(container);
const qsizetype size = metaSequence.diffConstIterator(end, begin);
metaSequence.destroyConstIterator(begin);
metaSequence.destroyConstIterator(end);
return size;
}
/*!
Returns whether it is possible to iterate over the container in reverse. This
corresponds to the std::bidirectional_iterator_tag iterator trait of the
const_iterator of the container.
*/
bool QSequentialIterable::canReverseIterate() const
{
return m_metaSequence.hasBidirectionalIterator();
}
/*!
\class QSequentialIterable::const_iterator
\since 5.2
\inmodule QtCore
\brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant.
A QSequentialIterable::const_iterator can only be created by a QSequentialIterable instance,
and can be used in a way similar to other stl-style iterators.
\snippet code/src_corelib_kernel_qvariant.cpp 9
\sa QSequentialIterable
*/
/*!
Destroys the QSequentialIterable::const_iterator.
*/
QSequentialIterable::const_iterator::~const_iterator() {
if (!m_ref->deref()) {
m_iterable->m_metaSequence.destroyConstIterator(m_iterator);
delete m_ref;
}
}
/*!
Creates a copy of \a other.
*/
QSequentialIterable::const_iterator::const_iterator(const const_iterator &other)
: m_iterable(other.m_iterable), m_iterator(other.m_iterator), m_ref(other.m_ref)
{
m_ref->ref();
}
/*!
Assigns \a other to this.
*/
QSequentialIterable::const_iterator&
QSequentialIterable::const_iterator::operator=(const const_iterator &other)
{
if (this == &other)
return *this;
other.m_ref->ref();
if (!m_ref->deref()) {
m_iterable->m_metaSequence.destroyConstIterator(m_iterator);
delete m_ref;
}
m_iterable = other.m_iterable;
m_iterator = other.m_iterator;
m_ref = other.m_ref;
return *this;
}
/*!
Returns the current item, converted to a QVariant.
*/
const QVariant QSequentialIterable::const_iterator::operator*() const
{
QVariant v(m_iterable->m_metaSequence.valueMetaType());
void *dataPtr;
if (m_iterable->m_metaSequence.valueMetaType() == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
m_iterable->m_metaSequence.elementAtConstIterator(m_iterator, dataPtr);
return v;
}
/*!
Returns \c true if \a other points to the same item as this
iterator; otherwise returns \c false.
\sa operator!=()
*/
bool QSequentialIterable::const_iterator::operator==(const const_iterator &other) const
{
return m_iterable->m_metaSequence.compareConstIterator(
m_iterator, other.m_iterator);
}
/*!
Returns \c true if \a other points to a different item than this
iterator; otherwise returns \c false.
\sa operator==()
*/
bool QSequentialIterable::const_iterator::operator!=(const const_iterator &other) const
{
return !m_iterable->m_metaSequence.compareConstIterator(
m_iterator, other.m_iterator);
}
/*!
The prefix ++ operator (\c{++it}) advances the iterator to the
next item in the container and returns an iterator to the new current
item.
Calling this function on QSequentialIterable::end() leads to undefined results.
\sa operator--()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator++()
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, 1);
return *this;
}
/*!
\overload
The postfix ++ operator (\c{it++}) advances the iterator to the
next item in the container and returns an iterator to the previously
current item.
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator++(int)
{
const_iterator result(
m_iterable,
m_iterable->m_metaSequence.constBegin(m_iterable->m_iterable));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, 1);
return result;
}
/*!
The prefix -- operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
Calling this function on QSequentialIterable::begin() leads to undefined results.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator++(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator--()
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -1);
return *this;
}
/*!
\overload
The postfix -- operator (\c{it--}) makes the preceding item
current and returns an iterator to the previously current item.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa canReverseIterate()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator--(int)
{
const_iterator result(
m_iterable,
m_iterable->m_metaSequence.constBegin(m_iterable->m_iterable));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -1);
return result;
}
/*!
Advances the iterator by \a j items.
\sa operator-=(), operator+()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator+=(int j)
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, j);
return *this;
}
/*!
Makes the iterator go back by \a j items.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator+=(), operator-(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator-=(int j)
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -j);
return *this;
}
/*!
Returns an iterator to the item at \a j positions forward from
this iterator.
\sa operator-(), operator+=()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator+(int j) const
{
const_iterator result(
m_iterable,
m_iterable->m_metaSequence.constBegin(m_iterable->m_iterable));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(result.m_iterator, j);
return result;
}
/*!
Returns an iterator to the item at \a j positions backward from
this iterator.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator+(), operator-=(), canReverseIterate()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator-(int j) const
{
const_iterator result(
m_iterable,
m_iterable->m_metaSequence.constBegin(m_iterable->m_iterable));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(result.m_iterator, -j);
return result;
}
QT_END_NAMESPACE

View File

@ -0,0 +1,149 @@
/****************************************************************************
**
** 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 QITERABLE_H
#define QITERABLE_H
#include <QtCore/qglobal.h>
#include <QtCore/qtypeinfo.h>
#include <QtCore/qmetacontainer.h>
#include <QtCore/qmetatype.h>
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QSequentialIterable
{
uint m_revision = 0;
const void *m_iterable = nullptr;
QMetaSequence m_metaSequence;
public:
struct Q_CORE_EXPORT const_iterator
{
private:
const QSequentialIterable *m_iterable = nullptr;
void *m_iterator = nullptr;
QAtomicInt *m_ref = nullptr;
friend class QSequentialIterable;
explicit const_iterator(const QSequentialIterable *iterable, void *iterator);
public:
~const_iterator();
const_iterator(const const_iterator &other);
const_iterator& operator=(const const_iterator &other);
const QVariant operator*() const;
bool operator==(const const_iterator &o) const;
bool operator!=(const const_iterator &o) const;
const_iterator &operator++();
const_iterator operator++(int);
const_iterator &operator--();
const_iterator operator--(int);
const_iterator &operator+=(int j);
const_iterator &operator-=(int j);
const_iterator operator+(int j) const;
const_iterator operator-(int j) const;
friend inline const_iterator operator+(int j, const const_iterator &k) { return k + j; }
};
friend struct const_iterator;
template<class T>
QSequentialIterable(const T *p)
: m_iterable(p)
, m_metaSequence(QMetaSequence::fromContainer<T>())
{
}
QSequentialIterable() = default;
QSequentialIterable(const QMetaSequence &metaSequence, const void *iterable)
: m_iterable(iterable)
, m_metaSequence(metaSequence)
{
}
const_iterator begin() const;
const_iterator end() const;
QVariant at(qsizetype idx) const;
qsizetype size() const;
bool canReverseIterate() const;
const void *constIterable() const { return m_iterable; }
QMetaSequence metaSequence() const { return m_metaSequence; }
};
namespace QtPrivate {
template<typename From>
struct QSequentialIterableConvertFunctor
{
QSequentialIterable operator()(const From &f) const
{
return QSequentialIterable(&f);
}
};
template<typename T>
struct SequentialValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QSequentialIterable>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QSequentialIterable>(o);
}
return true;
}
};
}
Q_DECLARE_TYPEINFO(QSequentialIterable, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::const_iterator, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QITERABLE_H

View File

@ -54,6 +54,7 @@
#include "quuid.h"
#include "qvariant.h"
#include "qdatastream.h"
#include "qiterable.h"
#if QT_CONFIG(regularexpression)
# include "qregularexpression.h"
@ -1832,13 +1833,12 @@ static bool convertIterableToVariantList(QMetaType fromType, const void *from, v
{
const QMetaType::ConverterFunction * const f =
customTypesConversionRegistry()->function(qMakePair(fromType.id(),
qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()));
qMetaTypeId<QSequentialIterable>()));
if (!f)
return false;
QtMetaTypePrivate::QSequentialIterableImpl iter;
(*f)(from, &iter);
QSequentialIterable list(iter);
QSequentialIterable list;
(*f)(from, &list);
QVariantList &l = *static_cast<QVariantList *>(to);
l.clear();
l.reserve(list.size());
@ -1924,20 +1924,15 @@ static bool convertToSequentialIterable(QMetaType fromType, const void *from, vo
QSequentialIterable &i = *static_cast<QSequentialIterable *>(to);
if (fromTypeId == QMetaType::QVariantList) {
i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast<const QVariantList *>(from)));
i = QSequentialIterable(reinterpret_cast<const QVariantList *>(from));
return true;
}
if (fromTypeId == QMetaType::QStringList) {
i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast<const QStringList *>(from)));
i = QSequentialIterable(reinterpret_cast<const QStringList *>(from));
return true;
}
else if (fromTypeId == QMetaType::QByteArrayList) {
i = QSequentialIterable(QSequentialIterableImpl(reinterpret_cast<const QByteArrayList *>(from)));
return true;
}
QSequentialIterableImpl impl;
if (QMetaType::convert(fromType, from, QMetaType::fromType<QtMetaTypePrivate::QSequentialIterableImpl>(), &impl)) {
i = QSequentialIterable(impl);
i = QSequentialIterable(reinterpret_cast<const QByteArrayList *>(from));
return true;
}
return false;
@ -2159,7 +2154,7 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
return true;
if (toTypeId == QVariantList && hasRegisteredConverterFunction(
fromTypeId, qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()))
fromTypeId, qMetaTypeId<QSequentialIterable>()))
return true;
if ((toTypeId == QVariantHash || toTypeId == QVariantMap) && hasRegisteredConverterFunction(

View File

@ -694,221 +694,6 @@ public:
}
};
enum IteratorCapability
{
ForwardCapability = 1,
BiDirectionalCapability = 2,
RandomAccessCapability = 4
};
enum ContainerCapability
{
ContainerIsAppendable = 1
};
template<typename Container, typename T = void>
struct ContainerCapabilitiesImpl
{
enum {ContainerCapabilities = 0};
using appendFunction = void(*)(const void *container, const void *newElement);
static constexpr const appendFunction appendImpl = nullptr;
};
template<typename Container>
struct ContainerCapabilitiesImpl<Container, decltype(std::declval<Container>().push_back(std::declval<typename Container::value_type>()))>
{
enum {ContainerCapabilities = ContainerIsAppendable};
// The code below invokes undefined behavior if and only if the pointer passed into QSequentialIterableImpl
// pointed to a const object to begin with
static void appendImpl(const void *container, const void *value)
{ static_cast<Container *>(const_cast<void *>(container))->push_back(*static_cast<const typename Container::value_type *>(value)); }
};
template<typename Container>
struct ContainerCapabilitiesImpl<Container,
std::void_t<decltype(std::declval<Container>().insert(std::declval<typename Container::value_type>())),
decltype(std::declval<typename Container::value_type>() == std::declval<typename Container::value_type>())>>
{
enum {ContainerCapabilities = ContainerIsAppendable};
// The code below invokes undefined behavior if and only if the pointer passed into QSequentialIterableImpl
// pointed to a const object to begin with
static void appendImpl(const void *container, const void *value)
{ static_cast<Container *>(const_cast<void *>(container))->insert(*static_cast<const typename Container::value_type *>(value)); }
};
template<typename T, typename Category = typename std::iterator_traits<typename T::const_iterator>::iterator_category>
struct CapabilitiesImpl;
template<typename T>
struct CapabilitiesImpl<T, std::forward_iterator_tag>
{ enum { IteratorCapabilities = ForwardCapability }; };
template<typename T>
struct CapabilitiesImpl<T, std::bidirectional_iterator_tag>
{ enum { IteratorCapabilities = BiDirectionalCapability | ForwardCapability }; };
template<typename T>
struct CapabilitiesImpl<T, std::random_access_iterator_tag>
{ enum { IteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability }; };
template<typename T>
struct ContainerAPI : CapabilitiesImpl<T>
{
static int size(const T *t) { return int(std::distance(t->begin(), t->end())); }
};
template<typename T>
struct ContainerAPI<QList<T>> : CapabilitiesImpl<QList<T>>
{ static int size(const QList<T> *t) { return t->size(); } };
template<typename T>
struct ContainerAPI<std::vector<T> > : CapabilitiesImpl<std::vector<T> >
{ static int size(const std::vector<T> *t) { return int(t->size()); } };
template<typename T>
struct ContainerAPI<std::list<T> > : CapabilitiesImpl<std::list<T> >
{ static int size(const std::list<T> *t) { return int(t->size()); } };
/*
revision 0: _iteratorCapabilties is treated as a bitfield, the remaining bits are used to introduce
_revision, _containerCapabilities and _unused. The latter contains 21 bits that are
not used yet
*/
class QSequentialIterableImpl
{
public:
const void * _iterable;
void *_iterator;
QMetaType _metaType;
uint _iteratorCapabilities;
// Iterator capabilities looks actually like
// uint _iteratorCapabilities:4;
// uint _revision:3;
// uint _containerCapabilities:4;
// uint _unused:21;
typedef int(*sizeFunc)(const void *p);
typedef void (*atFunc)(const void *p, int, void *);
enum Position { ToBegin, ToEnd };
typedef void (*moveIteratorFunc)(const void *p, void **, Position position);
typedef void (*advanceFunc)(void **p, int);
typedef void (*getFunc)( void * const *p, void *dataPtr);
typedef void (*destroyIterFunc)(void **p);
typedef bool (*equalIterFunc)(void * const *p, void * const *other);
typedef void (*copyIterFunc)(void **, void * const *);
typedef void(*appendFunction)(const void *container, const void *newElement);
IteratorCapability iteratorCapabilities() {return static_cast<IteratorCapability>(_iteratorCapabilities & 0xF);}
uint revision() {return _iteratorCapabilities >> 4 & 0x7;}
uint containerCapabilities() {return _iteratorCapabilities >> 7 & 0xF;}
sizeFunc _size;
atFunc _at;
moveIteratorFunc _moveTo;
appendFunction _append;
advanceFunc _advance;
getFunc _get;
destroyIterFunc _destroyIter;
equalIterFunc _equalIter;
copyIterFunc _copyIter;
template<class T>
static int sizeImpl(const void *p)
{ return ContainerAPI<T>::size(static_cast<const T*>(p)); }
template<class T>
static void atImpl(const void *p, int idx, void *dataPtr)
{
typename T::const_iterator i = static_cast<const T*>(p)->begin();
std::advance(i, idx);
IteratorOwner<typename T::const_iterator>::getData(i, dataPtr);
}
template<class Container>
static void moveToImpl(const void *container, void **iterator, Position position)
{
auto it = (position == ToBegin) ?
static_cast<const Container *>(container)->begin() :
static_cast<const Container *>(container)->end();
IteratorOwner<typename Container::const_iterator>::assign(iterator, it);
}
public:
template<class T> QSequentialIterableImpl(const T*p)
: _iterable(p)
, _iterator(nullptr)
, _metaType(QMetaType::fromType<typename T::value_type>())
, _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities | (0 << 4) | (ContainerCapabilitiesImpl<T>::ContainerCapabilities << (4+3)))
, _size(sizeImpl<T>)
, _at(atImpl<T>)
, _moveTo(moveToImpl<T>)
, _append(ContainerCapabilitiesImpl<T>::appendImpl)
, _advance(IteratorOwner<typename T::const_iterator>::advance)
, _get(IteratorOwner<typename T::const_iterator>::getData)
, _destroyIter(IteratorOwner<typename T::const_iterator>::destroy)
, _equalIter(IteratorOwner<typename T::const_iterator>::equal)
, _copyIter(IteratorOwner<typename T::const_iterator>::assign)
{
}
QSequentialIterableImpl()
: _iterable(nullptr)
, _iterator(nullptr)
, _iteratorCapabilities(0 | (0 << 4) ) // no iterator capabilities, revision 0
, _size(nullptr)
, _at(nullptr)
, _moveTo(nullptr)
, _append(nullptr)
, _advance(nullptr)
, _get(nullptr)
, _destroyIter(nullptr)
, _equalIter(nullptr)
, _copyIter(nullptr)
{
}
inline void moveToBegin() {
_moveTo(_iterable, &_iterator, ToBegin);
}
inline void moveToEnd() {
_moveTo(_iterable, &_iterator, ToEnd);
}
inline bool equal(const QSequentialIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); }
inline QSequentialIterableImpl &advance(int i) {
Q_ASSERT(i > 0 || _iteratorCapabilities & BiDirectionalCapability);
_advance(&_iterator, i);
return *this;
}
inline void append(const void *newElement) {
if (containerCapabilities() & ContainerIsAppendable)
_append(_iterable, newElement);
}
inline void getCurrent(void *dataPtr) const { _get(&_iterator, dataPtr); }
void at(int idx, void *dataPtr) const
{ return _at(_iterable, idx, dataPtr); }
int size() const { Q_ASSERT(_iterable); return _size(_iterable); }
inline void destroyIter() { _destroyIter(&_iterator); }
void copy(const QSequentialIterableImpl &other)
{
*this = other;
_copyIter(&_iterator, &other._iterator);
}
};
QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QSequentialIterableImpl, Q_MOVABLE_TYPE)
template<typename From>
struct QSequentialIterableConvertFunctor
{
QSequentialIterableImpl operator()(const From &f) const
{
return QSequentialIterableImpl(&f);
}
};
}
namespace QtMetaTypePrivate {
@ -1890,7 +1675,6 @@ QT_END_NAMESPACE
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QSequentialIterableImpl)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
@ -1908,20 +1692,6 @@ inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter(int id)
}
namespace QtPrivate {
template<typename T>
struct SequentialValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QtMetaTypePrivate::QSequentialIterableImpl>(o);
}
return true;
}
};
template<typename T>
struct AssociativeValueTypeIsMetaType<T, true>
{

View File

@ -2580,312 +2580,6 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\internal
*/
/*!
\class QSequentialIterable
\since 5.2
\inmodule QtCore
\brief The QSequentialIterable class is an iterable interface for a container in a QVariant.
This class allows several methods of accessing the elements of a container held within
a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can
be converted to a QVariantList.
\snippet code/src_corelib_kernel_qvariant.cpp 9
The container itself is not copied before iterating over it.
\sa QVariant
*/
/*!
\internal
*/
QSequentialIterable::QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl)
: m_impl(impl)
{
}
QSequentialIterable::const_iterator::const_iterator(const QSequentialIterable &iter, QAtomicInt *ref)
: m_impl(iter.m_impl), m_ref(ref)
{
m_ref->ref();
}
QSequentialIterable::const_iterator::const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref)
: m_impl(impl), m_ref(ref)
{
m_ref->ref();
}
/*! \fn QSequentialIterable::const_iterator QSequentialIterable::begin() const
Returns a QSequentialIterable::const_iterator for the beginning of the container. This
can be used in stl-style iteration.
\sa end()
*/
QSequentialIterable::const_iterator QSequentialIterable::begin() const
{
const_iterator it(*this, new QAtomicInt(0));
it.m_impl.moveToBegin();
return it;
}
/*!
Returns a QSequentialIterable::const_iterator for the end of the container. This
can be used in stl-style iteration.
\sa begin()
*/
QSequentialIterable::const_iterator QSequentialIterable::end() const
{
const_iterator it(*this, new QAtomicInt(0));
it.m_impl.moveToEnd();
return it;
}
/*!
Returns the element at position \a idx in the container.
*/
QVariant QSequentialIterable::at(int idx) const
{
QVariant v(m_impl._metaType);
void *dataPtr;
if (m_impl._metaType == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
m_impl.at(idx, dataPtr);
return v;
}
/*!
Returns the number of elements in the container.
*/
int QSequentialIterable::size() const
{
return m_impl.size();
}
/*!
Returns whether it is possible to iterate over the container in reverse. This
corresponds to the std::bidirectional_iterator_tag iterator trait of the
const_iterator of the container.
*/
bool QSequentialIterable::canReverseIterate() const
{
return m_impl._iteratorCapabilities & QtMetaTypePrivate::BiDirectionalCapability;
}
/*!
\class QSequentialIterable::const_iterator
\since 5.2
\inmodule QtCore
\brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant.
A QSequentialIterable::const_iterator can only be created by a QSequentialIterable instance,
and can be used in a way similar to other stl-style iterators.
\snippet code/src_corelib_kernel_qvariant.cpp 9
\sa QSequentialIterable
*/
/*!
Destroys the QSequentialIterable::const_iterator.
*/
QSequentialIterable::const_iterator::~const_iterator() {
if (!m_ref->deref()) {
m_impl.destroyIter();
delete m_ref;
}
}
/*!
Creates a copy of \a other.
*/
QSequentialIterable::const_iterator::const_iterator(const const_iterator &other)
: m_impl(other.m_impl), m_ref(other.m_ref)
{
m_ref->ref();
}
/*!
Assigns \a other to this.
*/
QSequentialIterable::const_iterator&
QSequentialIterable::const_iterator::operator=(const const_iterator &other)
{
other.m_ref->ref();
if (!m_ref->deref()) {
m_impl.destroyIter();
delete m_ref;
}
m_impl = other.m_impl;
m_ref = other.m_ref;
return *this;
}
/*!
Returns the current item, converted to a QVariant.
*/
const QVariant QSequentialIterable::const_iterator::operator*() const
{
QVariant v(m_impl._metaType);
void *dataPtr;
if (m_impl._metaType == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
m_impl.getCurrent(dataPtr);
return v;
}
/*!
Returns \c true if \a other points to the same item as this
iterator; otherwise returns \c false.
\sa operator!=()
*/
bool QSequentialIterable::const_iterator::operator==(const const_iterator &other) const
{
return m_impl.equal(other.m_impl);
}
/*!
Returns \c true if \a other points to a different item than this
iterator; otherwise returns \c false.
\sa operator==()
*/
bool QSequentialIterable::const_iterator::operator!=(const const_iterator &other) const
{
return !m_impl.equal(other.m_impl);
}
/*!
The prefix ++ operator (\c{++it}) advances the iterator to the
next item in the container and returns an iterator to the new current
item.
Calling this function on QSequentialIterable::end() leads to undefined results.
\sa operator--()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator++()
{
m_impl.advance(1);
return *this;
}
/*!
\overload
The postfix ++ operator (\c{it++}) advances the iterator to the
next item in the container and returns an iterator to the previously
current item.
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator++(int)
{
QtMetaTypePrivate::QSequentialIterableImpl impl;
impl.copy(m_impl);
m_impl.advance(1);
return const_iterator(impl, new QAtomicInt(0));
}
/*!
The prefix -- operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
Calling this function on QSequentialIterable::begin() leads to undefined results.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator++(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator--()
{
m_impl.advance(-1);
return *this;
}
/*!
\overload
The postfix -- operator (\c{it--}) makes the preceding item
current and returns an iterator to the previously current item.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa canReverseIterate()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator--(int)
{
QtMetaTypePrivate::QSequentialIterableImpl impl;
impl.copy(m_impl);
m_impl.advance(-1);
return const_iterator(impl, new QAtomicInt(0));
}
/*!
Advances the iterator by \a j items.
\sa operator-=(), operator+()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator+=(int j)
{
m_impl.advance(j);
return *this;
}
/*!
Makes the iterator go back by \a j items.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator+=(), operator-(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator-=(int j)
{
m_impl.advance(-j);
return *this;
}
/*!
Returns an iterator to the item at \a j positions forward from
this iterator.
\sa operator-(), operator+=()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator+(int j) const
{
QtMetaTypePrivate::QSequentialIterableImpl impl;
impl.copy(m_impl);
impl.advance(j);
return const_iterator(impl, new QAtomicInt(0));
}
/*!
Returns an iterator to the item at \a j positions backward from
this iterator.
If the container in the QVariant does not support bi-directional iteration, calling this function
leads to undefined results.
\sa operator+(), operator-=(), canReverseIterate()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator-(int j) const
{
QtMetaTypePrivate::QSequentialIterableImpl impl;
impl.copy(m_impl);
impl.advance(-j);
return const_iterator(impl, new QAtomicInt(0));
}
/*!
\class QAssociativeIterable
\since 5.2

View File

@ -581,55 +581,6 @@ inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2)
#endif
Q_DECLARE_SHARED(QVariant)
class Q_CORE_EXPORT QSequentialIterable
{
QtMetaTypePrivate::QSequentialIterableImpl m_impl;
public:
struct Q_CORE_EXPORT const_iterator
{
private:
QtMetaTypePrivate::QSequentialIterableImpl m_impl;
QAtomicInt *m_ref;
friend class QSequentialIterable;
explicit const_iterator(const QSequentialIterable &iter, QAtomicInt *ref);
explicit const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref);
public:
~const_iterator();
const_iterator(const const_iterator &other);
const_iterator& operator=(const const_iterator &other);
const QVariant operator*() const;
bool operator==(const const_iterator &o) const;
bool operator!=(const const_iterator &o) const;
const_iterator &operator++();
const_iterator operator++(int);
const_iterator &operator--();
const_iterator operator--(int);
const_iterator &operator+=(int j);
const_iterator &operator-=(int j);
const_iterator operator+(int j) const;
const_iterator operator-(int j) const;
friend inline const_iterator operator+(int j, const const_iterator &k) { return k + j; }
};
friend struct const_iterator;
explicit QSequentialIterable(const QtMetaTypePrivate::QSequentialIterableImpl &impl);
QSequentialIterable() {}
const_iterator begin() const;
const_iterator end() const;
QVariant at(int idx) const;
int size() const;
bool canReverseIterate() const;
};
class Q_CORE_EXPORT QAssociativeIterable
{
QtMetaTypePrivate::QAssociativeIterableImpl m_impl;

View File

@ -75,6 +75,7 @@ qt_add_module(Bootstrap
../../corelib/io/qurlrecode.cpp
../../corelib/kernel/qcoreapplication.cpp
../../corelib/kernel/qcoreglobaldata.cpp
../../corelib/kernel/qiterable.cpp
../../corelib/kernel/qmetacontainer.cpp
../../corelib/kernel/qmetatype.cpp
../../corelib/kernel/qsharedmemory.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/qiterable.cpp
../../corelib/kernel/qmetacontainer.cpp
../../corelib/kernel/qmetatype.cpp
../../corelib/kernel/qsharedmemory.cpp

View File

@ -62,6 +62,7 @@ SOURCES += \
../../corelib/io/qurlrecode.cpp \
../../corelib/kernel/qcoreapplication.cpp \
../../corelib/kernel/qcoreglobaldata.cpp \
../../corelib/kernel/qiterable.cpp \
../../corelib/kernel/qmetacontainer.cpp \
../../corelib/kernel/qmetatype.cpp \
../../corelib/kernel/qvariant.cpp \

View File

@ -1000,6 +1000,11 @@ void tst_QMetaType::alignOf()
}
struct CustomMovable { CustomMovable() {} };
// needed for QSet<CustomMovable>. We actually check that it makes sense.
bool operator==(const CustomMovable &, const CustomMovable &) { return true; }
qsizetype qHash(const CustomMovable &, qsizetype seed = 0) { return seed; }
#if !defined(Q_CC_CLANG) && defined(Q_CC_GNU) && Q_CC_GNU < 501
QT_BEGIN_NAMESPACE
Q_DECLARE_TYPEINFO(CustomMovable, Q_MOVABLE_TYPE);

View File

@ -4528,28 +4528,37 @@ void tst_QVariant::shouldDeleteVariantDataWorksForSequential()
{
QCOMPARE(instanceCount, 0);
{
QtMetaTypePrivate::QSequentialIterableImpl iterator {};
iterator._iteratorCapabilities = QtMetaTypePrivate::RandomAccessCapability |
QtMetaTypePrivate::BiDirectionalCapability |
QtMetaTypePrivate::ForwardCapability;
QtMetaContainerPrivate::QMetaSequenceInterface metaSequence {};
metaSequence.iteratorCapabilities = QtMetaContainerPrivate::RandomAccessCapability
| QtMetaContainerPrivate::BiDirectionalCapability
| QtMetaContainerPrivate::ForwardCapability;
iterator._size = [](const void *) {return 1;};
iterator._metaType = QMetaType::fromType<MyType>();
iterator._moveTo = [](const void *, void **, QtMetaTypePrivate::QSequentialIterableImpl::Position) {};
iterator._append = [](const void *, const void *) {};
iterator._advance = [](void **, int) {};
iterator._destroyIter = [](void **){};
iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/};
iterator._destroyIter = [](void **){};
iterator._at = [](const void *, int, void *dataPtr) -> void {
metaSequence.sizeFn = [](const void *) { return qsizetype(1); };
metaSequence.createConstIteratorFn =
[](const void *, QtMetaContainerPrivate::QMetaSequenceInterface::Position) -> void* {
return nullptr;
};
metaSequence.addElementFn = [](void *, const void *) {};
metaSequence.advanceConstIteratorFn = [](void *, qsizetype) {};
metaSequence.destroyConstIteratorFn = [](const void *){};
metaSequence.compareConstIteratorFn = [](const void *, const void *) {
return true; // all iterators are nullptr
};
metaSequence.copyConstIteratorFn = [](void *, const void *){};
metaSequence.diffConstIteratorFn = [](const void *, const void *) -> qsizetype {
return 0;
};
metaSequence.elementAtIndexFn = [](const void *, qsizetype, void *dataPtr) -> void {
MyType mytype {1, "eins"};
*static_cast<MyType *>(dataPtr) = mytype;
};
iterator._get = [](void * const *, void *dataPtr) -> void {
metaSequence.elementAtConstIteratorFn = [](const void *, void *dataPtr) -> void {
MyType mytype {2, "zwei"};
*static_cast<MyType *>(dataPtr) = mytype;
};
QSequentialIterable iterable {iterator};
metaSequence.valueMetaType = QMetaType::fromType<MyType>();
QSequentialIterable iterable(QMetaSequence(&metaSequence), nullptr);
QVariant value1 = iterable.at(0);
QVERIFY(value1.canConvert<MyType>());
QCOMPARE(value1.value<MyType>().number, 1);
@ -4669,12 +4678,13 @@ void tst_QVariant::qt4UuidDataStream()
void tst_QVariant::sequentialIterableEndianessSanityCheck()
{
namespace QMTP = QtMetaTypePrivate;
uint oldIteratorCaps = QMTP::ForwardCapability | QMTP::BiDirectionalCapability | QMTP::RandomAccessCapability;
QMTP::QSequentialIterableImpl seqImpl {};
QCOMPARE(seqImpl.revision(), 0u);
memcpy(&seqImpl._iteratorCapabilities, &oldIteratorCaps, sizeof(oldIteratorCaps));
QCOMPARE(seqImpl.revision(), 0u);
namespace QMTP = QtMetaContainerPrivate;
QMTP::IteratorCapabilities oldIteratorCaps
= QMTP::ForwardCapability | QMTP::BiDirectionalCapability | QMTP::RandomAccessCapability;
QMTP::QMetaSequenceInterface seqImpl {};
QCOMPARE(seqImpl.revision, 0u);
memcpy(&seqImpl.iteratorCapabilities, &oldIteratorCaps, sizeof(oldIteratorCaps));
QCOMPARE(seqImpl.revision, 0u);
}
void tst_QVariant::sequentialIterableAppend()
@ -4682,22 +4692,24 @@ void tst_QVariant::sequentialIterableAppend()
{
QList<int> container { 1, 2 };
auto variant = QVariant::fromValue(container);
QVERIFY(variant.canConvert<QtMetaTypePrivate::QSequentialIterableImpl>());
auto asIterable = variant.value<QtMetaTypePrivate::QSequentialIterableImpl>();
QVERIFY(variant.canConvert<QSequentialIterable>());
auto asIterable = variant.value<QSequentialIterable>();
const int i = 3, j = 4;
asIterable.append(&i);
asIterable.append(&j);
void *mutableIterable = const_cast<void *>(asIterable.constIterable());
asIterable.metaSequence().addElement(mutableIterable, &i);
asIterable.metaSequence().addElement(mutableIterable, &j);
QCOMPARE(variant.value<QList<int>>(), QList<int> ({ 1, 2, 3, 4 }));
}
{
QSet<QByteArray> container { QByteArray{"hello"}, QByteArray{"world"} };
auto variant = QVariant::fromValue(std::move(container));
QVERIFY(variant.canConvert<QtMetaTypePrivate::QSequentialIterableImpl>());
auto asIterable = variant.value<QtMetaTypePrivate::QSequentialIterableImpl>();
QVERIFY(variant.canConvert<QSequentialIterable>());
auto asIterable = variant.value<QSequentialIterable>();
QByteArray qba1 {"goodbye"};
QByteArray qba2 { "moon" };
asIterable.append( &qba1 );
asIterable.append( &qba2);
void *mutableIterable = const_cast<void *>(asIterable.constIterable());
asIterable.metaSequence().addElement(mutableIterable, &qba1);
asIterable.metaSequence().addElement(mutableIterable, &qba2);
QSet<QByteArray> reference { "hello", "world", "goodbye", "moon" };
QCOMPARE(variant.value<QSet<QByteArray>>(), reference);
}
@ -4707,8 +4719,8 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
{
using namespace QtMetaTypePrivate;
bool calledCorrectConverter = false;
QMetaType::registerConverter<MyType, QSequentialIterableImpl>([](const MyType &) {
return QSequentialIterableImpl {};
QMetaType::registerConverter<MyType, QSequentialIterable>([](const MyType &) {
return QSequentialIterable {};
});
QMetaType::registerConverter<MyType, QVariantList>([&calledCorrectConverter](const MyType &) {
calledCorrectConverter = true;
@ -4727,7 +4739,7 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
});
auto holder = QVariant::fromValue(MyType {});
QVERIFY(holder.canConvert<QSequentialIterableImpl>());
QVERIFY(holder.canConvert<QSequentialIterable>());
QVERIFY(holder.canConvert<QVariantList>());
QVERIFY(holder.canConvert<QAssociativeIterableImpl>());
QVERIFY(holder.canConvert<QVariantHash>());