summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
authorStephen Kelly <stephen.kelly@kdab.com>2013-04-05 13:23:38 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-05-20 09:09:06 +0200
commit87e27eb870d08ee8953cc9b350ed29c5b3e4f785 (patch)
tree8e022660f5fb09e617707b9d0c6eeb321f66df5c /src/corelib/kernel
parent65f953407a3a1726db3949743c28e1f9e2ad0e8b (diff)
Add container access functionality for associative containers in QVariant.
Change-Id: I4763a4c157e52918a0a68cba63624c0649aca235 Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qmetatype.cpp15
-rw-r--r--src/corelib/kernel/qmetatype.h268
-rw-r--r--src/corelib/kernel/qvariant.cpp189
-rw-r--r--src/corelib/kernel/qvariant.h142
4 files changed, 610 insertions, 4 deletions
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 5c3f252395..bfc48774b5 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -1990,6 +1990,21 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
\sa QVariant::canConvert()
*/
+/*!
+ \fn bool qRegisterAssociativeConverter()
+ \relates QMetaType
+ \since 5.2
+
+ Registers an associative container so that it can be converted to
+ a QVariantHash or QVariantMap. If the key_type and mapped_type of the container
+ was not declared with Q_DECLARE_METATYPE(), compilation will fail.
+
+ Note that it is not necessary to call this method for Qt containers (QHash,
+ QMap etc) or for std::map. Such containers are automatically registered by Qt.
+
+ \sa QVariant::canConvert()
+*/
+
namespace {
class TypeInfo {
template<typename T, bool IsAcceptedType = DefinedTypesFilter::Acceptor<T>::IsAccepted>
diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h
index 302c5da63a..ef741aeff9 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -296,6 +296,8 @@ struct ConverterFunctor : public AbstractConverterFunction
template<typename T, bool>
struct ValueTypeIsMetaType;
+ template<typename T, bool>
+ struct AssociativeValueTypeIsMetaType;
}
class Q_CORE_EXPORT QMetaType {
@@ -531,6 +533,9 @@ private:
template<typename, typename> friend struct QtPrivate::ConverterMemberFunction;
template<typename, typename> friend struct QtPrivate::ConverterMemberFunctionOk;
template<typename, typename, typename> friend struct QtPrivate::ConverterFunctor;
+ template<typename T>
+ friend bool qRegisterAssociativeConverter();
+ template<typename, bool> friend struct QtPrivate::AssociativeValueTypeIsMetaType;
#endif
#else
public:
@@ -876,6 +881,173 @@ struct QSequentialIterableConvertFunctor
};
}
+namespace QtMetaTypePrivate {
+template<typename T, bool = QtPrivate::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 = QtPrivate::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;
+ int _metaType_id_key;
+ uint _metaType_flags_key;
+ int _metaType_id_value;
+ uint _metaType_flags_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 VariantData (*getFunc)(void * const *p, int metaTypeId, uint flags);
+ typedef void (*destroyIterFunc)(void **p);
+ typedef bool (*equalIterFunc)(void * const *p, void * const *other);
+
+ sizeFunc _size;
+ findFunc _find;
+ beginFunc _begin;
+ beginFunc _end;
+ advanceFunc _advance;
+ getFunc _getKey;
+ getFunc _getValue;
+ destroyIterFunc _destroyIter;
+ equalIterFunc _equalIter;
+
+ template<class T>
+ static int sizeImpl(const void *p)
+ { return 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 VariantData getKeyImpl(void * const *iterator, int metaTypeId, uint flags)
+ { return VariantData(metaTypeId, &AssociativeContainerAccessor<T>::getKey(*static_cast<typename T::const_iterator*>(*iterator)), flags); }
+
+ template<class T>
+ static VariantData getValueImpl(void * const *iterator, int metaTypeId, uint flags)
+ { return VariantData(metaTypeId, &AssociativeContainerAccessor<T>::getValue(*static_cast<typename T::const_iterator*>(*iterator)), flags); }
+
+ template<class T>
+ static void destroyIterImpl(void **iterator)
+ { IteratorOwner<typename T::const_iterator>::destroy(iterator); }
+
+ template<class T>
+ static bool equalIterImpl(void * const *iterator, void * const *other)
+ { return *static_cast<typename T::const_iterator*>(*iterator) == *static_cast<typename T::const_iterator*>(*other); }
+
+public:
+ template<class T> QAssociativeIterableImpl(const T*p)
+ : _iterable(p)
+ , _metaType_id_key(qMetaTypeId<typename T::key_type>())
+ , _metaType_flags_key(QTypeInfo<typename T::key_type>::isPointer)
+ , _metaType_id_value(qMetaTypeId<typename T::mapped_type>())
+ , _metaType_flags_value(QTypeInfo<typename T::mapped_type>::isPointer)
+ , _size(sizeImpl<T>)
+ , _find(findImpl<T>)
+ , _begin(beginImpl<T>)
+ , _end(endImpl<T>)
+ , _advance(advanceImpl<T>)
+ , _getKey(getKeyImpl<T>)
+ , _getValue(getValueImpl<T>)
+ , _destroyIter(destroyIterImpl<T>)
+ , _equalIter(equalIterImpl<T>)
+ {
+ }
+
+ QAssociativeIterableImpl()
+ : _iterable(0)
+ , _metaType_id_key(QMetaType::UnknownType)
+ , _metaType_flags_key(0)
+ , _metaType_id_value(QMetaType::UnknownType)
+ , _metaType_flags_value(0)
+ , _size(0)
+ , _find(0)
+ , _begin(0)
+ , _end(0)
+ , _advance(0)
+ , _getKey(0)
+ , _getValue(0)
+ , _destroyIter(0)
+ , _equalIter(0)
+ {
+ }
+
+ 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 VariantData getCurrentKey() const { return _getKey(&_iterator, _metaType_id_key, _metaType_flags_value); }
+ inline VariantData getCurrentValue() const { return _getValue(&_iterator, _metaType_id_value, _metaType_flags_value); }
+
+ inline void find(const VariantData &key)
+ { _find(_iterable, key.data, &_iterator); }
+
+ int size() const { Q_ASSERT(_iterable); return _size(_iterable); }
+};
+
+template<typename From>
+struct QAssociativeIterableConvertFunctor
+{
+ QAssociativeIterableConvertFunctor() {}
+
+ QAssociativeIterableImpl operator()(const From& f) const
+ {
+ return QAssociativeIterableImpl(&f);
+ }
+};
+}
+
class QObject;
class QWidget;
template <class T> class QSharedPointer;
@@ -978,6 +1150,23 @@ namespace QtPrivate
QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::vector)
QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(std::list)
+ template<typename T>
+ struct IsAssociativeContainer
+ {
+ enum { Value = false };
+ };
+
+#define QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(CONTAINER) \
+ template<typename T, typename U> \
+ struct IsAssociativeContainer<CONTAINER<T, U> > \
+ { \
+ enum { Value = true }; \
+ };
+ QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QHash)
+ QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(QMap)
+ QT_DEFINE_ASSOCIATIVE_CONTAINER_TYPE(std::map)
+
+
template<typename T, bool = QtPrivate::IsSequentialContainer<T>::Value>
struct SequentialContainerConverterHelper
{
@@ -1018,6 +1207,60 @@ namespace QtPrivate
{
};
+ template<typename T, bool = QtPrivate::IsAssociativeContainer<T>::Value>
+ struct AssociativeContainerConverterHelper
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T, bool = QMetaTypeId2<typename T::mapped_type>::Defined>
+ struct AssociativeValueTypeIsMetaType
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T>
+ struct AssociativeValueTypeIsMetaType<T, true>
+ {
+ static bool registerConverter(int id)
+ {
+ const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>();
+ if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o;
+ static const QtPrivate::ConverterFunctor<T,
+ QtMetaTypePrivate::QAssociativeIterableImpl,
+ QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> > f(o);
+ return QMetaType::registerConverterFunction(&f, id, toId);
+ }
+ return true;
+ }
+ };
+
+ template<typename T, bool = QMetaTypeId2<typename T::key_type>::Defined>
+ struct KeyAndValueTypeIsMetaType
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T>
+ struct KeyAndValueTypeIsMetaType<T, true> : AssociativeValueTypeIsMetaType<T>
+ {
+ };
+
+ template<typename T>
+ struct AssociativeContainerConverterHelper<T, true> : KeyAndValueTypeIsMetaType<T>
+ {
+ };
+
Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
} // namespace QtPrivate
@@ -1118,6 +1361,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
if (id > 0) {
QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
+ QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
}
return id;
@@ -1501,6 +1745,7 @@ QT_END_NAMESPACE
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
Q_DECLARE_METATYPE(QtMetaTypePrivate::QSequentialIterableImpl)
+Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl)
QT_BEGIN_NAMESPACE
@@ -1520,9 +1765,26 @@ bool qRegisterSequentialConverter()
static const QtPrivate::ConverterFunctor<T,
QtMetaTypePrivate::QSequentialIterableImpl,
QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o);
- return QMetaType::registerConverterFunction(
- &f,
- id, toId);
+ return QMetaType::registerConverterFunction(&f, id, toId);
+}
+
+template<typename T>
+bool qRegisterAssociativeConverter()
+{
+ Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::key_type>::Defined
+ && QMetaTypeId2<typename T::mapped_type>::Defined,
+ "The key_type and mapped_type of an associative container must themselves be metatypes.");
+
+ const int id = qMetaTypeId<T>();
+ const int toId = qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>();
+ if (QMetaType::hasRegisteredConverterFunction(id, toId))
+ return true;
+ static const QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> o;
+ static const QtPrivate::ConverterFunctor<T,
+ QtMetaTypePrivate::QAssociativeIterableImpl,
+ QtMetaTypePrivate::QAssociativeIterableConvertFunctor<T> > f(o);
+
+ return QMetaType::registerConverterFunction(&f, id, toId);
}
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 99fdb4fa4a..37b89b82f0 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -2755,7 +2755,14 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
This requires that the value_type of the container is itself a metatype.
- \sa convert(), QSequentialIterable, qRegisterSequentialConverter()
+ Similarly, a QVariant containing a sequential container will also return true for this
+ function the \a targetTypeId is QVariantHash or QVariantMap. It is possible to iterate over
+ the contents of the container without extracting it as a (copied) QVariantHash or QVariantMap:
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 10
+
+ \sa convert(), QSequentialIterable, qRegisterSequentialConverter(), QAssociativeIterable,
+ qRegisterAssociativeConverter()
*/
bool QVariant::canConvert(int targetTypeId) const
{
@@ -2767,6 +2774,14 @@ bool QVariant::canConvert(int targetTypeId) const
return true;
}
+ if ((targetTypeId == QMetaType::QVariantHash || targetTypeId == QMetaType::QVariantMap)
+ && (d.type == QMetaType::QVariantMap
+ || d.type == QMetaType::QVariantHash
+ || QMetaType::hasRegisteredConverterFunction(d.type,
+ qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>()))) {
+ return true;
+ }
+
if ((d.type >= QMetaType::User || targetTypeId >= QMetaType::User)
&& QMetaType::hasRegisteredConverterFunction(d.type, targetTypeId)) {
return true;
@@ -3423,4 +3438,176 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\sa operator+(), operator-=(), canReverseIterate()
*/
+/*!
+ \class QAssociativeIterable
+
+ \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
+*/
+
+/*! \fn QAssociativeIterable::QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl)
+
+ \internal
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::begin() const
+
+ Returns a QAssociativeIterable::const_iterator for the beginning of the container. This
+ can be used in stl-style iteration.
+
+ \sa end()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::end() const
+
+ Returns a QAssociativeIterable::const_iterator for the end of the container. This
+ can be used in stl-style iteration.
+
+ \sa begin()
+*/
+
+/*! \fn QVariant QAssociativeIterable::value(const QVariant &key) const
+
+ Returns the value for the given \a key in the container, if the types are convertible.
+*/
+
+/*! \fn int QAssociativeIterable::size() const
+
+ Returns the number of elements in the container.
+*/
+
+/*!
+ \class QAssociativeIterable::const_iterator
+
+ \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
+*/
+
+
+/*! \fn QAssociativeIterable::const_iterator::~const_iterator()
+
+ Destroys the QAssociativeIterable::const_iterator.
+*/
+
+/*! \fn QAssociativeIterable::const_iterator::const_iterator(const const_iterator &other)
+
+ Creates a copy of \a other.
+*/
+
+/*! \fn QVariant QAssociativeIterable::const_iterator::operator*() const
+
+ Returns the current value, converted to a QVariant.
+*/
+
+/*! \fn QVariant QAssociativeIterable::const_iterator::key() const
+
+ Returns the current key, converted to a QVariant.
+*/
+
+/*! \fn QVariant QAssociativeIterable::const_iterator::value() const
+
+ Returns the current value, converted to a QVariant.
+*/
+
+/*! \fn bool QAssociativeIterable::const_iterator::operator==(const const_iterator &other) const
+
+ Returns true if \a other points to the same item as this
+ iterator; otherwise returns false.
+
+ \sa operator!=()
+*/
+
+/*! \fn bool QAssociativeIterable::const_iterator::operator!=(const const_iterator &other) const
+
+ Returns true if \a other points to a different item than this
+ iterator; otherwise returns false.
+
+ \sa operator==()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::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 QAssociativeIterable::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::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 QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator--()
+
+ 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++()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator--(int)
+
+ \overload
+
+ The postfix -- operator (\c{it--}) makes the preceding item
+ current and returns an iterator to the previously current item.
+*/
+
+/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator+=(int j)
+
+ Advances the iterator by \a j items.
+
+ \sa operator-=(), operator+()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator &QAssociativeIterable::const_iterator::operator-=(int j)
+
+ Makes the iterator go back by \a j items.
+
+ \sa operator+=(), operator-()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator+(int j) const
+
+ Returns an iterator to the item at \a j positions forward from
+ this iterator.
+
+ \sa operator-(), operator+=()
+*/
+
+/*! \fn QAssociativeIterable::const_iterator QAssociativeIterable::const_iterator::operator-(int j) const
+
+ Returns an iterator to the item at \a j positions backward from
+ this iterator.
+
+ \sa operator+(), operator-=()
+*/
+
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 5588cdb27c..271aaf13ce 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -632,6 +632,103 @@ public:
{ return m_impl._iteratorCapabilities & QtMetaTypePrivate::BiDirectionalCapability; }
};
+class QAssociativeIterable
+{
+ QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
+public:
+ struct const_iterator
+ {
+ private:
+ QtMetaTypePrivate::QAssociativeIterableImpl m_impl;
+ QAtomicInt *ref;
+ friend class QAssociativeIterable;
+ inline explicit const_iterator(const QAssociativeIterable &iter, QAtomicInt *ref_)
+ : m_impl(iter.m_impl), ref(ref_) { ref->ref(); }
+
+ inline explicit const_iterator(const QtMetaTypePrivate::QAssociativeIterableImpl &impl, QAtomicInt *ref_)
+ : m_impl(impl), ref(ref_) { ref->ref(); }
+
+ inline void begin() { m_impl.begin(); }
+ inline void end() { m_impl.end(); }
+ public:
+ inline ~const_iterator() {
+ if (!ref->deref()) {
+ m_impl.destroyIter();
+ }
+ }
+ inline const_iterator(const const_iterator &other) : m_impl(other.m_impl), ref(other.ref) {
+ ref->ref();
+ }
+
+ inline const QVariant key() const {
+ const QtMetaTypePrivate::VariantData d = m_impl.getCurrentKey();
+ QVariant v(d.metaTypeId, d.data, d.flags);
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return v;
+ }
+
+ inline const QVariant value() const {
+ const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue();
+ QVariant v(d.metaTypeId, d.data, d.flags);
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return v;
+ }
+
+ inline const QVariant operator*() const {
+ const QtMetaTypePrivate::VariantData d = m_impl.getCurrentValue();
+ QVariant v(d.metaTypeId, d.data, d.flags);
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return v;
+ }
+ inline bool operator==(const const_iterator &o) const { return m_impl.equal(o.m_impl); }
+ inline bool operator!=(const const_iterator &o) const { return !m_impl.equal(o.m_impl); }
+ inline const_iterator &operator++() { m_impl.advance(1); return *this; }
+ inline const_iterator operator++(int) { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; m_impl.advance(1); return const_iterator(impl, this->ref); }
+ inline const_iterator &operator--() { m_impl.advance(-1); return *this; }
+ inline const_iterator operator--(int) { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; m_impl.advance(-1); return const_iterator(impl, this->ref); }
+ inline const_iterator &operator+=(int j) { m_impl.advance(j); return *this; }
+ inline const_iterator &operator-=(int j) { m_impl.advance(-j); return *this; }
+ inline const_iterator operator+(int j) const { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; impl.advance(j); return const_iterator(impl, this->ref); }
+ inline const_iterator operator-(int j) const { QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl; impl.advance(-j); return const_iterator(impl, this->ref); }
+ };
+
+ friend struct const_iterator;
+
+ explicit QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl impl)
+ : m_impl(impl)
+ {
+ }
+
+ const_iterator begin() const { const_iterator it(*this, new QAtomicInt(0)); it.begin(); return it; }
+ const_iterator end() const { const_iterator it(*this, new QAtomicInt(0)); it.end(); return it; }
+
+ QVariant value(const QVariant &key) const
+ {
+ QVariant key_ = key;
+ if (!key_.canConvert(m_impl._metaType_id_key))
+ return QVariant();
+ if (!key_.convert(m_impl._metaType_id_key))
+ return QVariant();
+ const QtMetaTypePrivate::VariantData dkey(key_.userType(), key_.constData(), 0 /*key.flags()*/);
+ QtMetaTypePrivate::QAssociativeIterableImpl impl = m_impl;
+ impl.find(dkey);
+ QtMetaTypePrivate::QAssociativeIterableImpl endIt = m_impl;
+ endIt.end();
+ if (impl.equal(endIt))
+ return QVariant();
+ const QtMetaTypePrivate::VariantData d = impl.getCurrentValue();
+ QVariant v(d.metaTypeId, d.data, d.flags);
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return v;
+ }
+
+ int size() const { return m_impl.size(); }
+};
+
#ifndef QT_MOC
namespace QtPrivate {
template<typename T>
@@ -675,6 +772,20 @@ namespace QtPrivate {
}
};
template<>
+ struct QVariantValueHelperInterface<QAssociativeIterable>
+ {
+ static QAssociativeIterable invoke(const QVariant &v)
+ {
+ if (v.userType() == qMetaTypeId<QVariantMap>()) {
+ return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantMap*>(v.constData())));
+ }
+ if (v.userType() == qMetaTypeId<QVariantHash>()) {
+ return QAssociativeIterable(QtMetaTypePrivate::QAssociativeIterableImpl(reinterpret_cast<const QVariantHash*>(v.constData())));
+ }
+ return QAssociativeIterable(v.value<QtMetaTypePrivate::QAssociativeIterableImpl>());
+ }
+ };
+ template<>
struct QVariantValueHelperInterface<QVariantList>
{
static QVariantList invoke(const QVariant &v)
@@ -690,6 +801,37 @@ namespace QtPrivate {
return QVariantValueHelper<QVariantList>::invoke(v);
}
};
+ template<>
+ struct QVariantValueHelperInterface<QVariantHash>
+ {
+ static QVariantHash invoke(const QVariant &v)
+ {
+ if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) {
+ QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v);
+ QVariantHash l;
+ l.reserve(iter.size());
+ for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
+ l.insert(it.key().toString(), it.value());
+ return l;
+ }
+ return QVariantValueHelper<QVariantHash>::invoke(v);
+ }
+ };
+ template<>
+ struct QVariantValueHelperInterface<QVariantMap>
+ {
+ static QVariantMap invoke(const QVariant &v)
+ {
+ if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QAssociativeIterableImpl>())) {
+ QAssociativeIterable iter = QVariantValueHelperInterface<QAssociativeIterable>::invoke(v);
+ QVariantMap l;
+ for (QAssociativeIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
+ l.insert(it.key().toString(), it.value());
+ return l;
+ }
+ return QVariantValueHelper<QVariantMap>::invoke(v);
+ }
+ };
}
template<typename T> inline T qvariant_cast(const QVariant &v)