Extend QSequentialIterable and add QAssociativeIterable

And add mutable iterators. This requires some refactoring of the
existing iterators.

Task-number: QTBUG-81716
Change-Id: I61b3a3e8c0df5fd449679257a29d9f0c3d19c4f0
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
bb10
Ulf Hermann 2020-09-10 18:25:02 +02:00
parent b30801f64d
commit 5c808073af
17 changed files with 2205 additions and 1166 deletions

View File

@ -70,6 +70,7 @@ qt_add_module(Core
itemmodels/qitemselectionmodel.cpp itemmodels/qitemselectionmodel.h itemmodels/qitemselectionmodel_p.h
kernel/qabstracteventdispatcher.cpp kernel/qabstracteventdispatcher.h kernel/qabstracteventdispatcher_p.h
kernel/qabstractnativeeventfilter.cpp kernel/qabstractnativeeventfilter.h
kernel/qassociativeiterable.cpp kernel/qassociativeiterable.h
kernel/qbasictimer.cpp kernel/qbasictimer.h
kernel/qcoreapplication.cpp kernel/qcoreapplication.h kernel/qcoreapplication_p.h
kernel/qcorecmdlineargs_p.h
@ -79,7 +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/qiterable.cpp kernel/qiterable.h kernel/qiterable_p.cpp kernel/qiterable_p.h
kernel/qmath.cpp kernel/qmath.h
kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h
@ -96,6 +97,7 @@ qt_add_module(Core
kernel/qpointer.cpp kernel/qpointer.h
kernel/qproperty.cpp kernel/qproperty.h kernel/qproperty_p.h
kernel/qpropertyprivate.h
kernel/qsequentialiterable.cpp kernel/qsequentialiterable.h
kernel/qsharedmemory.cpp kernel/qsharedmemory.h kernel/qsharedmemory_p.h
kernel/qsignalmapper.cpp kernel/qsignalmapper.h
kernel/qsocketnotifier.cpp kernel/qsocketnotifier.h

View File

@ -93,6 +93,7 @@ qt_add_module(Core
itemmodels/qitemselectionmodel.cpp itemmodels/qitemselectionmodel.h itemmodels/qitemselectionmodel_p.h
kernel/qabstracteventdispatcher.cpp kernel/qabstracteventdispatcher.h kernel/qabstracteventdispatcher_p.h
kernel/qabstractnativeeventfilter.cpp kernel/qabstractnativeeventfilter.h
kernel/qassociativeiterable.cpp kernel/qassociativeiterable.h
kernel/qbasictimer.cpp kernel/qbasictimer.h
kernel/qcoreapplication.cpp kernel/qcoreapplication.h kernel/qcoreapplication_p.h
kernel/qcorecmdlineargs_p.h
@ -102,7 +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/qiterable.cpp kernel/qiterable.h kernel/qiterable_p.cpp kernel/qiterable_p.h
kernel/qmath.cpp kernel/qmath.h
kernel/qmetacontainer.cpp kernel/qmetacontainer.h
kernel/qmetaobject.cpp kernel/qmetaobject.h kernel/qmetaobject_p.h
@ -118,6 +119,7 @@ qt_add_module(Core
kernel/qpointer.cpp kernel/qpointer.h
kernel/qproperty.cpp kernel/qproperty.h kernel/qproperty_p.h
kernel/qpropertyprivate.h
kernel/qsequentialiterable.cpp kernel/qsequentialiterable.h
kernel/qsharedmemory.cpp kernel/qsharedmemory.h kernel/qsharedmemory_p.h
kernel/qsignalmapper.cpp kernel/qsignalmapper.h
kernel/qsocketnotifier.cpp kernel/qsocketnotifier.h

View File

@ -36,6 +36,9 @@ HEADERS += \
kernel/qobject_p.h \
kernel/qcoreglobaldata_p.h \
kernel/qiterable.h \
kernel/qiterable_p.h \
kernel/qsequentialiterable.h \
kernel/qassociativeiterable.h \
kernel/qsharedmemory.h \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
@ -72,6 +75,9 @@ SOURCES += \
kernel/qvariant.cpp \
kernel/qcoreglobaldata.cpp \
kernel/qiterable.cpp \
kernel/qiterable_p.cpp \
kernel/qsequentialiterable.cpp \
kernel/qassociativeiterable.cpp \
kernel/qsharedmemory.cpp \
kernel/qsystemsemaphore.cpp \
kernel/qpointer.cpp \

View File

@ -0,0 +1,253 @@
/****************************************************************************
**
** 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/qassociativeiterable.h>
#include <QtCore/qvariant.h>
#include <QtCore/private/qiterable_p.h>
QT_BEGIN_NAMESPACE
/*!
Returns the key this iterator points to.
*/
QVariant QAssociativeIterator::key() const
{
return QIterablePrivate::retrieveElement(
metaContainer().keyMetaType(), [this](void *dataPtr) {
metaContainer().keyAtIterator(constIterator(), dataPtr);
});
}
/*!
Returns the mapped value this iterator points to. If the container does not
provide a mapped value (for example a set), returns an invalid QVariantRef.
*/
QVariantRef<QAssociativeIterator> QAssociativeIterator::value() const
{
const QMetaType mappedMetaType(metaContainer().mappedMetaType());
return QVariantRef<QAssociativeIterator>(mappedMetaType.isValid() ? this : nullptr);
}
/*!
Returns the current item, converted to a QVariantRef. The resulting
QVariantRef resolves to the mapped value if there is one, or to the key
value if not.
*/
QVariantRef<QAssociativeIterator> QAssociativeIterator::operator*() const
{
return QVariantRef<QAssociativeIterator>(this);
}
/*!
Returns the current item, converted to a QVariantPointer. The resulting
QVariantPointer resolves to the mapped value if there is one, or to the key
value if not.
*/
QVariantPointer<QAssociativeIterator> QAssociativeIterator::operator->() const
{
return QVariantPointer<QAssociativeIterator>(this);
}
/*!
Returns the key this iterator points to.
*/
QVariant QAssociativeConstIterator::key() const
{
return QIterablePrivate::retrieveElement(
metaContainer().keyMetaType(), [this](void *dataPtr) {
metaContainer().keyAtConstIterator(constIterator(), dataPtr);
});
}
/*!
Returns the mapped value this iterator points to, or an invalid QVariant if
there is no mapped value.
*/
QVariant QAssociativeConstIterator::value() const
{
return QIterablePrivate::retrieveElement(
metaContainer().mappedMetaType(), [this](void *dataPtr) {
metaContainer().mappedAtConstIterator(constIterator(), dataPtr);
});
}
/*!
Returns the current item, converted to a QVariant. The returned value is the
mapped value at the current iterator if there is one, or otherwise the key.
*/
QVariant QAssociativeConstIterator::operator*() const
{
const QMetaType mappedMetaType(metaContainer().mappedMetaType());
return mappedMetaType.isValid() ? value() : key();
}
/*!
Returns the current item, converted to a QVariantConstPointer. The
QVariantConstPointer will resolve to the mapped value at the current
iterator if there is one, or otherwise the key.
*/
QVariantConstPointer QAssociativeConstIterator::operator->() const
{
return QVariantConstPointer(operator*());
}
/*!
\class QAssociativeIterable
\since 5.2
\inmodule QtCore
\brief The QAssociativeIterable class is an iterable interface for an associative container in a QVariant.
This class allows several methods of accessing the elements of an associative container held within
a QVariant. An instance of QAssociativeIterable can be extracted from a QVariant if it can
be converted to a QVariantHash or QVariantMap or if a custom mutable view has been registered.
\snippet code/src_corelib_kernel_qvariant.cpp 10
The container itself is not copied before iterating over it.
\sa QVariant
*/
/*!
\typedef QAssociativeIterable::RandomAccessIterator
Exposes an iterator using std::random_access_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::BidirectionalIterator
Exposes an iterator using std::bidirectional_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::ForwardIterator
Exposes an iterator using std::forward_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::InputIterator
Exposes an iterator using std::input_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::RandomAccessConstIterator
Exposes a const_iterator using std::random_access_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::BidirectionalConstIterator
Exposes a const_iterator using std::bidirectional_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::ForwardConstIterator
Exposes a const_iterator using std::forward_iterator_tag.
*/
/*!
\typedef QAssociativeIterable::InputConstIterator
Exposes a const_iterator using std::input_iterator_tag.
*/
/*!
Retrieves a const_iterator pointing to the element at the given \a key, or
the end of the container if that key does not exist.
*/
QAssociativeIterable::const_iterator QAssociativeIterable::find(const QVariant &key) const
{
const QMetaAssociation meta = metaContainer();
QVariant converted = key;
const void *keyData = QIterablePrivate::coerceType(converted, meta.keyMetaType());
return const_iterator(QConstIterator(
this, meta.createConstIteratorAtKey(constIterable(), keyData)));
}
/*!
Retrieves an iterator pointing to the element at the given \a key, or
the end of the container if that key does not exist.
*/
QAssociativeIterable::iterator QAssociativeIterable::mutableFind(const QVariant &key)
{
const QMetaAssociation meta = metaContainer();
QVariant converted = key;
const void *keyData = QIterablePrivate::coerceType(converted, meta.keyMetaType());
return iterator(QIterator(this, meta.createIteratorAtKey(mutableIterable(), keyData)));
}
/*!
Retrieves the mapped value at the given \a key, or an invalid QVariant
if the key does not exist.
*/
QVariant QAssociativeIterable::value(const QVariant &key) const
{
const QMetaAssociation meta = metaContainer();
QVariant converted = key;
const void *keyData = QIterablePrivate::coerceType(converted, meta.keyMetaType());
QVariant result(QMetaType(meta.mappedMetaType()));
meta.mappedAtKey(constIterable(), keyData, result.data());
return result;
}
/*!
\class QAssociativeIterable::const_iterator
\since 5.2
\inmodule QtCore
\brief The QAssociativeIterable::const_iterator allows iteration over a container in a QVariant.
A QAssociativeIterable::const_iterator can only be created by a QAssociativeIterable instance,
and can be used in a way similar to other stl-style iterators.
\snippet code/src_corelib_kernel_qvariant.cpp 10
\sa QAssociativeIterable
*/
/*!
\class QAssociativeIterable::iterator
\since 6.0
\inmodule QtCore
\brief The QAssociativeIterable::iterator allows iteration over a container in a QVariant.
A QAssociativeIterable::iterator can only be created by a QAssociativeIterable instance,
and can be used in a way similar to other stl-style iterators.
\sa QAssociativeIterable
*/
QT_END_NAMESPACE

View File

@ -0,0 +1,194 @@
/****************************************************************************
**
** 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 QASSOCIATIVEITERABLE_H
#define QASSOCIATIVEITERABLE_H
#include <QtCore/qiterable.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QAssociativeIterator : public QIterator<QMetaAssociation>
{
public:
using key_type = QVariant;
using mapped_type = QVariant;
using reference = QVariantRef<QAssociativeIterator>;
using pointer = QVariantPointer<QAssociativeIterator>;
QAssociativeIterator(QIterator &&it)
: QIterator(std::move(it))
{}
QVariant key() const;
QVariantRef<QAssociativeIterator> value() const;
QVariantRef<QAssociativeIterator> operator*() const;
QVariantPointer<QAssociativeIterator> operator->() const;
};
class Q_CORE_EXPORT QAssociativeConstIterator : public QConstIterator<QMetaAssociation>
{
public:
using key_type = QVariant;
using mapped_type = QVariant;
using reference = const QVariant &;
using pointer = QVariantConstPointer;
QAssociativeConstIterator(QConstIterator &&it)
: QConstIterator(std::move(it))
{}
QVariant key() const;
QVariant value() const;
QVariant operator*() const;
QVariantConstPointer operator->() const;
};
class Q_CORE_EXPORT QAssociativeIterable : public QIterable<QMetaAssociation>
{
public:
using iterator = QTaggedIterator<QAssociativeIterator, void>;
using const_iterator = QTaggedIterator<QAssociativeConstIterator, void>;
using RandomAccessIterator = QTaggedIterator<iterator, std::random_access_iterator_tag>;
using BidirectionalIterator = QTaggedIterator<iterator, std::bidirectional_iterator_tag>;
using ForwardIterator = QTaggedIterator<iterator, std::forward_iterator_tag>;
using InputIterator = QTaggedIterator<iterator, std::input_iterator_tag>;
using RandomAccessConstIterator = QTaggedIterator<const_iterator, std::random_access_iterator_tag>;
using BidirectionalConstIterator = QTaggedIterator<const_iterator, std::bidirectional_iterator_tag>;
using ForwardConstIterator = QTaggedIterator<const_iterator, std::forward_iterator_tag>;
using InputConstIterator = QTaggedIterator<const_iterator, std::input_iterator_tag>;
template<class T>
QAssociativeIterable(const T *p)
: QIterable(QMetaAssociation::fromContainer<T>(), p)
{
}
template<class T>
QAssociativeIterable(T *p)
: QIterable(QMetaAssociation::fromContainer<T>(), p)
{
}
QAssociativeIterable() = default;
template<typename Pointer>
QAssociativeIterable(const QMetaAssociation &metaAssociation, Pointer iterable)
: QIterable(metaAssociation, iterable)
{
}
QAssociativeIterable(const QMetaAssociation &metaSequence, const QMetaType &metaType,
void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
{
}
QAssociativeIterable(const QMetaAssociation &metaSequence, const QMetaType &metaType,
const void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
{
}
QAssociativeIterable(QIterable<QMetaAssociation> &&other) : QIterable(std::move(other)) {}
QAssociativeIterable &operator=(QIterable<QMetaAssociation> &&other)
{
QIterable::operator=(std::move(other));
return *this;
}
const_iterator begin() const { return constBegin(); }
const_iterator end() const { return constEnd(); }
const_iterator constBegin() const { return const_iterator(QIterable::constBegin()); }
const_iterator constEnd() const { return const_iterator(QIterable::constEnd()); }
iterator mutableBegin() { return iterator(QIterable::mutableBegin()); }
iterator mutableEnd() { return iterator(QIterable::mutableEnd()); }
const_iterator find(const QVariant &key) const;
const_iterator constFind(const QVariant &key) const { return find(key); }
iterator mutableFind(const QVariant &key);
QVariant value(const QVariant &key) const;
};
template<>
inline QVariantRef<QAssociativeIterator>::operator QVariant() const
{
if (m_pointer == nullptr)
return QVariant();
const auto metaAssociation = m_pointer->metaContainer();
QMetaType metaType(metaAssociation.mappedMetaType());
if (!metaType.isValid())
return m_pointer->key();
QVariant v(metaType);
void *dataPtr = metaType == QMetaType::fromType<QVariant>() ? &v : v.data();
metaAssociation.mappedAtIterator(m_pointer->constIterator(), dataPtr);
return v;
}
template<>
inline QVariantRef<QAssociativeIterator> &QVariantRef<QAssociativeIterator>::operator=(
const QVariant &value)
{
if (m_pointer == nullptr)
return *this;
const QMetaType metaType(m_pointer->metaContainer().mappedMetaType());
const void *dataPtr = metaType == QMetaType::fromType<QVariant>()
? &value
: value.constData();
m_pointer->metaContainer().setMappedAtIterator(m_pointer->constIterator(), dataPtr);
return *this;
}
Q_DECLARE_TYPEINFO(QAssociativeIterable, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QAssociativeIterable::iterator, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QAssociativeIterable::const_iterator, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QASSOCIATIVEITERABLE_H

View File

@ -38,271 +38,155 @@
****************************************************************************/
#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.
\class QBaseIterator
This class allows several methods of accessing the values 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
QBaseIterator forms the common base class for all iterators operating on
subclasses of QIterable.
*/
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.constPointer()));
}
/*!
Returns a QSequentialIterable::const_iterator for the end of the container. This
can be used in stl-style iteration.
\fn QBaseIterator::QBaseIterator(const QIterable *iterable, void *iterator)
\sa begin()
*/
QSequentialIterable::const_iterator QSequentialIterable::end() const
{
return const_iterator(this, m_metaSequence.constEnd(m_iterable.constPointer()));
}
/*!
Returns the value 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.canGetValueAtIndex()) {
metaSequence.valueAtIndex(m_iterable.constPointer(), idx, dataPtr);
} else if (metaSequence.canGetValueAtConstIterator()) {
void *iterator = metaSequence.constBegin(m_iterable.constPointer());
metaSequence.advanceConstIterator(iterator, idx);
metaSequence.valueAtConstIterator(iterator, dataPtr);
metaSequence.destroyConstIterator(iterator);
}
return v;
}
/*!
Returns the number of values in the container.
*/
qsizetype QSequentialIterable::size() const
{
const QMetaSequence metaSequence = m_metaSequence;
const void *container = m_iterable.constPointer();
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;
}
/*!
* Adds \a value to the container, at \a position, if possible.
\internal
Creates a const QBaseIterator from an \a iterable and an \a iterator.
*/
void QSequentialIterable::addValue(const QVariant &value, Position position)
{
QVariant converted;
const void *valuePtr;
if (valueMetaType() == QMetaType::fromType<QVariant>()) {
valuePtr = &value;
} else if (valueMetaType() == value.metaType()) {
valuePtr = value.constData();
} else if (value.canConvert(valueMetaType())) {
converted = value;
converted.convert(valueMetaType());
valuePtr = converted.constData();
} else {
converted = QVariant(valueMetaType());
valuePtr = converted.constData();
}
switch (position) {
case AtBegin:
if (metaSequence().canAddValueAtBegin())
metaSequence().addValueAtBegin(mutableIterable(), valuePtr);
break;
case AtEnd:
if (metaSequence().canAddValueAtEnd())
metaSequence().addValueAtEnd(mutableIterable(), valuePtr);
break;
case Unspecified:
if (metaSequence().canAddValue())
metaSequence().addValue(mutableIterable(), valuePtr);
break;
}
}
/*!
* Removes a value from the container, at \a position, if possible.
\fn QBaseIterator::QBaseIterator(QIterable *iterable, void *iterator)
\internal
Creates a non-const QBaseIterator from an \a iterable and an \a iterator.
*/
void QSequentialIterable::removeValue(Position position)
{
switch (position) {
case AtBegin:
if (metaSequence().canRemoveValueAtBegin())
metaSequence().removeValueAtBegin(mutableIterable());
break;
case AtEnd:
if (metaSequence().canRemoveValueAtEnd())
metaSequence().removeValueAtEnd(mutableIterable());
break;
case Unspecified:
if (metaSequence().canRemoveValue())
metaSequence().removeValue(mutableIterable());
break;
}
}
/*!
Returns whether it is possible to iterate over the container in forward
direction. This corresponds to the std::forward_iterator_tag iterator trait
of the iterator and const_iterator of the container.
*/
bool QSequentialIterable::canForwardIterate() const
{
return m_metaSequence.hasForwardIterator();
}
\fn QBaseIterator::QBaseIterator(QBaseIterator &&other)
\internal
Move-constructs a QBaseIterator from \a other, preserving its const-ness.
*/
/*!
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();
}
\fn QBaseIterator::QBaseIterator(const QBaseIterator &other)
\internal
Copy-constructs a QBaseIterator from \a other, preserving its const-ness.
*/
/*!
\class QSequentialIterable::const_iterator
\since 5.2
\fn QBaseIterator::~QBaseIterator()
\internal
Destroys a QBaseIterator.
*/
/*!
\fn QBaseIterator &QBaseIterator::operator=(const QBaseIterator &other)
\internal
Copy-assigns a QBaseIterator from \a other, preserving its const-ness.
*/
/*!
\fn void QBaseIterator::initIterator(const void *copy)
\internal
Initializes the internal native iterator by duplicating \a copy, if given.
*/
/*!
\fn void QBaseIterator::clearIterator()
\internal
Destroys the internal native iterator.
*/
/*!
\fn QMetaContainer QBaseIterator::metaContainer() const
\internal
Returns the meta sequence.
*/
/*!
\fn QIterable *QBaseIterator::mutableIterable() const
\internal
Returns a non-const pointer to the iterable, if the original iterable was
non-const. Otherwise returns nullptr.
*/
/*!
\fn const QIterable *QBaseIterator::constIterable() const
\internal
Returns a const pointer to the iterable.
*/
/*!
\fn void *QBaseIterator::mutableIterator()
Returns a non-const pointer to the internal native iterator.
*/
/*!
\fn const void *QBaseIterator::constIterator() const
Returns a const pointer to the internal native iterator.
*/
/*!
\fn QBaseIterator &QBaseIterator::operator=(QBaseIterator &&other)
\internal
Move-assigns a QBaseIterator from \a other, preserving its const-ness.
*/
/*!
\class Qiterator
\since 6.0
\inmodule QtCore
\brief The QSequentialIterable::const_iterator allows iteration over a container in a QVariant.
\brief The QIterator 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.
A QIterator can only be created by a QIterable instance, and can be used
in a way similar to other stl-style iterators. Generally, QIterator should
not be used directly, but through its derived classes provided by
QSequentialIterable and QAssociativeIterable.
\snippet code/src_corelib_kernel_qvariant.cpp 9
\sa QSequentialIterable
\sa QIterable
*/
/*!
\fn QIterator::QIterator(QIterable *iterable, void *iterator)
Creates an iterator from an \a iterable and a pointer to a native \a iterator.
*/
/*!
Destroys the QSequentialIterable::const_iterator.
*/
QSequentialIterable::const_iterator::~const_iterator() {
if (!m_ref->deref()) {
m_iterable->m_metaSequence.destroyConstIterator(m_iterator);
delete m_ref;
}
}
\fn bool QIterator::operator==(const QIterator &other) const
/*!
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.valueAtConstIterator(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);
}
/*!
\fn bool QIterator::operator!=(const QIterator &other) const
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);
}
/*!
\fn QIterator &QIterator::operator++()
The prefix ++ operator (\c{++it}) advances the iterator to the
next item in the container and returns an iterator to the new current
item.
@ -311,30 +195,20 @@ bool QSequentialIterable::const_iterator::operator!=(const const_iterator &other
\sa operator--()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator++()
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, 1);
return *this;
}
/*!
\fn QIterator QIterator::operator++(int)
\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.constPointer()));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, 1);
return result;
}
/*!
\fn QIterator &QIterator::operator--()
The prefix -- operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
@ -345,13 +219,10 @@ QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operato
\sa operator++(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator--()
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -1);
return *this;
}
/*!
\fn QIterator QIterator::operator--(int)
\overload
The postfix -- operator (\c{it--}) makes the preceding item
@ -362,28 +233,18 @@ QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operat
\sa canReverseIterate()
*/
QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator--(int)
{
const_iterator result(
m_iterable,
m_iterable->m_metaSequence.constBegin(m_iterable->m_iterable.constPointer()));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -1);
return result;
}
/*!
\fn QIterator &QIterator::operator+=(qsizetype j)
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;
}
/*!
\fn QIterator &QIterator::operator-=(qsizetype j)
Makes the iterator go back by \a j items.
If the container in the QVariant does not support bi-directional iteration, calling this function
@ -391,29 +252,19 @@ QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operat
\sa operator+=(), operator-(), canReverseIterate()
*/
QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator-=(int j)
{
m_iterable->m_metaSequence.advanceConstIterator(m_iterator, -j);
return *this;
}
/*!
\fn QIterator QIterator::operator+(qsizetype j) const
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.constPointer()));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(result.m_iterator, j);
return result;
}
/*!
\fn QIterator QIterator::operator-(qsizetype j) const
Returns an iterator to the item at \a j positions backward from
this iterator.
@ -422,14 +273,353 @@ QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operato
\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.constPointer()));
m_iterable->m_metaSequence.copyConstIterator(result.m_iterator, m_iterator);
m_iterable->m_metaSequence.advanceConstIterator(result.m_iterator, -j);
return result;
}
/*!
\fn qsizetype QIterator::operator-(const QIterator &j) const
Returns the distance between the two iterators.
\sa operator+(), operator-=(), canReverseIterator()
*/
/*!
QConstIterator::QConstIterator(const QIterable *iterable, void *iterator)
Creates a QConstIterator to wrap \a iterator, operating on \a iterable.
*/
/*!
bool QConstIterator::operator==(const QConstIterator &other) const
Returns \c true if \a other points to the same item as this
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
bool QConstIterator::operator!=(const QConstIterator &other) const
Returns \c true if \a other points to a different item than this
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
\fn QConstIterator &QConstIterator::operator++()
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 QIterable::end() leads to undefined results.
\sa operator--()
*/
/*!
\fn QConstIterator QConstIterator::operator++(int)
\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.
*/
/*!
\fn QConstIterator &QConstIterator::operator--()
The prefix -- operator (\c{--it}) makes the preceding item
current and returns an iterator to the new current item.
Calling this function on QIterable::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()
*/
/*!
\fn QConstIterator QConstIterator::operator--(int)
\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()
*/
/*!
\fn QConstIterator &QConstIterator::operator+=(qsizetype j)
Advances the iterator by \a j items.
\sa operator-=(), operator+()
*/
/*!
\fn QConstIterator &QConstIterator::operator-=(qsizetype j)
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()
*/
/*!
\fn QConstIterator QConstIterator::operator+(qsizetype j) const
Returns an iterator to the item at \a j positions forward from
this iterator.
\sa operator-(), operator+=()
*/
/*!
\fn QConstIterator QConstIterator::operator-(qsizetype j) const
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()
*/
/*!
\fn qsizetype QConstIterator::operator-(const QConstIterator &j) const
Returns the distance between the two iterators.
\sa operator+(), operator-=(), canReverseIterator()
*/
/*!
\class QIterable
\since 6.0
QIterable is the base class for QSequentialIterable and QAssociativeIterable.
*/
/*!
\fn bool QIterable::canInputIterate() const
Returns whether the container has an input iterator. This corresponds to
the std::input_iterator_tag iterator trait of the iterator and
const_iterator of the container.
*/
/*!
\fn bool QIterable::canForwardIterate() const
Returns whether it is possible to iterate over the container in forward
direction. This corresponds to the std::forward_iterator_tag iterator trait
of the iterator and const_iterator of the container.
*/
/*!
\fn bool QIterable::canReverseIterate() const
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.
*/
/*!
\fn bool QIterable::canRandomAccessIterate() const
Returns whether it is possible to efficiently skip over multiple values
using and iterator. This corresponds to the std::random_access_iterator_tag
iterator trait of the iterator and const_iterator of the container.
*/
/*!
\fn QConstIterator QIterable::constBegin() const
Returns a QConstIterator for the beginning of the container. This
can be used in stl-style iteration.
\sa end()
*/
/*!
\fn QConstIterator QIterable::constEnd() const
Returns a Qterable::QConstIterator for the end of the container. This
can be used in stl-style iteration.
\sa begin()
*/
/*!
\fn QIterator QIterable::mutableBegin()
Returns a QIterator for the beginning of the container. This
can be used in stl-style iteration.
\sa end()
*/
/*!
\fn QIterator QIterable::mutableEnd()
Returns a QSequentialIterable::iterator for the end of the container. This
can be used in stl-style iteration.
\sa begin()
*/
/*!
\fn qsizetype QIterable::size() const
Returns the number of values in the container.
*/
/*!
\class QTaggedIterator
\since 6.0
\inmodule QtCore
\brief Wraps an iterator and exposes standard iterator traits.
In order to use an iterator any of the standard algorithms, it iterator
traits need to be known. As QSequentialIterable can work with many different
kinds of containers, we cannot declare the traits in the iterator classes
themselves. StdIterator gives you a way to explicitly declare a trait for
a concrete instance of an iterator or QConstIterator.
*/
/*!
\fn QTaggedIterator::StdIterator(Iterator &&it)
Constructs a StdIterator from an iterator or QConstIterator \a it. Checks
whether the IteratorCategory passed as template argument matches the run
time capabilities of \a it and refuses \a it if not.
*/
/*!
\fn bool QTaggedIterator::operator==(const StdIterator &other) const
Returns \c true if \a other points to the same item as this
iterator; otherwise returns \c false.
\sa operator!=()
*/
/*!
\fn bool QTaggedIterator::operator!=(const StdIterator &other) const
Returns \c true if \a other points to a different item than this
iterator; otherwise returns \c false.
\sa operator==()
*/
/*!
\fn QTaggedIterator &QTaggedIterator::operator++()
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--()
*/
/*!
\fn QTaggedIterator QTaggedIterator::operator++(int)
\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.
*/
/*!
\fn QTaggedIterator &QTaggedIterator::operator--()
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()
*/
/*!
\fn QTaggedIterator QTaggedIterator::operator--(int)
\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()
*/
/*!
\fn QTaggedIterator &QTaggedIterator::operator+=(qsizetype j)
Advances the iterator by \a j items.
\sa operator-=(), operator+()
*/
/*!
\fn QTaggedIterator &QTaggedIterator::operator-=(qsizetype j)
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()
*/
/*!
\fn QTaggedIterator QTaggedIterator::operator+(qsizetype j) const
Returns an iterator to the item at \a j positions forward from
this iterator.
\sa operator-(), operator+=()
*/
/*!
\fn QTaggedIterator QTaggedIterator::operator-(qsizetype j) const
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()
*/
/*!
\fn qsizetype QTaggedIterator::operator-(const QTaggedIterator &j) const
Returns the distance between the two iterators.
\sa operator+(), operator-=(), canReverseIterator()
*/
QT_END_NAMESPACE

View File

@ -43,7 +43,6 @@
#include <QtCore/qglobal.h>
#include <QtCore/qtypeinfo.h>
#include <QtCore/qmetacontainer.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qtaggedpointer.h>
QT_BEGIN_NAMESPACE
@ -100,115 +99,454 @@ namespace QtPrivate {
};
}
class Q_CORE_EXPORT QSequentialIterable
template<class Iterator, typename IteratorCategory>
class QTaggedIterator : public Iterator
{
uint m_revision = 0;
QtPrivate::QConstPreservingPointer<void, quint16> m_iterable;
QMetaSequence m_metaSequence;
public:
using iterator_category = IteratorCategory;
QTaggedIterator(Iterator &&it) : Iterator(std::move(it))
{
const QMetaContainer metaContainer = this->metaContainer();
if (std::is_base_of_v<std::random_access_iterator_tag, IteratorCategory>
&& !metaContainer.hasRandomAccessIterator()) {
qFatal("You cannot use this iterator as a random access iterator");
this->clearIterator();
}
if (std::is_base_of_v<std::bidirectional_iterator_tag, IteratorCategory>
&& !metaContainer.hasBidirectionalIterator()) {
qFatal("You cannot use this iterator as a bidirectional iterator");
this->clearIterator();
}
if (std::is_base_of_v<std::forward_iterator_tag, IteratorCategory>
&& !metaContainer.hasForwardIterator()) {
qFatal("You cannot use this iterator as a forward iterator");
this->clearIterator();
}
if (std::is_base_of_v<std::input_iterator_tag, IteratorCategory>
&& !metaContainer.hasInputIterator()) {
qFatal("You cannot use this iterator as an input iterator");
this->clearIterator();
}
}
bool operator==(const QTaggedIterator &o) const { return Iterator::operator==(o); }
bool operator!=(const QTaggedIterator &o) const { return Iterator::operator!=(o); }
QTaggedIterator &operator++() { Iterator::operator++(); return *this; }
QTaggedIterator operator++(int x) { return QTaggedIterator(Iterator::operator++(x)); };
QTaggedIterator &operator--() { Iterator::operator--(); return *this; }
QTaggedIterator operator--(int x) { return QTaggedIterator(Iterator::operator--(x)); };
QTaggedIterator &operator+=(qsizetype j) { Iterator::operator+=(j); return *this; }
QTaggedIterator &operator-=(qsizetype j) { Iterator::operator-=(j); return *this; }
QTaggedIterator operator+(qsizetype j) const { return QTaggedIterator(Iterator::operator+(j)); }
QTaggedIterator operator-(qsizetype j) const { return QTaggedIterator(Iterator::operator-(j)); }
qsizetype operator-(const QTaggedIterator &j) const { return Iterator::operator-(j); }
bool operator<(const QTaggedIterator &j) { return operator-(j) < 0; }
bool operator>=(const QTaggedIterator &j) { return !operator<(j); }
bool operator>(const QTaggedIterator &j) { return operator-(j) > 0; }
bool operator<=(const QTaggedIterator &j) { return !operator>(j); }
friend inline QTaggedIterator operator+(qsizetype j, const QTaggedIterator &k) { return k + j; }
};
template<class Container>
class QIterable;
template<class Container>
class QBaseIterator
{
private:
QtPrivate::QConstPreservingPointer<QIterable<Container>> m_iterable;
void *m_iterator = nullptr;
protected:
QBaseIterator() = default;
QBaseIterator(const QIterable<Container> *iterable, void *iterator)
: m_iterable(iterable), m_iterator(iterator)
{}
QBaseIterator(QIterable<Container> *iterable, void *iterator)
: m_iterable(iterable), m_iterator(iterator)
{}
QBaseIterator(QBaseIterator &&other)
: m_iterable(std::move(other.m_iterable)), m_iterator(std::move(other.m_iterator))
{
other.m_iterator = nullptr;
}
QBaseIterator(const QBaseIterator &other)
: m_iterable(other.m_iterable)
{
initIterator(other.m_iterator);
}
~QBaseIterator() { clearIterator(); }
QBaseIterator &operator=(QBaseIterator &&other)
{
if (this != &other) {
clearIterator();
m_iterable = std::move(other.m_iterable);
m_iterator = std::move(other.m_iterator);
other.m_iterator = nullptr;
}
return *this;
}
QBaseIterator &operator=(const QBaseIterator &other)
{
if (this != &other) {
clearIterator();
m_iterable = other.m_iterable;
initIterator(other.m_iterator);
}
return *this;
}
QIterable<Container> *mutableIterable() const
{
return m_iterable.mutablePointer();
}
const QIterable<Container> *constIterable() const
{
return m_iterable.constPointer();
}
void initIterator(const void *copy)
{
if (!copy)
return;
if (auto *mutableIt = mutableIterable()) {
m_iterator = metaContainer().begin(mutableIt->mutableIterable());
metaContainer().copyIterator(m_iterator, copy);
} else if (auto *constIt = constIterable()) {
m_iterator = metaContainer().constBegin(constIt->constIterable());
metaContainer().copyConstIterator(m_iterator, copy);
}
}
void clearIterator()
{
if (!m_iterator)
return;
if (mutableIterable())
metaContainer().destroyIterator(m_iterator);
else
metaContainer().destroyConstIterator(m_iterator);
}
public:
struct Q_CORE_EXPORT const_iterator
void *mutableIterator() { return m_iterator; }
const void *constIterator() const { return m_iterator; }
Container metaContainer() const { return constIterable()->m_metaContainer; }
};
template<class Container>
struct QIterator : public QBaseIterator<Container>
{
public:
using difference_type = qsizetype;
explicit QIterator(QIterable<Container> *iterable, void *iterator)
: QBaseIterator<Container>(iterable, iterator)
{
private:
const QSequentialIterable *m_iterable = nullptr;
void *m_iterator = nullptr;
QAtomicInt *m_ref = nullptr;
Q_ASSERT(iterable != nullptr);
}
friend class QSequentialIterable;
explicit const_iterator(const QSequentialIterable *iterable, void *iterator);
bool operator==(const QIterator &o) const
{
return this->metaContainer().compareIterator(this->constIterator(), o.constIterator());
}
public:
~const_iterator();
bool operator!=(const QIterator &o) const
{
return !this->metaContainer().compareIterator(this->constIterator(), o.constIterator());
}
const_iterator(const const_iterator &other);
QIterator &operator++()
{
this->metaContainer().advanceIterator(this->mutableIterator(), 1);
return *this;
}
const_iterator& operator=(const const_iterator &other);
QIterator operator++(int)
{
QIterable<Container> *iterable = this->mutableIterable();
const Container metaContainer = this->metaContainer();
QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceIterator(this->mutableIterator(), 1);
return result;
}
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; }
};
QIterator &operator--()
{
this->metaContainer().advanceIterator(this->mutableIterator(), -1);
return *this;
}
friend struct const_iterator;
QIterator operator--(int)
{
QIterable<Container> *iterable = this->mutableIterable();
const Container metaContainer = this->metaContainer();
QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceIterator(this->mutableIterator(), -1);
return result;
}
QIterator &operator+=(qsizetype j)
{
this->metaContainer().advanceIterator(this->mutableIterator(), j);
return *this;
}
QIterator &operator-=(qsizetype j)
{
this->metaContainer().advanceIterator(this->mutableIterator(), -j);
return *this;
}
QIterator operator+(qsizetype j) const
{
QIterable<Container> *iterable = this->mutableIterable();
const Container metaContainer = this->metaContainer();
QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceIterator(result.mutableIterator(), j);
return result;
}
QIterator operator-(qsizetype j) const
{
QIterable<Container> *iterable = this->mutableIterable();
const Container metaContainer = this->metaContainer();
QIterator result(iterable, metaContainer.begin(iterable->mutableIterable()));
metaContainer.copyIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceIterator(result.mutableIterator(), -j);
return result;
}
qsizetype operator-(const QIterator &j) const
{
return this->metaContainer().diffIterator(this->constIterator(), j.constIterator());
}
friend inline QIterator operator+(qsizetype j, const QIterator &k) { return k + j; }
};
template<class Container>
struct QConstIterator : public QBaseIterator<Container>
{
public:
using difference_type = qsizetype;
explicit QConstIterator(const QIterable<Container> *iterable, void *iterator)
: QBaseIterator<Container>(iterable, iterator)
{
}
bool operator==(const QConstIterator &o) const
{
return this->metaContainer().compareConstIterator(
this->constIterator(), o.constIterator());
}
bool operator!=(const QConstIterator &o) const
{
return !this->metaContainer().compareConstIterator(
this->constIterator(), o.constIterator());
}
QConstIterator &operator++()
{
this->metaContainer().advanceConstIterator(this->mutableIterator(), 1);
return *this;
}
QConstIterator operator++(int)
{
const Container metaContainer = this->metaContainer();
QConstIterator result(this->constIterable(), metaContainer.constBegin(
this->constIterable()->constIterable()));
metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceConstIterator(this->mutableIterator(), 1);
return result;
}
QConstIterator &operator--()
{
this->metaContainer().advanceConstIterator(this->mutableIterator(), -1);
return *this;
}
QConstIterator operator--(int)
{
const Container metaContainer = this->metaContainer();
QConstIterator result(this->constIterable(), metaContainer.constBegin(
this->constIterable()->constIterable()));
metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceConstIterator(this->mutableIterator(), -1);
return result;
}
QConstIterator &operator+=(qsizetype j)
{
this->metaContainer().advanceConstIterator(this->mutableIterator(), j);
return *this;
}
QConstIterator &operator-=(qsizetype j)
{
this->metaContainer().advanceConstIterator(this->mutableIterator(), -j);
return *this;
}
QConstIterator operator+(qsizetype j) const
{
const Container metaContainer = this->metaContainer();
QConstIterator result(
this->constIterable(),
metaContainer.constBegin(this->constIterable()->constIterable()));
metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceConstIterator(result.mutableIterator(), j);
return result;
}
QConstIterator operator-(qsizetype j) const
{
const Container metaContainer = this->metaContainer();
QConstIterator result(this->constIterable(), metaContainer.constBegin(
this->constIterable()->constIterable()));
metaContainer.copyConstIterator(result.mutableIterator(), this->constIterator());
metaContainer.advanceConstIterator(result.mutableIterator(), -j);
return result;
}
qsizetype operator-(const QConstIterator &j) const
{
return this->metaContainer().diffIterator(this->constIterator(), j.constIterator());
}
friend inline QConstIterator operator+(qsizetype j, const QConstIterator &k)
{
return k + j;
}
};
template<class Container>
class QIterable
{
friend class QBaseIterator<Container>;
protected:
uint m_revision = 0;
QtPrivate::QConstPreservingPointer<void, quint16> m_iterable;
Container m_metaContainer;
public:
QIterable() = default;
template<class T>
QSequentialIterable(const T *p)
: m_iterable(p)
, m_metaSequence(QMetaSequence::fromContainer<T>())
QIterable(const Container &metaContainer, const T *p)
: m_iterable(p), m_metaContainer(metaContainer)
{
Q_UNUSED(m_revision);
}
QSequentialIterable() = default;
template<class T>
QIterable(const Container &metaContainer, T *p)
: m_iterable(p), m_metaContainer(metaContainer)
{
}
template<typename Pointer>
QSequentialIterable(const QMetaSequence &metaSequence, Pointer iterable)
: m_iterable(iterable)
, m_metaSequence(metaSequence)
QIterable(const Container &metaContainer, Pointer iterable)
: m_iterable(iterable), m_metaContainer(metaContainer)
{
}
const_iterator begin() const;
const_iterator end() const;
QIterable(const Container &metaContainer, qsizetype alignment, const void *p)
: m_iterable(p, alignment), m_metaContainer(metaContainer)
{
}
QVariant at(qsizetype idx) const;
qsizetype size() const;
QIterable(const Container &metaContainer, qsizetype alignment, void *p)
: m_iterable(p, alignment), m_metaContainer(metaContainer)
{
}
enum Position { Unspecified, AtBegin, AtEnd };
void addValue(const QVariant &value, Position position = Unspecified);
void removeValue(Position position = Unspecified);
bool canInputIterate() const
{
return m_metaContainer.hasInputIterator();
}
bool canForwardIterate() const;
bool canReverseIterate() const;
bool canForwardIterate() const
{
return m_metaContainer.hasForwardIterator();
}
bool canReverseIterate() const
{
return m_metaContainer.hasBidirectionalIterator();
}
bool canRandomAccessIterate() const
{
return m_metaContainer.hasRandomAccessIterator();
}
const void *constIterable() const { return m_iterable.constPointer(); }
// TODO: fix this when introducing mutable iterables
void *mutableIterable() { return const_cast<void *>(m_iterable.constPointer()); }
QMetaSequence metaSequence() const { return m_metaSequence; }
QMetaType valueMetaType() const { return m_metaSequence.valueMetaType(); }
};
namespace QtPrivate {
template<typename From>
struct QSequentialIterableConvertFunctor
{
QSequentialIterable operator()(const From &f) const
QConstIterator<Container> constBegin() const
{
return QSequentialIterable(&f);
return QConstIterator(this, m_metaContainer.constBegin(constIterable()));
}
};
template<typename T>
struct SequentialValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
QConstIterator<Container> constEnd() const
{
const int toId = qMetaTypeId<QSequentialIterable>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QSequentialIterable>(o);
}
return true;
return QConstIterator(this, m_metaContainer.constEnd(constIterable()));
}
QIterator<Container> mutableBegin()
{
return QIterator(this, m_metaContainer.begin(mutableIterable()));
}
QIterator<Container> mutableEnd()
{
return QIterator(this, m_metaContainer.end(mutableIterable()));
}
qsizetype size() const
{
const void *container = constIterable();
if (m_metaContainer.hasSize())
return m_metaContainer.size(container);
if (!m_metaContainer.hasConstIterator())
return -1;
const void *begin = m_metaContainer.constBegin(container);
const void *end = m_metaContainer.constEnd(container);
const qsizetype size = m_metaContainer.diffConstIterator(end, begin);
m_metaContainer.destroyConstIterator(begin);
m_metaContainer.destroyConstIterator(end);
return size;
}
Container metaContainer() const
{
return m_metaContainer;
};
};
}
Q_DECLARE_TYPEINFO(QSequentialIterable, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::const_iterator, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QITERABLE_H

View File

@ -0,0 +1,63 @@
/****************************************************************************
**
** 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/private/qiterable_p.h>
QT_BEGIN_NAMESPACE
namespace QIterablePrivate {
const void *coerceType(QVariant &value, const QMetaType &type)
{
if (type == QMetaType::fromType<QVariant>()) {
return &value;
} else if (type == value.metaType()) {
return value.constData();
} else if (value.canConvert(type)) {
value.convert(type);
return value.constData();
}
value = QVariant(type);
return value.constData();
}
} // namespace QIterablePrivate
QT_END_NAMESPACE

View File

@ -0,0 +1,80 @@
/****************************************************************************
**
** 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_P_H
#define QITERABLE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QtCore/qglobal.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
namespace QIterablePrivate {
const void *coerceType(QVariant &value, const QMetaType &type);
template<typename Callback>
static QVariant retrieveElement(const QMetaType &type, Callback callback)
{
QVariant v(type);
void *dataPtr;
if (type == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
callback(dataPtr);
return v;
}
} // namespace QIterablePrivate
QT_END_NAMESPACE
#endif // QITERABLE_P_H

View File

@ -54,7 +54,6 @@
#include "quuid.h"
#include "qvariant.h"
#include "qdatastream.h"
#include "qiterable.h"
#if QT_CONFIG(regularexpression)
# include "qregularexpression.h"
@ -73,6 +72,8 @@
# include "qcbormap.h"
# include "qbytearraylist.h"
# include "qmetaobject.h"
# include "qsequentialiterable.h"
# include "qassociativeiterable.h"
#endif
#if QT_CONFIG(itemmodel)
@ -1829,11 +1830,12 @@ static bool convertToEnum(QMetaType fromType, const void *from, QMetaType toType
}
}
#ifndef QT_BOOTSTRAPPED
static bool convertIterableToVariantList(QMetaType fromType, const void *from, void *to)
{
const QMetaType::ConverterFunction * const f =
customTypesConversionRegistry()->function(qMakePair(fromType.id(),
qMetaTypeId<QSequentialIterable>()));
customTypesConversionRegistry()->function(
qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaSequence>>()));
if (!f)
return false;
@ -1851,14 +1853,13 @@ static bool convertIterableToVariantList(QMetaType fromType, const void *from, v
static bool convertIterableToVariantMap(QMetaType fromType, const void *from, void *to)
{
const QMetaType::ConverterFunction * const f =
customTypesConversionRegistry()->function(qMakePair(fromType.id(),
qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()));
customTypesConversionRegistry()->function(
qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaAssociation>>()));
if (!f)
return false;
QtMetaTypePrivate::QAssociativeIterableImpl iter;
(*f)(from, &iter);
QAssociativeIterable map(iter);
QAssociativeIterable map;
(*f)(from, &map);
QVariantMap &h = *static_cast<QVariantMap *>(to);
h.clear();
auto end = map.end();
@ -1870,14 +1871,13 @@ static bool convertIterableToVariantMap(QMetaType fromType, const void *from, vo
static bool convertIterableToVariantHash(QMetaType fromType, const void *from, void *to)
{
const QMetaType::ConverterFunction * const f =
customTypesConversionRegistry()->function(qMakePair(fromType.id(),
qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()));
customTypesConversionRegistry()->function(
qMakePair(fromType.id(), qMetaTypeId<QIterable<QMetaAssociation>>()));
if (!f)
return false;
QtMetaTypePrivate::QAssociativeIterableImpl iter;
(*f)(from, &iter);
QAssociativeIterable map(iter);
QAssociativeIterable map;
(*f)(from, &map);
QVariantHash &h = *static_cast<QVariantHash *>(to);
h.clear();
h.reserve(map.size());
@ -1886,6 +1886,7 @@ static bool convertIterableToVariantHash(QMetaType fromType, const void *from, v
h.insert(it.key().toString(), it.value());
return true;
}
#endif
static bool convertIterableToVariantPair(QMetaType fromType, const void *from, void *to)
{
@ -1917,6 +1918,7 @@ static bool convertIterableToVariantPair(QMetaType fromType, const void *from, v
return true;
}
#ifndef QT_BOOTSTRAPPED
static bool convertToSequentialIterable(QMetaType fromType, const void *from, void *to)
{
using namespace QtMetaTypePrivate;
@ -1935,6 +1937,14 @@ static bool convertToSequentialIterable(QMetaType fromType, const void *from, vo
i = QSequentialIterable(reinterpret_cast<const QByteArrayList *>(from));
return true;
}
QSequentialIterable impl;
if (QMetaType::convert(
fromType, from, QMetaType::fromType<QIterable<QMetaSequence>>(), &impl)) {
i = std::move(impl);
return true;
}
return false;
}
@ -1944,23 +1954,24 @@ static bool convertToAssociativeIterable(QMetaType fromType, const void *from, v
QAssociativeIterable &i = *static_cast<QAssociativeIterable *>(to);
if (fromType.id() == QMetaType::QVariantMap) {
i = QAssociativeIterable(QAssociativeIterableImpl(reinterpret_cast<const QVariantMap *>(from)));
i = QAssociativeIterable(reinterpret_cast<const QVariantMap *>(from));
return true;
}
if (fromType.id() == QMetaType::QVariantHash) {
i = QAssociativeIterable(QAssociativeIterableImpl(reinterpret_cast<const QVariantHash *>(from)));
i = QAssociativeIterable(reinterpret_cast<const QVariantHash *>(from));
return true;
}
QAssociativeIterableImpl impl;
if (QMetaType::convert(fromType, from, QMetaType::fromType<QtMetaTypePrivate::QAssociativeIterableImpl>(), &impl)) {
i = QAssociativeIterable(impl);
QAssociativeIterable impl;
if (QMetaType::convert(
fromType, from, QMetaType::fromType<QIterable<QMetaAssociation>>(), &impl)) {
i = std::move(impl);
return true;
}
return false;
}
#ifndef QT_BOOTSTRAPPED
static bool canConvertMetaObject(QMetaType fromType, QMetaType toType)
{
const QMetaObject *f = fromType.metaObject();
@ -2022,6 +2033,10 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
}
}
if (toTypeId == QVariantPair && convertIterableToVariantPair(fromType, from, to))
return true;
#ifndef QT_BOOTSTRAPPED
// handle iterables
if (toTypeId == QVariantList && convertIterableToVariantList(fromType, from, to))
return true;
@ -2032,16 +2047,12 @@ bool QMetaType::convert(QMetaType fromType, const void *from, QMetaType toType,
if (toTypeId == QVariantHash && convertIterableToVariantHash(fromType, from, to))
return true;
if (toTypeId == QVariantPair && convertIterableToVariantPair(fromType, from, to))
return true;
if (toTypeId == qMetaTypeId<QSequentialIterable>())
return convertToSequentialIterable(fromType, from, to);
if (toTypeId == qMetaTypeId<QAssociativeIterable>())
return convertToAssociativeIterable(fromType, from, to);
#ifndef QT_BOOTSTRAPPED
// handle QObject conversion
if ((fromType.flags() & QMetaType::PointerToQObject) && (toType.flags() & QMetaType::PointerToQObject)) {
QObject *fromObject = *static_cast<QObject * const *>(from);
@ -2153,13 +2164,15 @@ bool QMetaType::canConvert(QMetaType fromType, QMetaType toType)
if (f)
return true;
#ifndef QT_BOOTSTRAPPED
if (toTypeId == QVariantList && hasRegisteredConverterFunction(
fromTypeId, qMetaTypeId<QSequentialIterable>()))
fromTypeId, qMetaTypeId<QIterable<QMetaSequence>>()))
return true;
if ((toTypeId == QVariantHash || toTypeId == QVariantMap) && hasRegisteredConverterFunction(
fromTypeId, qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()))
fromTypeId, qMetaTypeId<QIterable<QMetaAssociation>>()))
return true;
#endif
if (toTypeId == QVariantPair && hasRegisteredConverterFunction(
fromTypeId, qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>()))

View File

@ -48,6 +48,7 @@
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qrefcount.h>
#include <QtCore/qdatastream.h>
#include <QtCore/qiterable.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qobjectdefs.h>
#endif
@ -600,268 +601,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
Q_DECLARE_TYPEINFO(QtMetaTypePrivate:: C, (F)); \
namespace QtMetaTypePrivate {
namespace QtMetaTypePrivate {
template<typename const_iterator>
struct IteratorOwnerCommon
{
static void assign(void **ptr, const_iterator iterator)
{
*ptr = new const_iterator(iterator);
}
static void assign(void **ptr, void * const * src)
{
*ptr = new const_iterator(*static_cast<const_iterator*>(*src));
}
static void advance(void **iterator, int step)
{
const_iterator &it = *static_cast<const_iterator*>(*iterator);
std::advance(it, step);
}
static void destroy(void **ptr)
{
delete static_cast<const_iterator*>(*ptr);
}
static bool equal(void * const *it, void * const *other)
{
return *static_cast<const_iterator*>(*it) == *static_cast<const_iterator*>(*other);
}
};
template<typename const_iterator>
struct IteratorOwner : IteratorOwnerCommon<const_iterator>
{
static void getData(void * const *iterator, void *dataPtr)
{
const_iterator *it = static_cast<const_iterator*>(*iterator);
typename const_iterator::value_type *data = static_cast<typename const_iterator::value_type *>(dataPtr);
*data = **it;
}
static void getData(const_iterator it, void *dataPtr)
{
typename const_iterator::value_type *data = static_cast<typename const_iterator::value_type *>(dataPtr);
*data = *it;
}
};
template<typename value_type>
struct IteratorOwner<const value_type*>
{
private:
// We need to disable typed overloads of assign() and getData() if the value_type
// is void* to avoid overloads conflicts. We do it by injecting unaccessible Dummy
// type as part of the overload signature.
struct Dummy {};
typedef typename std::conditional<std::is_same<value_type, void*>::value, Dummy, value_type>::type value_type_OR_Dummy;
public:
static void assign(void **ptr, const value_type_OR_Dummy *iterator )
{
*ptr = const_cast<value_type*>(iterator);
}
static void assign(void **ptr, void * const * src)
{
*ptr = static_cast<value_type*>(*src);
}
static void advance(void **iterator, int step)
{
value_type *it = static_cast<value_type*>(*iterator);
std::advance(it, step);
*iterator = it;
}
static void destroy(void **)
{
}
static void getData(void * const *iterator, void *dataPtr)
{
*static_cast<value_type *>(dataPtr) = *static_cast<value_type * const>(*iterator);
}
static void getData(const value_type_OR_Dummy *it, void *dataPtr)
{
*static_cast<value_type *>(dataPtr) = *static_cast<value_type const *>(it);
}
static bool equal(void * const *it, void * const *other)
{
return static_cast<value_type const *>(*it) == static_cast<value_type const *>(*other);
}
};
}
namespace QtMetaTypePrivate {
template<typename T, bool = std::is_same<typename T::const_iterator::value_type, typename T::mapped_type>::value>
struct AssociativeContainerAccessor
{
static const typename T::key_type& getKey(const typename T::const_iterator &it)
{
return it.key();
}
static const typename T::mapped_type& getValue(const typename T::const_iterator &it)
{
return it.value();
}
};
template<typename T, bool = std::is_same<typename T::const_iterator::value_type, std::pair<const typename T::key_type, typename T::mapped_type> >::value>
struct StlStyleAssociativeContainerAccessor;
template<typename T>
struct StlStyleAssociativeContainerAccessor<T, true>
{
static const typename T::key_type& getKey(const typename T::const_iterator &it)
{
return it->first;
}
static const typename T::mapped_type& getValue(const typename T::const_iterator &it)
{
return it->second;
}
};
template<typename T>
struct AssociativeContainerAccessor<T, false> : public StlStyleAssociativeContainerAccessor<T>
{
};
class QAssociativeIterableImpl
{
public:
const void *_iterable;
void *_iterator;
QMetaType _metaType_key;
QMetaType _metaType_value;
typedef int(*sizeFunc)(const void *p);
typedef void (*findFunc)(const void *container, const void *p, void **iterator);
typedef void (*beginFunc)(const void *p, void **);
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 *);
sizeFunc _size;
findFunc _find;
beginFunc _begin;
beginFunc _end;
advanceFunc _advance;
getFunc _getKey;
getFunc _getValue;
destroyIterFunc _destroyIter;
equalIterFunc _equalIter;
copyIterFunc _copyIter;
template<class T>
static int sizeImpl(const void *p)
{ return int(std::distance(static_cast<const T*>(p)->begin(),
static_cast<const T*>(p)->end())); }
template<class T>
static void findImpl(const void *container, const void *p, void **iterator)
{ IteratorOwner<typename T::const_iterator>::assign(iterator,
static_cast<const T*>(container)->find(*static_cast<const typename T::key_type*>(p))); }
template<class T>
static void advanceImpl(void **p, int step)
{ std::advance(*static_cast<typename T::const_iterator*>(*p), step); }
template<class T>
static void beginImpl(const void *container, void **iterator)
{ IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->begin()); }
template<class T>
static void endImpl(const void *container, void **iterator)
{ IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->end()); }
template<class T>
static void getKeyImpl(void * const *iterator, void *dataPtr)
{
auto *data = static_cast<typename T::key_type *>(dataPtr);
*data = AssociativeContainerAccessor<T>::getKey(*static_cast<typename T::const_iterator*>(*iterator));
}
template<class T>
static void getValueImpl(void * const *iterator, void *dataPtr)
{
auto *data = static_cast<typename T::mapped_type *>(dataPtr);
*data = AssociativeContainerAccessor<T>::getValue(*static_cast<typename T::const_iterator*>(*iterator));
}
public:
template<class T> QAssociativeIterableImpl(const T*p)
: _iterable(p)
, _iterator(nullptr)
, _metaType_key(QMetaType::fromType<typename T::key_type>())
, _metaType_value(QMetaType::fromType<typename T::mapped_type>())
, _size(sizeImpl<T>)
, _find(findImpl<T>)
, _begin(beginImpl<T>)
, _end(endImpl<T>)
, _advance(advanceImpl<T>)
, _getKey(getKeyImpl<T>)
, _getValue(getValueImpl<T>)
, _destroyIter(IteratorOwner<typename T::const_iterator>::destroy)
, _equalIter(IteratorOwner<typename T::const_iterator>::equal)
, _copyIter(IteratorOwner<typename T::const_iterator>::assign)
{
}
QAssociativeIterableImpl()
: _iterable(nullptr)
, _iterator(nullptr)
, _size(nullptr)
, _find(nullptr)
, _begin(nullptr)
, _end(nullptr)
, _advance(nullptr)
, _getKey(nullptr)
, _getValue(nullptr)
, _destroyIter(nullptr)
, _equalIter(nullptr)
, _copyIter(nullptr)
{
}
inline void begin() { _begin(_iterable, &_iterator); }
inline void end() { _end(_iterable, &_iterator); }
inline bool equal(const QAssociativeIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); }
inline QAssociativeIterableImpl &advance(int i) { _advance(&_iterator, i); return *this; }
inline void destroyIter() { _destroyIter(&_iterator); }
inline void getCurrentKey(void *dataPtr) const { return _getKey(&_iterator, dataPtr); }
inline void getCurrentValue(void *dataPtr) const { return _getValue(&_iterator, dataPtr); }
inline void find(const void *key)
{ _find(_iterable, key, &_iterator); }
int size() const { Q_ASSERT(_iterable); return _size(_iterable); }
void copy(const QAssociativeIterableImpl &other)
{
*this = other;
_copyIter(&_iterator, &other._iterator);
}
};
QT_METATYPE_PRIVATE_DECLARE_TYPEINFO(QAssociativeIterableImpl, Q_MOVABLE_TYPE)
template<typename From>
struct QAssociativeIterableConvertFunctor
{
QAssociativeIterableImpl operator()(const From& f) const
{
return QAssociativeIterableImpl(&f);
}
};
class QPairVariantInterfaceImpl
{
@ -1675,7 +1416,6 @@ QT_END_NAMESPACE
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
QT_BEGIN_NAMESPACE
@ -1692,19 +1432,53 @@ inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter(int id)
}
namespace QtPrivate {
template<typename T>
struct AssociativeValueTypeIsMetaType<T, true>
template<typename From>
struct QSequentialIterableConvertFunctor
{
QIterable<QMetaSequence> operator()(const From &f) const
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QtMetaTypePrivate::QAssociativeIterableImpl>(o);
}
return true;
return QIterable<QMetaSequence>(QMetaSequence::fromContainer<From>(), &f);
}
};
template<typename T>
struct SequentialValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QIterable<QMetaSequence>>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QSequentialIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaSequence>>(o);
}
};
return true;
}
};
template<typename From>
struct QAssociativeIterableConvertFunctor
{
QIterable<QMetaAssociation> operator()(const From &f) const
{
return QIterable<QMetaAssociation>(QMetaAssociation::fromContainer<From>(), &f);
}
};
template<typename T>
struct AssociativeValueTypeIsMetaType<T, true>
{
static bool registerConverter(int id)
{
const int toId = qMetaTypeId<QIterable<QMetaAssociation>>();
if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
QAssociativeIterableConvertFunctor<T> o;
return QMetaType::registerConverter<T, QIterable<QMetaAssociation>>(o);
}
return true;
}
};
}
namespace QtPrivate {

View File

@ -0,0 +1,258 @@
/****************************************************************************
**
** 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/qsequentialiterable.h>
#include <QtCore/qvariant.h>
#include <QtCore/private/qiterable_p.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 values 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
*/
/*!
\typedef QSequentialIterable::RandomAccessIterator
Exposes an iterator using std::random_access_iterator_tag.
*/
/*!
\typedef QSequentialIterable::BidirectionalIterator
Exposes an iterator using std::bidirectional_iterator_tag.
*/
/*!
\typedef QSequentialIterable::ForwardIterator
Exposes an iterator using std::forward_iterator_tag.
*/
/*!
\typedef QSequentialIterable::InputIterator
Exposes an iterator using std::input_iterator_tag.
*/
/*!
\typedef QSequentialIterable::RandomAccessConstIterator
Exposes a const_iterator using std::random_access_iterator_tag.
*/
/*!
\typedef QSequentialIterable::BidirectionalConstIterator
Exposes a const_iterator using std::bidirectional_iterator_tag.
*/
/*!
\typedef QSequentialIterable::ForwardConstIterator
Exposes a const_iterator using std::forward_iterator_tag.
*/
/*!
\typedef QSequentialIterable::InputConstIterator
Exposes a const_iterator using std::input_iterator_tag.
*/
/*!
Adds \a value to the container, at \a position, if possible.
*/
void QSequentialIterable::addValue(const QVariant &value, Position position)
{
QVariant converted = value;
const void *valuePtr = QIterablePrivate::coerceType(converted, metaContainer().valueMetaType());
switch (position) {
case AtBegin:
if (metaContainer().canAddValueAtBegin())
metaContainer().addValueAtBegin(mutableIterable(), valuePtr);
break;
case AtEnd:
if (metaContainer().canAddValueAtEnd())
metaContainer().addValueAtEnd(mutableIterable(), valuePtr);
break;
case Unspecified:
if (metaContainer().canAddValue())
metaContainer().addValue(mutableIterable(), valuePtr);
break;
}
}
/*!
Removes a value from the container, at \a position, if possible.
*/
void QSequentialIterable::removeValue(Position position)
{
switch (position) {
case AtBegin:
if (metaContainer().canRemoveValueAtBegin())
metaContainer().removeValueAtBegin(mutableIterable());
break;
case AtEnd:
if (metaContainer().canRemoveValueAtEnd())
metaContainer().removeValueAtEnd(mutableIterable());
break;
case Unspecified:
if (metaContainer().canRemoveValue())
metaContainer().removeValue(mutableIterable());
break;
}
}
QMetaType QSequentialIterable::valueMetaType() const
{
return QMetaType(metaContainer().valueMetaType());
}
/*!
Returns the value at position \a idx in the container.
*/
QVariant QSequentialIterable::at(qsizetype idx) const
{
QVariant v(valueMetaType());
void *dataPtr;
if (valueMetaType() == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
const QMetaSequence meta = metaContainer();
if (meta.canGetValueAtIndex()) {
meta.valueAtIndex(m_iterable.constPointer(), idx, dataPtr);
} else if (meta.canGetValueAtConstIterator()) {
void *iterator = meta.constBegin(m_iterable.constPointer());
meta.advanceConstIterator(iterator, idx);
meta.valueAtConstIterator(iterator, dataPtr);
meta.destroyConstIterator(iterator);
}
return v;
}
/*!
Sets the element at position \a idx in the container to \a value.
*/
void QSequentialIterable::set(qsizetype idx, const QVariant &value)
{
QVariant converted = value;
const void *dataPtr = QIterablePrivate::coerceType(converted, metaContainer().valueMetaType());
const QMetaSequence meta = metaContainer();
if (meta.canSetValueAtIndex()) {
meta.setValueAtIndex(m_iterable.mutablePointer(), idx, dataPtr);
} else if (meta.canSetValueAtIterator()) {
void *iterator = meta.begin(m_iterable.mutablePointer());
meta.advanceIterator(iterator, idx);
meta.setValueAtIterator(iterator, dataPtr);
meta.destroyIterator(iterator);
}
}
/*!
\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
*/
/*!
\class QSequentialIterable::iterator
\since 6.0
\inmodule QtCore
\brief The QSequentialIterable::iterator allows iteration over a container in a QVariant.
A QSequentialIterable::iterator can only be created by a QSequentialIterable instance,
and can be used in a way similar to other stl-style iterators.
\sa QSequentialIterable
*/
/*!
Returns the current item, converted to a QVariantRef.
*/
QVariantRef<QSequentialIterator> QSequentialIterator::operator*() const
{
return QVariantRef<QSequentialIterator>(this);
}
/*!
Returns the current item, converted to a QVariantPointer.
*/
QVariantPointer<QSequentialIterator> QSequentialIterator::operator->() const
{
return QVariantPointer<QSequentialIterator>(this);
}
/*!
Returns the current item, converted to a QVariant.
*/
QVariant QSequentialConstIterator::operator*() const
{
return QIterablePrivate::retrieveElement(metaContainer().valueMetaType(), [this](void *dataPtr) {
metaContainer().valueAtConstIterator(constIterator(), dataPtr);
});
}
/*!
Returns the current item, converted to a QVariantConstPointer.
*/
QVariantConstPointer QSequentialConstIterator::operator->() const
{
return QVariantConstPointer(operator*());
}
QT_END_NAMESPACE

View File

@ -0,0 +1,186 @@
/****************************************************************************
**
** 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 QSEQUENTIALITERABLE_H
#define QSEQUENTIALITERABLE_H
#include <QtCore/qiterable.h>
#include <QtCore/qvariant.h>
QT_BEGIN_NAMESPACE
class Q_CORE_EXPORT QSequentialIterator : public QIterator<QMetaSequence>
{
public:
using value_type = QVariant;
using reference = QVariantRef<QSequentialIterator>;
using pointer = QVariantPointer<QSequentialIterator>;
QSequentialIterator(QIterator &&it)
: QIterator(std::move(it))
{}
QVariantRef<QSequentialIterator> operator*() const;
QVariantPointer<QSequentialIterator> operator->() const;
};
class Q_CORE_EXPORT QSequentialConstIterator : public QConstIterator<QMetaSequence>
{
public:
using value_type = QVariant;
using reference = const QVariant &;
using pointer = QVariantConstPointer;
QSequentialConstIterator(QConstIterator &&it)
: QConstIterator(std::move(it))
{}
QVariant operator*() const;
QVariantConstPointer operator->() const;
};
class Q_CORE_EXPORT QSequentialIterable : public QIterable<QMetaSequence>
{
public:
using iterator = QTaggedIterator<QSequentialIterator, void>;
using const_iterator = QTaggedIterator<QSequentialConstIterator, void>;
using RandomAccessIterator = QTaggedIterator<iterator, std::random_access_iterator_tag>;
using BidirectionalIterator = QTaggedIterator<iterator, std::bidirectional_iterator_tag>;
using ForwardIterator = QTaggedIterator<iterator, std::forward_iterator_tag>;
using InputIterator = QTaggedIterator<iterator, std::input_iterator_tag>;
using RandomAccessConstIterator = QTaggedIterator<const_iterator, std::random_access_iterator_tag>;
using BidirectionalConstIterator = QTaggedIterator<const_iterator, std::bidirectional_iterator_tag>;
using ForwardConstIterator = QTaggedIterator<const_iterator, std::forward_iterator_tag>;
using InputConstIterator = QTaggedIterator<const_iterator, std::input_iterator_tag>;
template<class T>
QSequentialIterable(const T *p)
: QIterable(QMetaSequence::fromContainer<T>(), p)
{
Q_UNUSED(m_revision);
}
template<class T>
QSequentialIterable(T *p)
: QIterable(QMetaSequence::fromContainer<T>(), p)
{
}
QSequentialIterable() = default;
template<typename Pointer>
QSequentialIterable(const QMetaSequence &metaSequence, Pointer iterable)
: QIterable(metaSequence, iterable)
{
}
QSequentialIterable(const QMetaSequence &metaSequence, const QMetaType &metaType,
void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
{
}
QSequentialIterable(const QMetaSequence &metaSequence, const QMetaType &metaType,
const void *iterable)
: QIterable(metaSequence, metaType.alignOf(), iterable)
{
}
QSequentialIterable(QIterable<QMetaSequence> &&other) : QIterable(std::move(other)) {}
QSequentialIterable &operator=(QIterable<QMetaSequence> &&other)
{
QIterable::operator=(std::move(other));
return *this;
}
const_iterator begin() const { return constBegin(); }
const_iterator end() const { return constEnd(); }
const_iterator constBegin() const { return const_iterator(QIterable::constBegin()); }
const_iterator constEnd() const { return const_iterator(QIterable::constEnd()); }
iterator mutableBegin() { return iterator(QIterable::mutableBegin()); }
iterator mutableEnd() { return iterator(QIterable::mutableEnd()); }
QVariant at(qsizetype idx) const;
void set(qsizetype idx, const QVariant &value);
enum Position { Unspecified, AtBegin, AtEnd };
void addValue(const QVariant &value, Position position = Unspecified);
void removeValue(Position position = Unspecified);
QMetaType valueMetaType() const;
};
template<>
inline QVariantRef<QSequentialIterator>::operator QVariant() const
{
if (m_pointer == nullptr)
return QVariant();
const QMetaType metaType(m_pointer->metaContainer().valueMetaType());
QVariant v(metaType);
void *dataPtr = metaType == QMetaType::fromType<QVariant>() ? &v : v.data();
m_pointer->metaContainer().valueAtIterator(m_pointer->constIterator(), dataPtr);
return v;
}
template<>
inline QVariantRef<QSequentialIterator> &QVariantRef<QSequentialIterator>::operator=(
const QVariant &value)
{
if (m_pointer == nullptr)
return *this;
const QMetaType metaType(m_pointer->metaContainer().valueMetaType());
const void *dataPtr = metaType == QMetaType::fromType<QVariant>()
? &value
: value.constData();
m_pointer->metaContainer().setValueAtIterator(m_pointer->constIterator(), dataPtr);
return *this;
}
Q_DECLARE_TYPEINFO(QSequentialIterable, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::iterator, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QSequentialIterable::const_iterator, Q_MOVABLE_TYPE);
QT_END_NAMESPACE
#endif // QSEQUENTIALITERABLE_H

View File

@ -2616,348 +2616,6 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\internal
*/
/*!
\class QAssociativeIterable
\since 5.2
\inmodule QtCore
\brief The QAssociativeIterable class is an iterable interface for an associative container in a QVariant.
This class allows several methods of accessing the elements of an associative container held within
a QVariant. An instance of QAssociativeIterable can be extracted from a QVariant if it can
be converted to a QVariantHash or QVariantMap.
\snippet code/src_corelib_kernel_qvariant.cpp 10
The container itself is not copied before iterating over it.
\sa QVariant
*/
/*!
\internal
*/
QAssociativeIterable::QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl)
: m_impl(impl)
{
}
QAssociativeIterable::const_iterator::const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_)
: m_impl(iter.m_impl), ref(ref_)
{
ref->ref();
}
QAssociativeIterable::const_iterator::const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_)
: m_impl(impl), ref(ref_)
{
ref->ref();
}
void QAssociativeIterable::const_iterator::begin()
{
m_impl.begin();
}
void QAssociativeIterable::const_iterator::end()
{
m_impl.end();
}
void QAssociativeIterable::const_iterator::find(const QVariant &key)
{
Q_ASSERT(key.metaType() == m_impl._metaType_key);
m_impl.find(key.constData());
}
/*!
Returns a QAssociativeIterable::const_iterator for the beginning of the container. This
can be used in stl-style iteration.
\sa end()
*/
QAssociativeIterable::const_iterator QAssociativeIterable::begin() const
{
const_iterator it(*this, new QAtomicInt(0));
it.begin();
return it;
}
/*!
Returns a QAssociativeIterable::const_iterator for the end of the container. This
can be used in stl-style iteration.
\sa begin()
*/
QAssociativeIterable::const_iterator QAssociativeIterable::end() const
{
const_iterator it(*this, new QAtomicInt(0));
it.end();
return it;
}
/*!
\since 5.5
Returns a QAssociativeIterable::const_iterator for the given key \a key
in the container, if the types are convertible.
If the key is not found, returns end().
This can be used in stl-style iteration.
\sa begin(), end(), value()
*/
QAssociativeIterable::const_iterator QAssociativeIterable::find(const QVariant &key) const
{
const_iterator it(*this, new QAtomicInt(0));
QVariant key_ = key;
if (key_.canConvert(m_impl._metaType_key) && key_.convert(m_impl._metaType_key))
it.find(key_);
else
it.end();
return it;
}
/*!
Returns the value for the given \a key in the container, if the types are convertible.
\sa find()
*/
QVariant QAssociativeIterable::value(const QVariant &key) const
{
const const_iterator it = find(key);
if (it == end())
return QVariant();
return *it;
}
/*!
Returns the number of elements in the container.
*/
int QAssociativeIterable::size() const
{
return m_impl.size();
}
/*!
\class QAssociativeIterable::const_iterator
\since 5.2
\inmodule QtCore
\brief The QAssociativeIterable::const_iterator allows iteration over a container in a QVariant.
A QAssociativeIterable::const_iterator can only be created by a QAssociativeIterable instance,
and can be used in a way similar to other stl-style iterators.
\snippet code/src_corelib_kernel_qvariant.cpp 10
\sa QAssociativeIterable
*/
/*!
Destroys the QAssociativeIterable::const_iterator.
*/
QAssociativeIterable::const_iterator::~const_iterator()
{
if (!ref->deref()) {
m_impl.destroyIter();
delete ref;
}
}
/*!
Creates a copy of \a other.
*/
QAssociativeIterable::const_iterator::const_iterator(const const_iterator &other)
: m_impl(other.m_impl), ref(other.ref)
{
ref->ref();
}
/*!
Assigns \a other to this.
*/
QAssociativeIterable::const_iterator&
QAssociativeIterable::const_iterator::operator=(const const_iterator &other)
{
other.ref->ref();
if (!ref->deref()) {
m_impl.destroyIter();
delete ref;
}
m_impl = other.m_impl;
ref = other.ref;
return *this;
}
/*!
Returns the current value, converted to a QVariant.
*/
const QVariant QAssociativeIterable::const_iterator::operator*() const
{
QVariant v(m_impl._metaType_value);
void *dataPtr;
if (m_impl._metaType_value == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
m_impl.getCurrentValue(dataPtr);
return v;
}
/*!
Returns the current key, converted to a QVariant.
*/
const QVariant QAssociativeIterable::const_iterator::key() const
{
QVariant v(m_impl._metaType_key);
void *dataPtr;
if (m_impl._metaType_key == QMetaType::fromType<QVariant>())
dataPtr = &v;
else
dataPtr = v.data();
m_impl.getCurrentKey(dataPtr);
return v;
}
/*!
Returns the current value, converted to a QVariant.
*/
const QVariant QAssociativeIterable::const_iterator::value() const
{
return operator*();
}
/*!
Returns \c true if \a other points to the same item as this
iterator; otherwise returns \c false.
\sa operator!=()
*/
bool QAssociativeIterable::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 QAssociativeIterable::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 QAssociativeIterable::end() leads to undefined results.
\sa operator--()
*/
QAssociativeIterable::const_iterator &QAssociativeIterable::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.
*/
QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator++(int)
{
QtMetaTypePrivate::QAssociativeIterableImpl 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 QAssociativeIterable::begin() leads to undefined results.
\sa operator++()
*/
QAssociativeIterable::const_iterator &QAssociativeIterable::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.
*/
QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator--(int)
{
QtMetaTypePrivate::QAssociativeIterableImpl 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+()
*/
QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator+=(int j)
{
m_impl.advance(j);
return *this;
}
/*!
Makes the iterator go back by \a j items.
\sa operator+=(), operator-()
*/
QAssociativeIterable::const_iterator &QAssociativeIterable::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+=()
*/
QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator+(int j) const
{
QtMetaTypePrivate::QAssociativeIterableImpl 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.
\sa operator+(), operator-=()
*/
QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator-(int j) const
{
QtMetaTypePrivate::QAssociativeIterableImpl impl;
impl.copy(m_impl);
impl.advance(-j);
return const_iterator(impl, new QAtomicInt(0));
}
/*!
\class QVariantRef
\since 6.0
@ -2978,6 +2636,13 @@ QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::opera
Creates a QVariantRef from an \a pointer.
*/
/*!
\fn QVariantRef &QVariantRef::operator=(const QVariant &value)
Assigns a new \a value to the value pointed to by the pointer this
QVariantRef refers to.
*/
/*!
\fn QVariantRef &QVariantRef::operator=(const QVariantRef &value)
@ -2992,6 +2657,12 @@ QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::opera
QVariantRef refers to.
*/
/*!
\fn QVariantRef::operator QVariant() const
Resolves the QVariantRef to an actual QVariant.
*/
/*!
\fn void swap(QVariantRef a, QVariantRef b)

View File

@ -580,61 +580,6 @@ inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2)
#endif
Q_DECLARE_SHARED(QVariant)
class Q_CORE_EXPORT QAssociativeIterable
{
QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
public:
struct Q_CORE_EXPORT const_iterator
{
private:
QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
QAtomicInt *ref;
friend class QAssociativeIterable;
explicit const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_);
explicit const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_);
void begin();
void end();
void find(const QVariant &key);
public:
~const_iterator();
const_iterator(const const_iterator &other);
const_iterator& operator=(const const_iterator &other);
const QVariant key() const;
const QVariant value() const;
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 QAssociativeIterable(const QtMetaTypePrivate::QAssociativeIterableImpl &impl);
QAssociativeIterable() {}
const_iterator begin() const;
const_iterator end() const;
const_iterator find(const QVariant &key) const;
QVariant value(const QVariant &key) const;
int size() const;
};
#ifndef QT_MOC
template<typename T> inline T qvariant_cast(const QVariant &v)

View File

@ -4151,91 +4151,148 @@ struct KeyGetter<std::unordered_map<T, U> >
};
#endif
template<typename Iterator>
void sortIterable(QSequentialIterable *iterable)
{
std::sort(Iterator(iterable->mutableBegin()), Iterator(iterable->mutableEnd()),
[&](const QVariant &a, const QVariant &b) {
return a.toInt() < b.toInt();
});
}
template<typename Container>
void testSequentialIteration()
{
int numSeen = 0;
Container sequence;
ContainerAPI<Container>::insert(sequence, 1);
ContainerAPI<Container>::insert(sequence, 2);
ContainerAPI<Container>::insert(sequence, 3);
QVariant listVariant = QVariant::fromValue(sequence);
QVERIFY(listVariant.canConvert<QVariantList>());
QVariantList varList = listVariant.value<QVariantList>();
QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end()));
QSequentialIterable listIter = listVariant.value<QSequentialIterable>();
QCOMPARE(varList.size(), listIter.size());
typename Container::iterator containerIter = sequence.begin();
const typename Container::iterator containerEnd = sequence.end();
for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen)
{
QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), *containerIter));
QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), varList.at(i)));
}
QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
QCOMPARE(containerIter, containerEnd);
containerIter = sequence.begin();
numSeen = 0;
Q_FOREACH (const QVariant &v, listIter) {
QVERIFY(ContainerAPI<Container>::compare(v, *containerIter));
QVERIFY(ContainerAPI<Container>::compare(v, varList.at(numSeen)));
++containerIter;
++numSeen;
}
QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
numSeen = 0;
containerIter = sequence.begin();
for (QVariant v : listIter) {
QVERIFY(ContainerAPI<Container>::compare(v, *containerIter));
QVERIFY(ContainerAPI<Container>::compare(v, varList.at(numSeen)));
++containerIter;
++numSeen;
}
QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
auto compareLists = [&]() {
int numSeen = 0;
auto varList = listVariant.value<QVariantList>();
auto varIter = varList.begin();
for (const QVariant &v : qAsConst(listIter)) {
QVERIFY(ContainerAPI<Container>::compare(v, *varIter));
++varIter;
++numSeen;
}
QCOMPARE(varIter, varList.end());
numSeen = 0;
auto constVarIter = varList.constBegin();
for (QVariant v : listIter) {
QVERIFY(ContainerAPI<Container>::compare(v, *constVarIter));
++constVarIter;
++numSeen;
}
QCOMPARE(numSeen, (int)std::distance(varList.begin(), varList.end()));
};
compareLists();
QVariant first = listIter.at(0);
QVariant second = listIter.at(1);
QVariant third = listIter.at(2);
compareLists();
listIter.addValue(third);
compareLists();
listIter.addValue(second);
compareLists();
listIter.addValue(first);
compareLists();
QCOMPARE(listIter.size(), 6);
if (listIter.canRandomAccessIterate())
sortIterable<QSequentialIterable::RandomAccessIterator>(&listIter);
else if (listIter.canReverseIterate())
sortIterable<QSequentialIterable::BidirectionalIterator>(&listIter);
else if (listIter.canForwardIterate())
return; // std::sort cannot sort with only forward iterators.
else
QFAIL("The container has no meaningful iterators");
compareLists();
QCOMPARE(listIter.size(), 6);
QCOMPARE(listIter.at(0), first);
QCOMPARE(listIter.at(1), first);
QCOMPARE(listIter.at(2), second);
QCOMPARE(listIter.at(3), second);
QCOMPARE(listIter.at(4), third);
QCOMPARE(listIter.at(5), third);
listIter.removeValue();
compareLists();
QCOMPARE(listIter.size(), 5);
QCOMPARE(listIter.at(0), first);
QCOMPARE(listIter.at(1), first);
QCOMPARE(listIter.at(2), second);
QCOMPARE(listIter.at(3), second);
QCOMPARE(listIter.at(4), third);
}
void tst_QVariant::iterateContainerElements()
{
#ifdef Q_COMPILER_RANGE_FOR
#define TEST_RANGE_FOR(CONTAINER) \
numSeen = 0; \
containerIter = intList.begin(); \
for (QVariant v : listIter) { \
QVERIFY(ContainerAPI<CONTAINER >::compare(v, *containerIter)); \
QVERIFY(ContainerAPI<CONTAINER >::compare(v, varList.at(numSeen))); \
++containerIter; \
++numSeen; \
} \
QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end()));
#else
#define TEST_RANGE_FOR(CONTAINER)
#endif
#define TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(CONTAINER) \
{ \
int numSeen = 0; \
CONTAINER intList; \
ContainerAPI<CONTAINER >::insert(intList, 1); \
ContainerAPI<CONTAINER >::insert(intList, 2); \
ContainerAPI<CONTAINER >::insert(intList, 3); \
\
QVariant listVariant = QVariant::fromValue(intList); \
QVERIFY(listVariant.canConvert<QVariantList>()); \
QVariantList varList = listVariant.value<QVariantList>(); \
QCOMPARE(varList.size(), (int)std::distance(intList.begin(), intList.end())); \
QSequentialIterable listIter = listVariant.value<QSequentialIterable>(); \
QCOMPARE(varList.size(), listIter.size()); \
\
CONTAINER::iterator containerIter = intList.begin(); \
const CONTAINER::iterator containerEnd = intList.end(); \
for (int i = 0; i < listIter.size(); ++i, ++containerIter, ++numSeen) \
{ \
QVERIFY(ContainerAPI<CONTAINER >::compare(listIter.at(i), *containerIter)); \
QVERIFY(ContainerAPI<CONTAINER >::compare(listIter.at(i), varList.at(i))); \
} \
QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \
QCOMPARE(containerIter, containerEnd); \
\
containerIter = intList.begin(); \
numSeen = 0; \
Q_FOREACH (const QVariant &v, listIter) { \
QVERIFY(ContainerAPI<CONTAINER >::compare(v, *containerIter)); \
QVERIFY(ContainerAPI<CONTAINER >::compare(v, varList.at(numSeen))); \
++containerIter; \
++numSeen; \
} \
QCOMPARE(numSeen, (int)std::distance(intList.begin(), intList.end())); \
TEST_RANGE_FOR(CONTAINER) \
}
#define TEST_SEQUENTIAL_ITERATION(CONTAINER, VALUE_TYPE) \
TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(CONTAINER<VALUE_TYPE > )
TEST_SEQUENTIAL_ITERATION(QQueue, int)
TEST_SEQUENTIAL_ITERATION(QQueue, QVariant)
TEST_SEQUENTIAL_ITERATION(QQueue, QString)
TEST_SEQUENTIAL_ITERATION(QList, int)
TEST_SEQUENTIAL_ITERATION(QList, QVariant)
TEST_SEQUENTIAL_ITERATION(QList, QString)
TEST_SEQUENTIAL_ITERATION(QList, QByteArray)
TEST_SEQUENTIAL_ITERATION(QStack, int)
TEST_SEQUENTIAL_ITERATION(QStack, QVariant)
TEST_SEQUENTIAL_ITERATION(QStack, QString)
TEST_SEQUENTIAL_ITERATION(std::vector, int)
TEST_SEQUENTIAL_ITERATION(std::vector, QVariant)
TEST_SEQUENTIAL_ITERATION(std::vector, QString)
TEST_SEQUENTIAL_ITERATION(std::list, int)
TEST_SEQUENTIAL_ITERATION(std::list, QVariant)
TEST_SEQUENTIAL_ITERATION(std::list, QString)
TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(QStringList)
TEST_SEQUENTIAL_ITERATION_ON_FULL_NAME(QByteArrayList)
testSequentialIteration<QQueue<int>>();
testSequentialIteration<QQueue<QVariant>>();
testSequentialIteration<QQueue<QString>>();
testSequentialIteration<QList<int>>();
testSequentialIteration<QList<QVariant>>();
testSequentialIteration<QList<QString>>();
testSequentialIteration<QList<QByteArray>>();
testSequentialIteration<QStack<int>>();
testSequentialIteration<QStack<QVariant>>();
testSequentialIteration<QStack<QString>>();
testSequentialIteration<std::vector<int>>();
testSequentialIteration<std::vector<QVariant>>();
testSequentialIteration<std::vector<QString>>();
testSequentialIteration<std::list<int>>();
testSequentialIteration<std::list<QVariant>>();
testSequentialIteration<std::list<QString>>();
testSequentialIteration<QStringList>();
testSequentialIteration<QByteArrayList>();
#ifdef TEST_FORWARD_LIST
TEST_SEQUENTIAL_ITERATION(std::forward_list, int)
TEST_SEQUENTIAL_ITERATION(std::forward_list, QVariant)
TEST_SEQUENTIAL_ITERATION(std::forward_list, QString)
testSequentialIteration<std::forward_list<int>>();
testSequentialIteration<std::forward_list<QVariant>>();
testSequentialIteration<std::forward_list<QString>>();
#endif
{
@ -4575,37 +4632,42 @@ void tst_QVariant::shouldDeleteVariantDataWorksForAssociative()
{
QCOMPARE(instanceCount, 0);
{
QtMetaTypePrivate::QAssociativeIterableImpl iterator {};
QtMetaContainerPrivate::QMetaAssociationInterface iterator {};
iterator._size = [](const void *) {return 1;};
iterator._metaType_value = QMetaType::fromType<MyType>();
iterator._metaType_key = QMetaType::fromType<MyType>();
iterator._begin = [](const void *, void **) {};
iterator._end = [](const void *, void **) {};
iterator._advance = [](void **, int) {};
iterator._destroyIter = [](void **){};
iterator._equalIter = [](void * const *, void * const *){return true; /*all iterators are nullptr*/};
iterator._destroyIter = [](void **){};
iterator._find = [](const void *, const void *, void **iterator ) -> void {
(*iterator) = reinterpret_cast<void *>(quintptr(42));
iterator.sizeFn = [](const void *) -> qsizetype {return 1;};
iterator.mappedMetaType = QtPrivate::qMetaTypeInterfaceForType<MyType>();
iterator.keyMetaType = QtPrivate::qMetaTypeInterfaceForType<MyType>();
iterator.createConstIteratorFn = [](
const void *, QtMetaContainerPrivate::QMetaContainerInterface::Position) -> void * {
return nullptr;
};
iterator._getKey = [](void * const *iterator, void *dataPtr) -> void {
iterator.advanceConstIteratorFn = [](void *, qsizetype) {};
iterator.destroyConstIteratorFn = [](const void *){};
iterator.compareConstIteratorFn = [](const void *, const void *) {
return true; /*all iterators are nullptr*/
};
iterator.createConstIteratorAtKeyFn = [](const void *, const void *) -> void * {
return reinterpret_cast<void *>(quintptr(42));
};
iterator.copyConstIteratorFn = [](void *, const void *) {};
iterator.diffConstIteratorFn = [](const void *, const void *) -> qsizetype { return 0; };
iterator.keyAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
MyType mytype {1, "key"};
if (reinterpret_cast<quintptr>(*iterator) == 42) {
if (reinterpret_cast<quintptr>(iterator) == 42) {
mytype.number = 42;
mytype.text = "find_key";
}
*static_cast<MyType *>(dataPtr) = mytype;
};
iterator._getValue = [](void * const *iterator, void *dataPtr) -> void {
iterator.mappedAtConstIteratorFn = [](const void *iterator, void *dataPtr) -> void {
MyType mytype {2, "value"};
if (reinterpret_cast<quintptr>(*iterator) == 42) {
if (reinterpret_cast<quintptr>(iterator) == 42) {
mytype.number = 42;
mytype.text = "find_value";
}
*static_cast<MyType *>(dataPtr) = mytype;
};
QAssociativeIterable iterable {iterator};
QAssociativeIterable iterable(QMetaAssociation(&iterator), nullptr);
auto it = iterable.begin();
QVariant value1 = it.key();
QVERIFY(value1.canConvert<MyType>());
@ -4695,37 +4757,37 @@ void tst_QVariant::sequentialIterableAppend()
{
QList<int> container { 1, 2 };
auto variant = QVariant::fromValue(container);
QVERIFY(variant.canConvert<QSequentialIterable>());
auto asIterable = variant.value<QSequentialIterable>();
QVERIFY(variant.canConvert<QIterable<QMetaSequence>>());
QSequentialIterable asIterable = variant.value<QIterable<QMetaSequence>>();
const int i = 3, j = 4;
void *mutableIterable = asIterable.mutableIterable();
asIterable.metaSequence().addValueAtEnd(mutableIterable, &i);
asIterable.metaSequence().addValueAtEnd(mutableIterable, &j);
asIterable.metaContainer().addValueAtEnd(mutableIterable, &i);
asIterable.metaContainer().addValueAtEnd(mutableIterable, &j);
QCOMPARE(variant.value<QList<int>>(), QList<int> ({ 1, 2, 3, 4 }));
asIterable.metaSequence().addValueAtBegin(mutableIterable, &i);
asIterable.metaSequence().addValueAtBegin(mutableIterable, &j);
asIterable.metaContainer().addValueAtBegin(mutableIterable, &i);
asIterable.metaContainer().addValueAtBegin(mutableIterable, &j);
QCOMPARE(variant.value<QList<int>>(), QList<int> ({ 4, 3, 1, 2, 3, 4 }));
asIterable.metaSequence().removeValueAtBegin(mutableIterable);
asIterable.metaContainer().removeValueAtBegin(mutableIterable);
QCOMPARE(variant.value<QList<int>>(), QList<int> ({ 3, 1, 2, 3, 4 }));
asIterable.metaSequence().removeValueAtEnd(mutableIterable);
asIterable.metaContainer().removeValueAtEnd(mutableIterable);
QCOMPARE(variant.value<QList<int>>(), QList<int> ({ 3, 1, 2, 3 }));
}
{
QSet<QByteArray> container { QByteArray{"hello"}, QByteArray{"world"} };
auto variant = QVariant::fromValue(std::move(container));
QVERIFY(variant.canConvert<QSequentialIterable>());
auto asIterable = variant.value<QSequentialIterable>();
QVERIFY(variant.canConvert<QIterable<QMetaSequence>>());
QSequentialIterable asIterable = variant.value<QIterable<QMetaSequence>>();
QByteArray qba1 {"goodbye"};
QByteArray qba2 { "moon" };
void *mutableIterable = asIterable.mutableIterable();
asIterable.metaSequence().addValue(mutableIterable, &qba1);
asIterable.metaSequence().addValue(mutableIterable, &qba2);
asIterable.metaContainer().addValue(mutableIterable, &qba1);
asIterable.metaContainer().addValue(mutableIterable, &qba2);
QSet<QByteArray> reference { "hello", "world", "goodbye", "moon" };
QCOMPARE(variant.value<QSet<QByteArray>>(), reference);
asIterable.metaSequence().addValue(mutableIterable, &qba1);
asIterable.metaSequence().addValue(mutableIterable, &qba2);
asIterable.metaContainer().addValue(mutableIterable, &qba1);
asIterable.metaContainer().addValue(mutableIterable, &qba2);
QCOMPARE(variant.value<QSet<QByteArray>>(), reference);
}
}
@ -4741,8 +4803,8 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
calledCorrectConverter = true;
return QVariantList {};
});
QMetaType::registerConverter<MyType, QAssociativeIterableImpl>([](const MyType &) {
return QAssociativeIterableImpl {};
QMetaType::registerConverter<MyType, QAssociativeIterable>([](const MyType &) {
return QAssociativeIterable {};
});
QMetaType::registerConverter<MyType, QVariantHash>([&calledCorrectConverter](const MyType &) {
calledCorrectConverter = true;
@ -4756,7 +4818,7 @@ void tst_QVariant::preferDirectConversionOverInterfaces()
QVERIFY(holder.canConvert<QSequentialIterable>());
QVERIFY(holder.canConvert<QVariantList>());
QVERIFY(holder.canConvert<QAssociativeIterableImpl>());
QVERIFY(holder.canConvert<QAssociativeIterable>());
QVERIFY(holder.canConvert<QVariantHash>());
QVERIFY(holder.canConvert<QVariantMap>());

View File

@ -38,6 +38,8 @@ struct ForwardDeclaredParam;
template <typename T> class ForwardDeclaredContainer;
struct FullyDefined {};
inline size_t qHash(const FullyDefined &, size_t seed = 0) { return seed; }
inline bool operator==(const FullyDefined &, const FullyDefined &) { return true; }
Q_DECLARE_METATYPE(FullyDefined)
class ForwardDeclaredParamClass : public QObject