summaryrefslogtreecommitdiffstats
path: root/src/corelib/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r--src/corelib/kernel/qcore_mac_p.h6
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp61
-rw-r--r--src/corelib/kernel/qeventdispatcher_blackberry.cpp82
-rw-r--r--src/corelib/kernel/qmetaobjectbuilder.cpp2
-rw-r--r--src/corelib/kernel/qmetatype.cpp285
-rw-r--r--src/corelib/kernel/qmetatype.h1134
-rw-r--r--src/corelib/kernel/qobject.cpp62
-rw-r--r--src/corelib/kernel/qobject_p.h7
-rw-r--r--src/corelib/kernel/qobjectdefs.h1
-rw-r--r--src/corelib/kernel/qsocketnotifier.cpp9
-rw-r--r--src/corelib/kernel/qvariant.cpp591
-rw-r--r--src/corelib/kernel/qvariant.h299
12 files changed, 2397 insertions, 142 deletions
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index f0899c6dee..fa911fb967 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -75,6 +75,12 @@
#include "qstring.h"
+#if defined( __OBJC__) && defined(QT_NAMESPACE)
+#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__) @compatibility_alias __KLASS__ QT_MANGLE_NAMESPACE(__KLASS__)
+#else
+#define QT_NAMESPACE_ALIAS_OBJC_CLASS(__KLASS__)
+#endif
+
QT_BEGIN_NAMESPACE
/*
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index a7b14b22b5..bba878d2eb 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -589,6 +589,8 @@ void QCoreApplicationPrivate::initLocale()
Note that some arguments supplied by the user may have been
processed and removed by QCoreApplication.
+ For more advanced command line option handling, create a QCommandLineParser.
+
\section1 Locale Settings
On Unix/Linux Qt is configured to use the system locale settings by
@@ -1950,7 +1952,6 @@ QString QCoreApplication::applicationFilePath()
char buff[maximum_path+1];
if (_cmdname(buff)) {
d->cachedApplicationFilePath = QDir::cleanPath(QString::fromLocal8Bit(buff));
- return d->cachedApplicationFilePath;
} else {
qWarning("QCoreApplication::applicationFilePath: _cmdname() failed");
// _cmdname() won't fail, but just in case, fallback to the old method
@@ -1959,11 +1960,11 @@ QString QCoreApplication::applicationFilePath()
if (!executables.empty()) {
//We assume that there is only one executable in the folder
d->cachedApplicationFilePath = dir.absoluteFilePath(executables.first());
- return d->cachedApplicationFilePath;
} else {
- return QString();
+ d->cachedApplicationFilePath = QString();
}
}
+ return d->cachedApplicationFilePath;
#elif defined(Q_OS_MAC)
QString qAppFileName_str = qAppFileName();
if(!qAppFileName_str.isEmpty()) {
@@ -1982,34 +1983,38 @@ QString QCoreApplication::applicationFilePath()
return d->cachedApplicationFilePath;
}
# endif
+ if (!arguments().isEmpty()) {
+ QString argv0 = QFile::decodeName(arguments().at(0).toLocal8Bit());
+ QString absPath;
+
+ if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
+ /*
+ If argv0 starts with a slash, it is already an absolute
+ file path.
+ */
+ absPath = argv0;
+ } else if (argv0.contains(QLatin1Char('/'))) {
+ /*
+ If argv0 contains one or more slashes, it is a file path
+ relative to the current directory.
+ */
+ absPath = QDir::current().absoluteFilePath(argv0);
+ } else {
+ /*
+ Otherwise, the file path has to be determined using the
+ PATH environment variable.
+ */
+ absPath = QStandardPaths::findExecutable(argv0);
+ }
+
+ absPath = QDir::cleanPath(absPath);
- QString argv0 = QFile::decodeName(arguments().at(0).toLocal8Bit());
- QString absPath;
-
- if (!argv0.isEmpty() && argv0.at(0) == QLatin1Char('/')) {
- /*
- If argv0 starts with a slash, it is already an absolute
- file path.
- */
- absPath = argv0;
- } else if (argv0.contains(QLatin1Char('/'))) {
- /*
- If argv0 contains one or more slashes, it is a file path
- relative to the current directory.
- */
- absPath = QDir::current().absoluteFilePath(argv0);
+ QFileInfo fi(absPath);
+ d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString();
} else {
- /*
- Otherwise, the file path has to be determined using the
- PATH environment variable.
- */
- absPath = QStandardPaths::findExecutable(argv0);
+ d->cachedApplicationFilePath = QString();
}
- absPath = QDir::cleanPath(absPath);
-
- QFileInfo fi(absPath);
- d->cachedApplicationFilePath = fi.exists() ? fi.canonicalFilePath() : QString();
return d->cachedApplicationFilePath;
#endif
}
@@ -2057,7 +2062,7 @@ qint64 QCoreApplication::applicationPid()
As a result of this, the string given by arguments().at(0) might not be
the program name on Windows, depending on how the application was started.
- \sa applicationFilePath()
+ \sa applicationFilePath(), QCommandLineParser
*/
QStringList QCoreApplication::arguments()
diff --git a/src/corelib/kernel/qeventdispatcher_blackberry.cpp b/src/corelib/kernel/qeventdispatcher_blackberry.cpp
index f90f2e3268..d9e38b68b2 100644
--- a/src/corelib/kernel/qeventdispatcher_blackberry.cpp
+++ b/src/corelib/kernel/qeventdispatcher_blackberry.cpp
@@ -128,16 +128,16 @@ static int bpsIOHandler(int fd, int io_events, void *data)
// create unblock event
bps_event_t *event;
int result = bps_event_create(&event, bpsUnblockDomain, 0, NULL, NULL);
- if (result != BPS_SUCCESS) {
- qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_event_create() failed");
+ if (Q_UNLIKELY(result != BPS_SUCCESS)) {
+ qWarning("QEventDispatcherBlackberry: bps_event_create failed");
return BPS_FAILURE;
}
// post unblock event to our thread; in this callback the bps channel is
// guaranteed to be the same that was active when bps_add_fd was called
result = bps_push_event(event);
- if (result != BPS_SUCCESS) {
- qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_push_event() failed");
+ if (Q_UNLIKELY(result != BPS_SUCCESS)) {
+ qWarning("QEventDispatcherBlackberry: bps_push_event failed");
bps_event_destroy(event);
return BPS_FAILURE;
}
@@ -151,16 +151,16 @@ QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberryPrivate()
{
// prepare to use BPS
int result = bps_initialize();
- if (result != BPS_SUCCESS)
- qFatal("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_initialize() failed");
+ if (Q_UNLIKELY(result != BPS_SUCCESS))
+ qFatal("QEventDispatcherBlackberry: bps_initialize failed");
bps_channel = bps_channel_get_active();
// get domain for IO ready and wake up events - ignoring race condition here for now
if (bpsUnblockDomain == -1) {
bpsUnblockDomain = bps_register_domain();
- if (bpsUnblockDomain == -1)
- qWarning("QEventDispatcherBlackberryPrivate::QEventDispatcherBlackberry: bps_register_domain() failed");
+ if (Q_UNLIKELY(bpsUnblockDomain == -1))
+ qWarning("QEventDispatcherBlackberry: bps_register_domain failed");
}
}
@@ -202,21 +202,26 @@ void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifie
Q_ASSERT(notifier);
Q_D(QEventDispatcherBlackberry);
- BpsChannelScopeSwitcher channelSwitcher(d->bps_channel);
-
- // Register the fd with bps
int sockfd = notifier->socket();
int type = notifier->type();
- qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd;
- int io_events = ioEvents(sockfd);
+ qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd;
- if (io_events)
- bps_remove_fd(sockfd);
+ if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) {
+ qWarning() << "QEventDispatcherBlackberry: cannot register QSocketNotifier (fd too high)"
+ << sockfd;
+ return;
+ }
// Call the base Unix implementation. Needed to allow select() to be called correctly
QEventDispatcherUNIX::registerSocketNotifier(notifier);
+ // Register the fd with bps
+ BpsChannelScopeSwitcher channelSwitcher(d->bps_channel);
+ int io_events = ioEvents(sockfd);
+ if (io_events)
+ bps_remove_fd(sockfd);
+
switch (type) {
case QSocketNotifier::Read:
qEventDispatcherDebug << "Registering" << sockfd << "for Reads";
@@ -233,44 +238,41 @@ void QEventDispatcherBlackberry::registerSocketNotifier(QSocketNotifier *notifie
break;
}
- errno = 0;
- int result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data());
-
- if (result != BPS_SUCCESS)
- qWarning() << Q_FUNC_INFO << "bps_add_fd() failed" << strerror(errno) << "code:" << errno;
+ const int result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data());
+ if (Q_UNLIKELY(result != BPS_SUCCESS))
+ qWarning() << "QEventDispatcherBlackberry: bps_add_fd failed";
}
void QEventDispatcherBlackberry::unregisterSocketNotifier(QSocketNotifier *notifier)
{
Q_D(QEventDispatcherBlackberry);
- BpsChannelScopeSwitcher channelSwitcher(d->bps_channel);
+ int sockfd = notifier->socket();
+
+ qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd;
+
+ if (Q_UNLIKELY(sockfd >= FD_SETSIZE)) {
+ qWarning() << "QEventDispatcherBlackberry: cannot unregister QSocketNotifier" << sockfd;
+ return;
+ }
// Allow the base Unix implementation to unregister the fd too
QEventDispatcherUNIX::unregisterSocketNotifier(notifier);
// Unregister the fd with bps
- int sockfd = notifier->socket();
- qEventDispatcherDebug << Q_FUNC_INFO << "fd =" << sockfd;
-
+ BpsChannelScopeSwitcher channelSwitcher(d->bps_channel);
const int io_events = ioEvents(sockfd);
-
int result = bps_remove_fd(sockfd);
- if (result != BPS_SUCCESS)
- qWarning() << Q_FUNC_INFO << "bps_remove_fd() failed" << sockfd;
-
+ if (Q_UNLIKELY(result != BPS_SUCCESS))
+ qWarning() << "QEventDispatcherBlackberry: bps_remove_fd failed" << sockfd;
- /* if no other socket notifier is
- * watching sockfd, our job ends here
- */
+ // if no other socket notifier is watching sockfd, our job ends here
if (!io_events)
return;
- errno = 0;
result = bps_add_fd(sockfd, io_events, &bpsIOHandler, d->ioData.data());
- if (result != BPS_SUCCESS) {
- qWarning() << Q_FUNC_INFO << "bps_add_fd() failed" << strerror(errno) << "code:" << errno;
- }
+ if (Q_UNLIKELY(result != BPS_SUCCESS))
+ qWarning("QEventDispatcherBlackberry: bps_add_fd error");
}
static inline int timespecToMillisecs(const timespec &tv)
@@ -358,8 +360,8 @@ int QEventDispatcherBlackberry::select(int nfds, fd_set *readfds, fd_set *writef
// Wait for event or file to be ready
const int result = bps_get_event(&event, timeoutLeft);
- if (result != BPS_SUCCESS)
- qWarning("QEventDispatcherBlackberry::select: bps_get_event() failed");
+ if (Q_UNLIKELY(result != BPS_SUCCESS))
+ qWarning("QEventDispatcherBlackberry: bps_get_event failed");
}
if (!event) // In case of !event, we break out of the loop to let Qt process the timers
@@ -392,13 +394,13 @@ void QEventDispatcherBlackberry::wakeUp()
Q_D(QEventDispatcherBlackberry);
if (d->wakeUps.testAndSetAcquire(0, 1)) {
bps_event_t *event;
- if (bps_event_create(&event, bpsUnblockDomain, 0, 0, 0) == BPS_SUCCESS) {
- if (bps_channel_push_event(d->bps_channel, event) == BPS_SUCCESS)
+ if (Q_LIKELY(bps_event_create(&event, bpsUnblockDomain, 0, 0, 0) == BPS_SUCCESS)) {
+ if (Q_LIKELY(bps_channel_push_event(d->bps_channel, event) == BPS_SUCCESS))
return;
else
bps_event_destroy(event);
}
- qWarning("QEventDispatcherBlackberryPrivate::wakeUp failed");
+ qWarning("QEventDispatcherBlackberry: wakeUp failed");
}
}
diff --git a/src/corelib/kernel/qmetaobjectbuilder.cpp b/src/corelib/kernel/qmetaobjectbuilder.cpp
index 96450f9441..4c727f9d3d 100644
--- a/src/corelib/kernel/qmetaobjectbuilder.cpp
+++ b/src/corelib/kernel/qmetaobjectbuilder.cpp
@@ -90,7 +90,7 @@ Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type)
} // namespace QtPrivate
// copied from qmetaobject.cpp
-static inline const QMetaObjectPrivate *priv(const uint* data)
+static inline Q_DECL_UNUSED const QMetaObjectPrivate *priv(const uint* data)
{ return reinterpret_cast<const QMetaObjectPrivate*>(data); }
class QMetaMethodBuilderPrivate
diff --git a/src/corelib/kernel/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp
index 50f3a1814b..17fbbda720 100644
--- a/src/corelib/kernel/qmetatype.cpp
+++ b/src/corelib/kernel/qmetatype.cpp
@@ -421,6 +421,56 @@ public:
int alias;
};
+template<typename T, typename Key>
+class QMetaTypeFunctionRegistry
+{
+public:
+ ~QMetaTypeFunctionRegistry()
+ {
+ const QWriteLocker locker(&lock);
+ map.clear();
+ }
+
+ bool contains(Key k) const
+ {
+ const QReadLocker locker(&lock);
+ return map.contains(k);
+ }
+
+ bool insertIfNotContains(Key k, const T *f)
+ {
+ const QWriteLocker locker(&lock);
+ const T* &fun = map[k];
+ if (fun != 0)
+ return false;
+ fun = f;
+ return true;
+ }
+
+ const T *function(Key k) const
+ {
+ const QReadLocker locker(&lock);
+ return map.value(k, 0);
+ }
+
+ void remove(int from, int to)
+ {
+ const Key k(from, to);
+ const QWriteLocker locker(&lock);
+ map.remove(k);
+ }
+private:
+ mutable QReadWriteLock lock;
+ QHash<Key, const T *> map;
+};
+
+typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractConverterFunction,QPair<int,int> >
+QMetaTypeConverterRegistry;
+typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractComparatorFunction,int>
+QMetaTypeComparatorRegistry;
+typedef QMetaTypeFunctionRegistry<QtPrivate::AbstractDebugStreamFunction,int>
+QMetaTypeDebugStreamRegistry;
+
namespace
{
union CheckThatItIsPod
@@ -432,6 +482,200 @@ union CheckThatItIsPod
Q_DECLARE_TYPEINFO(QCustomTypeInfo, Q_MOVABLE_TYPE);
Q_GLOBAL_STATIC(QVector<QCustomTypeInfo>, customTypes)
Q_GLOBAL_STATIC(QReadWriteLock, customTypesLock)
+Q_GLOBAL_STATIC(QMetaTypeConverterRegistry, customTypesConversionRegistry)
+Q_GLOBAL_STATIC(QMetaTypeComparatorRegistry, customTypesComparatorRegistry)
+Q_GLOBAL_STATIC(QMetaTypeDebugStreamRegistry, customTypesDebugStreamRegistry)
+
+/*!
+ \fn bool QMetaType::registerConverter()
+ \since 5.2
+ Registers the possibility of an implicit conversion from type From to type To in the meta
+ type system. Returns true if the registration succeeded, otherwise false.
+*/
+
+/*!
+ \fn bool QMetaType::registerConverter(MemberFunction function)
+ \since 5.2
+ \overload
+ Registers a method \a function like To From::function() const as converter from type From
+ to type To in the meta type system. Returns true if the registration succeeded, otherwise false.
+*/
+
+/*!
+ \fn bool QMetaType::registerConverter(MemberFunctionOk function)
+ \since 5.2
+ \overload
+ Registers a method \a function like To From::function(bool *ok) const as converter from type From
+ to type To in the meta type system. Returns true if the registration succeeded, otherwise false.
+*/
+
+/*!
+ \fn bool QMetaType::registerConverter(UnaryFunction function)
+ \since 5.2
+ \overload
+ Registers a unary function object \a function as converter from type From
+ to type To in the meta type system. Returns true if the registration succeeded, otherwise false.
+*/
+
+/*!
+ \fn bool QMetaType::registerComparators()
+ \since 5.2
+ Registers comparison operetarors for the user-registered type T. This requires T to have
+ both an operator== and an operator<.
+ Returns true if the registration succeeded, otherwise false.
+*/
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ \fn bool QMetaType::registerDebugStreamOperator()
+ Registers the debug stream operator for the user-registered type T. This requires T to have
+ an operator<<(QDebug dbg, T).
+ Returns true if the registration succeeded, otherwise false.
+*/
+#endif
+
+/*!
+ Registers function \a f as converter function from type id \a from to \a to.
+ If there's already a conversion registered, this does nothing but deleting \a f.
+ Returns true if the registration succeeded, otherwise false.
+ \since 5.2
+ \internal
+*/
+bool QMetaType::registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to)
+{
+ if (!customTypesConversionRegistry()->insertIfNotContains(qMakePair(from, to), f)) {
+ qWarning("Type conversion already registered from type %s to type %s",
+ QMetaType::typeName(from), QMetaType::typeName(to));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \internal
+
+ Invoked automatically when a converter function object is destroyed.
+ */
+void QMetaType::unregisterConverterFunction(int from, int to)
+{
+ if (customTypesConversionRegistry.isDestroyed())
+ return;
+ customTypesConversionRegistry()->remove(from, to);
+}
+
+bool QMetaType::registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type)
+{
+ if (!customTypesComparatorRegistry()->insertIfNotContains(type, f)) {
+ qWarning("Comparators already registered for type %s", QMetaType::typeName(type));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn bool QMetaType::hasRegisteredComparators()
+ Returns true, if the meta type system has registered comparators for type T.
+ \since 5.2
+ */
+
+/*!
+ Returns true, if the meta type system has registered comparators for type id \a typeId.
+ \since 5.2
+ */
+bool QMetaType::hasRegisteredComparators(int typeId)
+{
+ return customTypesComparatorRegistry()->contains(typeId);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+bool QMetaType::registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f,
+ int type)
+{
+ if (!customTypesDebugStreamRegistry()->insertIfNotContains(type, f)) {
+ qWarning("Debug stream operator already registered for type %s", QMetaType::typeName(type));
+ return false;
+ }
+ return true;
+}
+
+/*!
+ \fn bool QMetaType::hasRegisteredDebugStreamOperator()
+ Returns true, if the meta type system has a registered debug stream operator for type T.
+ \since 5.2
+ */
+
+/*!
+ Returns true, if the meta type system has a registered debug stream operator for type
+ id \a typeId.
+ \since 5.2
+*/
+bool QMetaType::hasRegisteredDebugStreamOperator(int typeId)
+{
+ return customTypesDebugStreamRegistry()->contains(typeId);
+}
+#endif
+
+/*!
+ Converts the object at \a from from \a fromTypeId to the preallocated space at \a to
+ typed \a toTypeId. Returns true, if the conversion succeeded, otherwise false.
+ \since 5.2
+*/
+bool QMetaType::convert(const void *from, int fromTypeId, void *to, int toTypeId)
+{
+ const QtPrivate::AbstractConverterFunction * const f =
+ customTypesConversionRegistry()->function(qMakePair(fromTypeId, toTypeId));
+ return f && f->convert(f, from, to);
+}
+
+/*!
+ Compares the objects at \a lhs and \a rhs. Both objects need to be of type \a typeId.
+ \a result is set to less than, equal to or greater than zero, if \a lhs is less than, equal to
+ or greater than \a rhs. Returns true, if the comparison succeeded, otherwiess false.
+ \since 5.2
+*/
+bool QMetaType::compare(const void *lhs, const void *rhs, int typeId, int* result)
+{
+ const QtPrivate::AbstractComparatorFunction * const f =
+ customTypesComparatorRegistry()->function(typeId);
+ if (!f)
+ return false;
+ if (f->equals(f, lhs, rhs))
+ *result = 0;
+ else
+ *result = f->lessThan(f, lhs, rhs) ? -1 : 1;
+ return true;
+}
+
+/*!
+ Streams the object at \a rhs of type \a typeId to the debug stream \a dbg. Returns true
+ on success, otherwise false.
+ \since 5.2
+*/
+bool QMetaType::debugStream(QDebug& dbg, const void *rhs, int typeId)
+{
+ const QtPrivate::AbstractDebugStreamFunction * const f = customTypesDebugStreamRegistry()->function(typeId);
+ if (!f)
+ return false;
+ f->stream(f, dbg, rhs);
+ return true;
+}
+
+/*!
+ \fn bool QMetaType::hasRegisteredConverterFunction()
+ Returns true, if the meta type system has a registered conversion from type From to type To.
+ \since 5.2
+ \overload
+ */
+
+/*!
+ Returns true, if the meta type system has a registered conversion from meta type id \a fromTypeId
+ to \a toTypeId
+ \since 5.2
+*/
+bool QMetaType::hasRegisteredConverterFunction(int fromTypeId, int toTypeId)
+{
+ return customTypesConversionRegistry()->contains(qMakePair(fromTypeId, toTypeId));
+}
#ifndef QT_NO_DATASTREAM
/*!
@@ -723,11 +967,11 @@ int QMetaType::registerNormalizedTypedef(const NS(QByteArray) &normalizedTypeNam
}
if (idx != aliasId) {
- qFatal("QMetaType::registerTypedef: Binary compatibility break "
- "-- Type name '%s' previously registered as typedef of '%s' [%i], "
- "now registering as typedef of '%s' [%i].",
- normalizedTypeName.constData(), QMetaType::typeName(idx), idx,
- QMetaType::typeName(aliasId), aliasId);
+ qWarning("QMetaType::registerTypedef: "
+ "-- Type name '%s' previously registered as typedef of '%s' [%i], "
+ "now registering as typedef of '%s' [%i].",
+ normalizedTypeName.constData(), QMetaType::typeName(idx), idx,
+ QMetaType::typeName(aliasId), aliasId);
}
return idx;
}
@@ -1841,6 +2085,37 @@ const QMetaObject *QMetaType::metaObjectForType(int type)
\sa Q_DECLARE_METATYPE(), QMetaType::type()
*/
+/*!
+ \fn bool qRegisterSequentialConverter()
+ \relates QMetaType
+ \since 5.2
+
+ Registers a sequential container so that it can be converted to
+ a QVariantList. If compilation fails, then you probably forgot to
+ Q_DECLARE_METATYPE the value type.
+
+ Note that it is not necessary to call this method for Qt containers (QList,
+ QVector etc) or for std::vector or std::list. Such containers are automatically
+ registered by Qt.
+
+ \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 5763bcc07b..6b1a988fce 100644
--- a/src/corelib/kernel/qmetatype.h
+++ b/src/corelib/kernel/qmetatype.h
@@ -47,17 +47,27 @@
#include <QtCore/qbytearray.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qisenum.h>
+#include <QtCore/qtypetraits.h>
#ifndef QT_NO_QOBJECT
#include <QtCore/qobjectdefs.h>
#endif
#include <new>
+#include <vector>
+#include <list>
+#include <map>
+
#ifdef Bool
#error qmetatype.h must be included before any header file that defines Bool
#endif
QT_BEGIN_NAMESPACE
+template <typename T>
+struct QMetaTypeId2;
+
+template <typename T>
+inline Q_DECL_CONSTEXPR int qMetaTypeId();
// F is a tuple: (QMetaType::TypeName, QMetaType::TypeNameID, RealType)
#define QT_FOR_EACH_STATIC_PRIMITIVE_TYPE(F)\
@@ -183,10 +193,188 @@ QT_BEGIN_NAMESPACE
#define QT_DEFINE_METATYPE_ID(TypeName, Id, Name) \
TypeName = Id,
+#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
+ F(QList) \
+ F(QVector) \
+ F(QQueue) \
+ F(QStack) \
+ F(QSet) \
+ F(QLinkedList)
+
+#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
+ F(QHash, class) \
+ F(QMap, class) \
+ F(QPair, struct)
+
+#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
+ F(QSharedPointer) \
+ F(QWeakPointer) \
+ F(QPointer)
+
class QDataStream;
class QMetaTypeInterface;
struct QMetaObject;
+namespace QtPrivate
+{
+/*!
+ This template is used for implicit conversion from type From to type To.
+ \internal
+*/
+template<typename From, typename To>
+To convertImplicit(const From& from)
+{
+ return from;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+struct AbstractDebugStreamFunction
+{
+ typedef void (*Stream)(const AbstractDebugStreamFunction *, QDebug&, const void *);
+ typedef void (*Destroy)(AbstractDebugStreamFunction *);
+ explicit AbstractDebugStreamFunction(Stream s = 0, Destroy d = 0)
+ : stream(s), destroy(d) {}
+ Q_DISABLE_COPY(AbstractDebugStreamFunction)
+ Stream stream;
+ Destroy destroy;
+};
+
+template<typename T>
+struct BuiltInDebugStreamFunction : public AbstractDebugStreamFunction
+{
+ BuiltInDebugStreamFunction()
+ : AbstractDebugStreamFunction(stream, destroy) {}
+ static void stream(const AbstractDebugStreamFunction *, QDebug& dbg, const void *r)
+ {
+ const T *rhs = static_cast<const T *>(r);
+ operator<<(dbg, *rhs);
+ }
+
+ static void destroy(AbstractDebugStreamFunction *_this)
+ {
+ delete static_cast<BuiltInDebugStreamFunction *>(_this);
+ }
+};
+#endif
+
+struct AbstractComparatorFunction
+{
+ typedef bool (*LessThan)(const AbstractComparatorFunction *, const void *, const void *);
+ typedef bool (*Equals)(const AbstractComparatorFunction *, const void *, const void *);
+ typedef void (*Destroy)(AbstractComparatorFunction *);
+ explicit AbstractComparatorFunction(LessThan lt = 0, Equals e = 0, Destroy d = 0)
+ : lessThan(lt), equals(e), destroy(d) {}
+ Q_DISABLE_COPY(AbstractComparatorFunction)
+ LessThan lessThan;
+ Equals equals;
+ Destroy destroy;
+};
+
+template<typename T>
+struct BuiltInComparatorFunction : public AbstractComparatorFunction
+{
+ BuiltInComparatorFunction()
+ : AbstractComparatorFunction(lessThan, equals, destroy) {}
+ static bool lessThan(const AbstractComparatorFunction *, const void *l, const void *r)
+ {
+ const T *lhs = static_cast<const T *>(l);
+ const T *rhs = static_cast<const T *>(r);
+ return *lhs < *rhs;
+ }
+
+ static bool equals(const AbstractComparatorFunction *, const void *l, const void *r)
+ {
+ const T *lhs = static_cast<const T *>(l);
+ const T *rhs = static_cast<const T *>(r);
+ return *lhs == *rhs;
+ }
+
+ static void destroy(AbstractComparatorFunction *_this)
+ {
+ delete static_cast<BuiltInComparatorFunction *>(_this);
+ }
+};
+
+struct AbstractConverterFunction
+{
+ typedef bool (*Converter)(const AbstractConverterFunction *, const void *, void*);
+ explicit AbstractConverterFunction(Converter c = 0)
+ : convert(c) {}
+ Q_DISABLE_COPY(AbstractConverterFunction)
+ Converter convert;
+};
+
+template<typename From, typename To>
+struct ConverterMemberFunction : public AbstractConverterFunction
+{
+ explicit ConverterMemberFunction(To(From::*function)() const)
+ : AbstractConverterFunction(convert),
+ m_function(function) {}
+ ~ConverterMemberFunction();
+ static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
+ {
+ const From *f = static_cast<const From *>(in);
+ To *t = static_cast<To *>(out);
+ const ConverterMemberFunction *_typedThis =
+ static_cast<const ConverterMemberFunction *>(_this);
+ *t = (f->*_typedThis->m_function)();
+ return true;
+ }
+
+ To(From::* const m_function)() const;
+};
+
+template<typename From, typename To>
+struct ConverterMemberFunctionOk : public AbstractConverterFunction
+{
+ explicit ConverterMemberFunctionOk(To(From::*function)(bool *) const)
+ : AbstractConverterFunction(convert),
+ m_function(function) {}
+ ~ConverterMemberFunctionOk();
+ static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
+ {
+ const From *f = static_cast<const From *>(in);
+ To *t = static_cast<To *>(out);
+ bool ok = false;
+ const ConverterMemberFunctionOk *_typedThis =
+ static_cast<const ConverterMemberFunctionOk *>(_this);
+ *t = (f->*_typedThis->m_function)(&ok);
+ if (!ok)
+ *t = To();
+ return ok;
+ }
+
+ To(From::* const m_function)(bool*) const;
+};
+
+template<typename From, typename To, typename UnaryFunction>
+struct ConverterFunctor : public AbstractConverterFunction
+{
+ explicit ConverterFunctor(UnaryFunction function)
+ : AbstractConverterFunction(convert),
+ m_function(function) {}
+ ~ConverterFunctor();
+ static bool convert(const AbstractConverterFunction *_this, const void *in, void *out)
+ {
+ const From *f = static_cast<const From *>(in);
+ To *t = static_cast<To *>(out);
+ const ConverterFunctor *_typedThis =
+ static_cast<const ConverterFunctor *>(_this);
+ *t = _typedThis->m_function(*f);
+ return true;
+ }
+
+ UnaryFunction m_function;
+};
+
+ template<typename T, bool>
+ struct ValueTypeIsMetaType;
+ template<typename T, bool>
+ struct AssociativeValueTypeIsMetaType;
+ template<typename T, bool>
+ struct IsMetaTypePair;
+}
+
class Q_CORE_EXPORT QMetaType {
enum ExtensionFlag { NoExtensionFlags,
CreateEx = 0x1, DestroyEx = 0x2,
@@ -320,6 +508,109 @@ public:
inline void destroy(void *data) const;
inline void *construct(void *where, const void *copy = 0) const;
inline void destruct(void *data) const;
+
+public:
+ template<typename T>
+ static bool registerComparators()
+ {
+ Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn),
+ "QMetaType::registerComparators: The type must be a custom type.");
+
+ const int typeId = qMetaTypeId<T>();
+ static const QtPrivate::BuiltInComparatorFunction<T> f;
+ return registerComparatorFunction( &f, typeId);
+ }
+ template<typename T>
+ static bool hasRegisteredComparators()
+ {
+ return hasRegisteredComparators(qMetaTypeId<T>());
+ }
+ static bool hasRegisteredComparators(int typeId);
+
+
+#ifndef QT_NO_DEBUG_STREAM
+ template<typename T>
+ static bool registerDebugStreamOperator()
+ {
+ Q_STATIC_ASSERT_X((!QMetaTypeId2<T>::IsBuiltIn),
+ "QMetaType::registerDebugStreamOperator: The type must be a custom type.");
+
+ const int typeId = qMetaTypeId<T>();
+ static const QtPrivate::BuiltInDebugStreamFunction<T> f;
+ return registerDebugStreamOperatorFunction(&f, typeId);
+ }
+ template<typename T>
+ static bool hasRegisteredDebugStreamOperator()
+ {
+ return hasRegisteredDebugStreamOperator(qMetaTypeId<T>());
+ }
+ static bool hasRegisteredDebugStreamOperator(int typeId);
+#endif
+
+ // implicit conversion supported like double -> float
+ template<typename From, typename To>
+ static bool registerConverter()
+ {
+ return registerConverter<From, To>(QtPrivate::convertImplicit<From, To>);
+ }
+
+#ifdef Q_QDOC
+ static bool registerConverter(MemberFunction function);
+ static bool registerConverter(MemberFunctionOk function);
+ static bool registerConverter(UnaryFunction function);
+#else
+ // member function as in "QString QFont::toString() const"
+ template<typename From, typename To>
+ static bool registerConverter(To(From::*function)() const)
+ {
+ Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
+ "QMetaType::registerConverter: At least one of the types must be a custom type.");
+
+ const int fromTypeId = qMetaTypeId<From>();
+ const int toTypeId = qMetaTypeId<To>();
+ static const QtPrivate::ConverterMemberFunction<From, To> f(function);
+ return registerConverterFunction(&f, fromTypeId, toTypeId);
+ }
+
+ // member function as in "double QString::toDouble(bool *ok = 0) const"
+ template<typename From, typename To>
+ static bool registerConverter(To(From::*function)(bool*) const)
+ {
+ Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
+ "QMetaType::registerConverter: At least one of the types must be a custom type.");
+
+ const int fromTypeId = qMetaTypeId<From>();
+ const int toTypeId = qMetaTypeId<To>();
+ static const QtPrivate::ConverterMemberFunctionOk<From, To> f(function);
+ return registerConverterFunction(&f, fromTypeId, toTypeId);
+ }
+
+ // functor or function pointer
+ template<typename From, typename To, typename UnaryFunction>
+ static bool registerConverter(UnaryFunction function)
+ {
+ Q_STATIC_ASSERT_X((!QMetaTypeId2<To>::IsBuiltIn || !QMetaTypeId2<From>::IsBuiltIn),
+ "QMetaType::registerConverter: At least one of the types must be a custom type.");
+
+ const int fromTypeId = qMetaTypeId<From>();
+ const int toTypeId = qMetaTypeId<To>();
+ static const QtPrivate::ConverterFunctor<From, To, UnaryFunction> f(function);
+ return registerConverterFunction(&f, fromTypeId, toTypeId);
+ }
+#endif
+
+ static bool convert(const void *from, int fromTypeId, void *to, int toTypeId);
+ static bool compare(const void *lhs, const void *rhs, int typeId, int* result);
+ static bool debugStream(QDebug& dbg, const void *rhs, int typeId);
+
+ template<typename From, typename To>
+ static bool hasRegisteredConverterFunction()
+ {
+ return hasRegisteredConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>());
+ }
+
+ static bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId);
+
private:
static QMetaType typeInfo(const int type);
inline QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
@@ -348,6 +639,31 @@ private:
void *constructExtended(void *where, const void *copy = 0) const;
void destructExtended(void *data) const;
+ static bool registerComparatorFunction(const QtPrivate::AbstractComparatorFunction *f, int type);
+#ifndef QT_NO_DEBUG_STREAM
+ static bool registerDebugStreamOperatorFunction(const QtPrivate::AbstractDebugStreamFunction *f, int type);
+#endif
+
+#ifndef Q_NO_TEMPLATE_FRIENDS
+#ifndef Q_QDOC
+ template<typename T>
+ friend bool qRegisterSequentialConverter();
+ template<typename, bool> friend struct QtPrivate::ValueTypeIsMetaType;
+ 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;
+ template<typename, bool> friend struct QtPrivate::IsMetaTypePair;
+#endif
+#else
+public:
+#endif
+ static bool registerConverterFunction(const QtPrivate::AbstractConverterFunction *f, int from, int to);
+ static void unregisterConverterFunction(int from, int to);
+private:
+
Creator m_creator;
Deleter m_deleter;
SaveOperator m_saveOp;
@@ -366,6 +682,26 @@ private:
Q_DECLARE_OPERATORS_FOR_FLAGS(QMetaType::TypeFlags)
+namespace QtPrivate {
+
+template<typename From, typename To>
+ConverterMemberFunction<From, To>::~ConverterMemberFunction()
+{
+ QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>());
+}
+template<typename From, typename To>
+ConverterMemberFunctionOk<From, To>::~ConverterMemberFunctionOk()
+{
+ QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>());
+}
+template<typename From, typename To, typename UnaryFunction>
+ConverterFunctor<From, To, UnaryFunction>::~ConverterFunctor()
+{
+ QMetaType::unregisterConverterFunction(qMetaTypeId<From>(), qMetaTypeId<To>());
+}
+
+}
+
namespace QtMetaTypePrivate {
template <typename T, bool Accepted = true>
struct QMetaTypeFunctionHelper {
@@ -421,13 +757,493 @@ template <>
struct QMetaTypeFunctionHelper<void, /* Accepted */ true>
: public QMetaTypeFunctionHelper<void, /* Accepted */ false>
{};
+
+struct VariantData
+{
+ VariantData(const int metaTypeId_,
+ const void *data_,
+ const uint flags_)
+ : metaTypeId(metaTypeId_)
+ , data(data_)
+ , flags(flags_)
+ {
+ }
+ const int metaTypeId;
+ const void *data;
+ const uint flags;
+};
+
+template<typename const_iterator>
+struct IteratorOwner
+{
+ static void assign(void **ptr, const_iterator iterator)
+ {
+ *ptr = new const_iterator(iterator);
+ }
+
+ 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 const void *getData(void * const *iterator)
+ {
+ return &**static_cast<const_iterator*>(*iterator);
+ }
+
+ static const void *getData(const_iterator it)
+ {
+ return &*it;
+ }
+};
+template<typename const_iterator>
+struct IteratorOwner<const const_iterator*>
+{
+ static void assign(void **ptr, const const_iterator *iterator )
+ {
+ *ptr = const_cast<const_iterator*>(iterator);
+ }
+
+ static void advance(void **iterator, int step)
+ {
+ const_iterator *it = static_cast<const_iterator*>(*iterator);
+ std::advance(it, step);
+ *iterator = it;
+ }
+
+ static void destroy(void **)
+ {
+ }
+
+ static const void *getData(void * const *iterator)
+ {
+ return *iterator;
+ }
+
+ static const void *getData(const const_iterator *it)
+ {
+ return it;
+ }
+};
+
+enum IteratorCapability
+{
+ ForwardCapability = 1,
+ BiDirectionalCapability = 2,
+ RandomAccessCapability = 4
+};
+
+template<typename T, typename Category = typename std::iterator_traits<typename T::const_iterator>::iterator_category>
+struct CapabilitiesImpl;
+
+template<typename T>
+struct CapabilitiesImpl<T, std::forward_iterator_tag>
+{ enum { IteratorCapabilities = ForwardCapability }; };
+template<typename T>
+struct CapabilitiesImpl<T, std::bidirectional_iterator_tag>
+{ enum { IteratorCapabilities = BiDirectionalCapability | ForwardCapability }; };
+template<typename T>
+struct CapabilitiesImpl<T, std::random_access_iterator_tag>
+{ enum { IteratorCapabilities = RandomAccessCapability | BiDirectionalCapability | ForwardCapability }; };
+
+template<typename T>
+struct ContainerAPI : CapabilitiesImpl<T>
+{
+ static int size(const T *t) { return std::distance(t->begin(), t->end()); }
+};
+
+template<typename T>
+struct ContainerAPI<QList<T> > : CapabilitiesImpl<QList<T> >
+{ static int size(const QList<T> *t) { return t->size(); } };
+
+template<typename T>
+struct ContainerAPI<QVector<T> > : CapabilitiesImpl<QVector<T> >
+{ static int size(const QVector<T> *t) { return t->size(); } };
+
+template<typename T>
+struct ContainerAPI<std::vector<T> > : CapabilitiesImpl<std::vector<T> >
+{ static int size(const std::vector<T> *t) { return t->size(); } };
+
+template<typename T>
+struct ContainerAPI<std::list<T> > : CapabilitiesImpl<std::list<T> >
+{ static int size(const std::list<T> *t) { return t->size(); } };
+
+class QSequentialIterableImpl
+{
+public:
+ const void * _iterable;
+ void *_iterator;
+ int _metaType_id;
+ uint _metaType_flags;
+ uint _iteratorCapabilities;
+ typedef int(*sizeFunc)(const void *p);
+ typedef const void * (*atFunc)(const void *p, int);
+ typedef void (*moveIteratorFunc)(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;
+ atFunc _at;
+ moveIteratorFunc _moveToBegin;
+ moveIteratorFunc _moveToEnd;
+ advanceFunc _advance;
+ getFunc _get;
+ destroyIterFunc _destroyIter;
+ equalIterFunc _equalIter;
+
+ template<class T>
+ static int sizeImpl(const void *p)
+ { return ContainerAPI<T>::size(static_cast<const T*>(p)); }
+
+ template<class T>
+ static const void* atImpl(const void *p, int idx)
+ {
+ typename T::const_iterator i = static_cast<const T*>(p)->begin();
+ std::advance(i, idx);
+ return IteratorOwner<typename T::const_iterator>::getData(i);
+ }
+
+ template<class T>
+ static void advanceImpl(void **p, int step)
+ { IteratorOwner<typename T::const_iterator>::advance(p, step); }
+
+ template<class T>
+ static void moveToBeginImpl(const void *container, void **iterator)
+ { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->begin()); }
+
+ template<class T>
+ static void moveToEndImpl(const void *container, void **iterator)
+ { IteratorOwner<typename T::const_iterator>::assign(iterator, static_cast<const T*>(container)->end()); }
+
+ 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); }
+
+ template<class T>
+ static VariantData getImpl(void * const *iterator, int metaTypeId, uint flags)
+ { return VariantData(metaTypeId, IteratorOwner<typename T::const_iterator>::getData(iterator), flags); }
+
+public:
+ template<class T> QSequentialIterableImpl(const T*p)
+ : _iterable(p)
+ , _iterator(0)
+ , _metaType_id(qMetaTypeId<typename T::value_type>())
+ , _metaType_flags(QTypeInfo<typename T::value_type>::isPointer)
+ , _iteratorCapabilities(ContainerAPI<T>::IteratorCapabilities)
+ , _size(sizeImpl<T>)
+ , _at(atImpl<T>)
+ , _moveToBegin(moveToBeginImpl<T>)
+ , _moveToEnd(moveToEndImpl<T>)
+ , _advance(advanceImpl<T>)
+ , _get(getImpl<T>)
+ , _destroyIter(destroyIterImpl<T>)
+ , _equalIter(equalIterImpl<T>)
+ {
+ }
+
+ QSequentialIterableImpl()
+ : _iterable(0)
+ , _iterator(0)
+ , _metaType_id(QMetaType::UnknownType)
+ , _metaType_flags(0)
+ , _iteratorCapabilities(0)
+ , _size(0)
+ , _at(0)
+ , _moveToBegin(0)
+ , _moveToEnd(0)
+ , _advance(0)
+ , _get(0)
+ , _destroyIter(0)
+ , _equalIter(0)
+ {
+ }
+
+ inline void moveToBegin() { _moveToBegin(_iterable, &_iterator); }
+ inline void moveToEnd() { _moveToEnd(_iterable, &_iterator); }
+ inline bool equal(const QSequentialIterableImpl&other) const { return _equalIter(&_iterator, &other._iterator); }
+ inline QSequentialIterableImpl &advance(int i) {
+ Q_ASSERT(i > 0 || _iteratorCapabilities & BiDirectionalCapability);
+ _advance(&_iterator, i);
+ return *this;
+ }
+
+ inline VariantData getCurrent() const { return _get(&_iterator, _metaType_id, _metaType_flags); }
+
+ VariantData at(int idx) const
+ { return VariantData(_metaType_id, _at(_iterable, idx), _metaType_flags); }
+
+ int size() const { Q_ASSERT(_iterable); return _size(_iterable); }
+
+ inline void destroyIter() { _destroyIter(&_iterator); }
+};
+
+template<typename From>
+struct QSequentialIterableConvertFunctor
+{
+ QSequentialIterableConvertFunctor() {}
+
+ QSequentialIterableImpl operator()(const From &f) const
+ {
+ return QSequentialIterableImpl(&f);
+ }
+};
+}
+
+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 QPairVariantInterfaceImpl
+{
+ const void *_pair;
+ int _metaType_id_first;
+ uint _metaType_flags_first;
+ int _metaType_id_second;
+ uint _metaType_flags_second;
+
+ typedef VariantData (*getFunc)(const void * const *p, int metaTypeId, uint flags);
+
+ getFunc _getFirst;
+ getFunc _getSecond;
+
+ template<class T>
+ static VariantData getFirstImpl(const void * const *pair, int metaTypeId, uint flags)
+ { return VariantData(metaTypeId, &static_cast<const T*>(*pair)->first, flags); }
+ template<class T>
+ static VariantData getSecondImpl(const void * const *pair, int metaTypeId, uint flags)
+ { return VariantData(metaTypeId, &static_cast<const T*>(*pair)->second, flags); }
+
+public:
+ template<class T> QPairVariantInterfaceImpl(const T*p)
+ : _pair(p)
+ , _metaType_id_first(qMetaTypeId<typename T::first_type>())
+ , _metaType_flags_first(QTypeInfo<typename T::first_type>::isPointer)
+ , _metaType_id_second(qMetaTypeId<typename T::second_type>())
+ , _metaType_flags_second(QTypeInfo<typename T::second_type>::isPointer)
+ , _getFirst(getFirstImpl<T>)
+ , _getSecond(getSecondImpl<T>)
+ {
+ }
+
+ QPairVariantInterfaceImpl()
+ : _pair(0)
+ , _getFirst(0)
+ , _getSecond(0)
+ {
+ }
+
+ inline VariantData first() const { return _getFirst(&_pair, _metaType_id_first, _metaType_flags_first); }
+ inline VariantData second() const { return _getSecond(&_pair, _metaType_id_second, _metaType_flags_second); }
+};
+
+template<typename From>
+struct QPairVariantInterfaceConvertFunctor;
+
+template<typename T, typename U>
+struct QPairVariantInterfaceConvertFunctor<QPair<T, U> >
+{
+ QPairVariantInterfaceConvertFunctor() {}
+
+ QPairVariantInterfaceImpl operator()(const QPair<T, U>& f) const
+ {
+ return QPairVariantInterfaceImpl(&f);
+ }
+};
+
+template<typename T, typename U>
+struct QPairVariantInterfaceConvertFunctor<std::pair<T, U> >
+{
+ QPairVariantInterfaceConvertFunctor() {}
+
+ QPairVariantInterfaceImpl operator()(const std::pair<T, U>& f) const
+ {
+ return QPairVariantInterfaceImpl(&f);
+ }
+};
+
}
class QObject;
class QWidget;
-template <class T> class QSharedPointer;
-template <class T> class QWeakPointer;
-template <class T> class QPointer;
+
+#define QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER(Name) \
+ template <class T> class Name; \
+
+QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(QT_FORWARD_DECLARE_SHARED_POINTER_TYPES_ITER)
namespace QtPrivate
{
@@ -509,6 +1325,165 @@ namespace QtPrivate
enum { Value = true };
};
+ template<typename T>
+ struct IsSequentialContainer
+ {
+ enum { Value = false };
+ };
+
+#define QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE(CONTAINER) \
+ template<typename T> \
+ struct IsSequentialContainer<CONTAINER<T> > \
+ { \
+ enum { Value = true }; \
+ };
+ QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(QT_DEFINE_SEQUENTIAL_CONTAINER_TYPE)
+ 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
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T, bool = QMetaTypeId2<typename T::value_type>::Defined>
+ struct ValueTypeIsMetaType
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T>
+ struct ValueTypeIsMetaType<T, true>
+ {
+ static bool registerConverter(int id)
+ {
+ const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>();
+ if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ static const QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o;
+ static const QtPrivate::ConverterFunctor<T,
+ QtMetaTypePrivate::QSequentialIterableImpl,
+ QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o);
+ return QMetaType::registerConverterFunction(&f, id, toId);
+ }
+ return true;
+ }
+ };
+
+ template<typename T>
+ struct SequentialContainerConverterHelper<T, true> : ValueTypeIsMetaType<T>
+ {
+ };
+
+ 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>
+ {
+ };
+
+ template<typename T, bool = QMetaTypeId2<typename T::first_type>::Defined
+ && QMetaTypeId2<typename T::second_type>::Defined>
+ struct IsMetaTypePair
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+
+ template<typename T>
+ struct IsMetaTypePair<T, true>
+ {
+ inline static bool registerConverter(int id);
+ };
+
+ template<typename T>
+ struct IsPair
+ {
+ static bool registerConverter(int)
+ {
+ return false;
+ }
+ };
+ template<typename T, typename U>
+ struct IsPair<QPair<T, U> > : IsMetaTypePair<QPair<T, U> > {};
+ template<typename T, typename U>
+ struct IsPair<std::pair<T, U> > : IsMetaTypePair<std::pair<T, U> > {};
+
+ template<typename T>
+ struct MetaTypePairHelper : IsPair<T> {};
+
Q_CORE_EXPORT bool isBuiltinType(const QByteArray &type);
} // namespace QtPrivate
@@ -546,11 +1521,16 @@ namespace QtPrivate {
{ return -1; }
};
+#ifndef Q_COMPILER_VARIADIC_TEMPLATES
// Function pointers don't derive from QObject
template <class Result> struct IsPointerToTypeDerivedFromQObject<Result(*)()> { enum { Value = false }; };
template <class Result, class Arg0> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0)> { enum { Value = false }; };
template <class Result, class Arg0, class Arg1> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0, Arg1)> { enum { Value = false }; };
template <class Result, class Arg0, class Arg1, class Arg2> struct IsPointerToTypeDerivedFromQObject<Result(*)(Arg0, Arg1, Arg2)> { enum { Value = false }; };
+#else
+ template <typename Result, typename... Args>
+ struct IsPointerToTypeDerivedFromQObject<Result(*)(Args...)> { enum { Value = false }; };
+#endif
template<typename T>
struct QMetaTypeTypeFlags
@@ -593,7 +1573,7 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
if (defined)
flags |= QMetaType::WasDeclaredAsMetaType;
- return QMetaType::registerNormalizedType(normalizedTypeName,
+ const int id = QMetaType::registerNormalizedType(normalizedTypeName,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Delete,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Create,
QtMetaTypePrivate::QMetaTypeFunctionHelper<T>::Destruct,
@@ -601,6 +1581,14 @@ int qRegisterNormalizedMetaType(const QT_PREPEND_NAMESPACE(QByteArray) &normaliz
int(sizeof(T)),
flags,
QtPrivate::MetaObjectForType<T>::value());
+
+ if (id > 0) {
+ QtPrivate::SequentialContainerConverterHelper<T>::registerConverter(id);
+ QtPrivate::AssociativeContainerConverterHelper<T>::registerConverter(id);
+ QtPrivate::MetaTypePairHelper<T>::registerConverter(id);
+ }
+
+ return id;
}
template <typename T>
@@ -746,6 +1734,7 @@ typedef QMap<QString, QVariant> QVariantMap;
typedef QHash<QString, QVariant> QVariantHash;
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG(SINGLE_ARG_TEMPLATE) \
+QT_BEGIN_NAMESPACE \
template <typename T> \
struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
{ \
@@ -773,9 +1762,11 @@ struct QMetaTypeId< SINGLE_ARG_TEMPLATE<T> > \
metatype_id.storeRelease(newId); \
return newId; \
} \
-};
+}; \
+QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG(DOUBLE_ARG_TEMPLATE) \
+QT_BEGIN_NAMESPACE \
template<typename T, typename U> \
struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
{ \
@@ -806,19 +1797,30 @@ struct QMetaTypeId< DOUBLE_ARG_TEMPLATE<T, U> > \
metatype_id.storeRelease(newId); \
return newId; \
} \
+}; \
+QT_END_NAMESPACE
+
+namespace QtPrivate {
+
+template<typename T, bool /* isSharedPointerToQObjectDerived */ = false>
+struct SharedPointerMetaTypeIdHelper
+{
+ enum {
+ Defined = 0
+ };
+ static int qt_metatype_id()
+ {
+ return -1;
+ }
};
+}
+
#define Q_DECLARE_SMART_POINTER_METATYPE(SMART_POINTER) \
-template <typename T, bool = QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value> \
-struct QMetaTypeId_ ## SMART_POINTER ## _QObjectStar \
-{ \
- enum { \
- Defined = 0 \
- }; \
-};\
- \
-template <typename T> \
-struct QMetaTypeId_ ## SMART_POINTER ## _QObjectStar<T, true> \
+QT_BEGIN_NAMESPACE \
+namespace QtPrivate { \
+template<typename T> \
+struct SharedPointerMetaTypeIdHelper<SMART_POINTER<T>, true> \
{ \
enum { \
Defined = 1 \
@@ -840,51 +1842,51 @@ struct QMetaTypeId_ ## SMART_POINTER ## _QObjectStar<T, true> \
return newId; \
} \
}; \
-\
+} \
template <typename T> \
-struct QMetaTypeId< SMART_POINTER<T> > : public QMetaTypeId_ ## SMART_POINTER ## _QObjectStar<T> \
+struct QMetaTypeId< SMART_POINTER<T> > \
+ : QtPrivate::SharedPointerMetaTypeIdHelper< SMART_POINTER<T>, \
+ QtPrivate::IsPointerToTypeDerivedFromQObject<T*>::Value> \
{ \
-};
-
-#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(F) \
- F(QList) \
- F(QVector) \
- F(QQueue) \
- F(QStack) \
- F(QSet) \
- F(QLinkedList)
-
-#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(F) \
- F(QHash, class) \
- F(QMap, class) \
- F(QPair, struct)
-
-#define QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(F) \
- F(QSharedPointer) \
- F(QWeakPointer) \
- F(QPointer)
+};\
+QT_END_NAMESPACE
#define Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER(TEMPLATENAME) \
+ QT_BEGIN_NAMESPACE \
template <class T> class TEMPLATENAME; \
+ QT_END_NAMESPACE \
Q_DECLARE_METATYPE_TEMPLATE_1ARG(TEMPLATENAME)
+QT_END_NAMESPACE
+
QT_FOR_EACH_AUTOMATIC_TEMPLATE_1ARG(Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER)
#undef Q_DECLARE_METATYPE_TEMPLATE_1ARG_ITER
+Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::vector)
+Q_DECLARE_METATYPE_TEMPLATE_1ARG(std::list)
+
#define Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER(TEMPLATENAME, CPPTYPE) \
+ QT_BEGIN_NAMESPACE \
template <class T1, class T2> CPPTYPE TEMPLATENAME; \
+ QT_END_NAMESPACE \
Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME)
QT_FOR_EACH_AUTOMATIC_TEMPLATE_2ARG(Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER)
#undef Q_DECLARE_METATYPE_TEMPLATE_2ARG_ITER
+Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::pair)
+Q_DECLARE_METATYPE_TEMPLATE_2ARG(std::map)
+
#define Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER(TEMPLATENAME) \
Q_DECLARE_SMART_POINTER_METATYPE(TEMPLATENAME)
+
QT_FOR_EACH_AUTOMATIC_TEMPLATE_SMART_POINTER(Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER)
+QT_BEGIN_NAMESPACE
+
#undef Q_DECLARE_METATYPE_TEMPLATE_SMART_POINTER_ITER
inline QMetaType::QMetaType(const ExtensionFlag extensionFlags, const QMetaTypeInterface *info,
@@ -987,5 +1989,65 @@ QT_END_NAMESPACE
QT_FOR_EACH_STATIC_TYPE(Q_DECLARE_BUILTIN_METATYPE)
+Q_DECLARE_METATYPE(QtMetaTypePrivate::QSequentialIterableImpl)
+Q_DECLARE_METATYPE(QtMetaTypePrivate::QAssociativeIterableImpl)
+Q_DECLARE_METATYPE(QtMetaTypePrivate::QPairVariantInterfaceImpl)
+
+QT_BEGIN_NAMESPACE
+
+template <typename T>
+inline bool QtPrivate::IsMetaTypePair<T, true>::registerConverter(int id)
+{
+ const int toId = qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+ if (!QMetaType::hasRegisteredConverterFunction(id, toId)) {
+ static const QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> o;
+ static const QtPrivate::ConverterFunctor<T,
+ QtMetaTypePrivate::QPairVariantInterfaceImpl,
+ QtMetaTypePrivate::QPairVariantInterfaceConvertFunctor<T> > f(o);
+ return QMetaType::registerConverterFunction(&f, id, toId);
+ }
+ return true;
+}
+
+
+#ifndef Q_QDOC
+template<typename T>
+#endif
+bool qRegisterSequentialConverter()
+{
+ Q_STATIC_ASSERT_X(QMetaTypeId2<typename T::value_type>::Defined,
+ "The value_type of a sequential container must itself be a metatype.");
+ const int id = qMetaTypeId<T>();
+ const int toId = qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>();
+ if (QMetaType::hasRegisteredConverterFunction(id, toId))
+ return true;
+
+ static const QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> o;
+ static const QtPrivate::ConverterFunctor<T,
+ QtMetaTypePrivate::QSequentialIterableImpl,
+ QtMetaTypePrivate::QSequentialIterableConvertFunctor<T> > f(o);
+ 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
#endif // QMETATYPE_H
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 33e2adf5ba..b914ca812f 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -2346,6 +2346,7 @@ void QMetaObjectPrivate::memberIndexes(const QObject *obj,
}
}
+#ifndef QT_NO_DEBUG
static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaMethod &signal,
const QMetaObject *receiver, const QMetaMethod &method)
{
@@ -2360,6 +2361,7 @@ static inline void check_and_warn_compat(const QMetaObject *sender, const QMetaM
receiver->className(), method.methodSignature().constData());
}
}
+#endif
/*!
\threadsafe
@@ -4270,7 +4272,7 @@ void qDeleteInEventHandler(QObject *o)
must not have an overloaded or templated operator().
*/
-/**
+/*!
\internal
Implementation of the template version of connect
@@ -4295,12 +4297,13 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
const int *types, const QMetaObject *senderMetaObject)
{
- if (!sender || !signal || !slotObj || !senderMetaObject) {
+ if (!signal) {
qWarning("QObject::connect: invalid null parameter");
if (slotObj)
slotObj->destroyIfLastRef();
return QMetaObject::Connection();
}
+
int signal_index = -1;
void *args[] = { &signal_index, signal };
for (; senderMetaObject && signal_index < 0; senderMetaObject = senderMetaObject->superClass()) {
@@ -4314,6 +4317,27 @@ QMetaObject::Connection QObject::connectImpl(const QObject *sender, void **signa
return QMetaObject::Connection(0);
}
signal_index += QMetaObjectPrivate::signalOffset(senderMetaObject);
+ return QObjectPrivate::connectImpl(sender, signal_index, receiver, slot, slotObj, type, types, senderMetaObject);
+}
+
+/*!
+ \internal
+
+ Internal version of connect used by the template version of QObject::connect (called via connectImpl) and
+ also used by the QObjectPrivate::connect version used by QML. The signal_index is expected to be relative
+ to the number of signals.
+ */
+QMetaObject::Connection QObjectPrivate::connectImpl(const QObject *sender, int signal_index,
+ const QObject *receiver, void **slot,
+ QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
+ const int *types, const QMetaObject *senderMetaObject)
+{
+ if (!sender || !slotObj || !senderMetaObject) {
+ qWarning("QObject::connect: invalid null parameter");
+ if (slotObj)
+ slotObj->destroyIfLastRef();
+ return QMetaObject::Connection();
+ }
QObject *s = const_cast<QObject *>(sender);
QObject *r = const_cast<QObject *>(receiver);
@@ -4487,6 +4511,40 @@ bool QObject::disconnectImpl(const QObject *sender, void **signal, const QObject
return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, receiver, -1, slot);
}
+/*!
+ \internal
+ Used by QML to connect a signal by index to a slot implemented in JavaScript (wrapped in a custom QSlotOBjectBase subclass).
+
+ The signal_index is an index relative to the number of methods.
+ */
+QMetaObject::Connection QObjectPrivate::connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type)
+{
+ if (!sender) {
+ qWarning("QObject::connect: invalid null parameter");
+ if (slotObj)
+ slotObj->destroyIfLastRef();
+ return QMetaObject::Connection();
+ }
+ const QMetaObject *senderMetaObject = sender->metaObject();
+ signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
+
+ return QObjectPrivate::connectImpl(sender, signal_index, sender, /*slot*/0, slotObj, type, /*types*/0, senderMetaObject);
+}
+
+/*!
+ \internal
+ Used by QML to disconnect a signal by index that's connected to a slot implemented in JavaScript (wrapped in a custom QSlotObjectBase subclass)
+ In the QML case the slot is not a pointer to a pointer to the function to disconnect, but instead it is a pointer to an array of internal values
+ required for the disconnect.
+ */
+bool QObjectPrivate::disconnect(const QObject *sender, int signal_index, void **slot)
+{
+ const QMetaObject *senderMetaObject = sender->metaObject();
+ signal_index = methodIndexToSignalIndex(&senderMetaObject, signal_index);
+
+ return QMetaObjectPrivate::disconnect(sender, signal_index, senderMetaObject, sender, -1, slot);
+}
+
/*! \class QMetaObject::Connection
\inmodule QtCore
Represents a handle to a signal-slot connection.
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index e849ec1599..3c43972ac9 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -207,6 +207,13 @@ public:
template <typename Func1, typename Func2>
static inline bool disconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal,
const typename QtPrivate::FunctionPointer<Func2>::Object *receiverPrivate, Func2 slot);
+
+ static QMetaObject::Connection connectImpl(const QObject *sender, int signal_index,
+ const QObject *receiver, void **slot,
+ QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type,
+ const int *types, const QMetaObject *senderMetaObject);
+ static QMetaObject::Connection connect(const QObject *sender, int signal_index, QtPrivate::QSlotObjectBase *slotObj, Qt::ConnectionType type);
+ static bool disconnect(const QObject *sender, int signal_index, void **slot);
public:
ExtraData *extraData; // extra data set by the user
QThreadData *threadData; // id of the thread that owns the object
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index afbe1a5ece..c489344b10 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -456,6 +456,7 @@ class Q_CORE_EXPORT QMetaObject::Connection {
void *d_ptr; //QObjectPrivate::Connection*
explicit Connection(void *data) : d_ptr(data) { }
friend class QObject;
+ friend class QObjectPrivate;
friend struct QMetaObject;
public:
~Connection();
diff --git a/src/corelib/kernel/qsocketnotifier.cpp b/src/corelib/kernel/qsocketnotifier.cpp
index e0c7f171c3..6c88ed4531 100644
--- a/src/corelib/kernel/qsocketnotifier.cpp
+++ b/src/corelib/kernel/qsocketnotifier.cpp
@@ -181,17 +181,16 @@ QSocketNotifier::QSocketNotifier(qintptr socket, Type type, QObject *parent)
: QObject(*new QSocketNotifierPrivate, parent)
{
Q_D(QSocketNotifier);
- if (socket < 0)
- qWarning("QSocketNotifier: Invalid socket specified");
d->sockfd = socket;
d->sntype = type;
d->snenabled = true;
- if (!d->threadData->eventDispatcher.load()) {
+ if (socket < 0)
+ qWarning("QSocketNotifier: Invalid socket specified");
+ else if (!d->threadData->eventDispatcher.load())
qWarning("QSocketNotifier: Can only be used with threads started with QThread");
- } else {
+ else
d->threadData->eventDispatcher.load()->registerSocketNotifier(this);
- }
}
/*!
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp
index 276257ddcf..c3ccc74a20 100644
--- a/src/corelib/kernel/qvariant.cpp
+++ b/src/corelib/kernel/qvariant.cpp
@@ -269,6 +269,16 @@ inline bool qt_convertToBool(const QVariant::Private *const d)
/*!
\internal
+ Returns the internal data pointer from \a d.
+ */
+
+static const void *constData(const QVariant::Private &d)
+{
+ return d.is_shared ? d.data.shared->ptr : reinterpret_cast<const void *>(&d.data.c);
+}
+
+/*!
+ \internal
Converts \a d to type \a t, which is placed in \a result.
*/
@@ -277,6 +287,14 @@ static bool convert(const QVariant::Private *d, int t, void *result, bool *ok)
Q_ASSERT(d->type != uint(t));
Q_ASSERT(result);
+ if (d->type >= QMetaType::User || t >= QMetaType::User) {
+ const bool isOk = QMetaType::convert(constData(*d), d->type, result, t);
+ if (ok)
+ *ok = isOk;
+ if (isOk)
+ return true;
+ }
+
bool dummy;
if (!ok)
ok = &dummy;
@@ -867,8 +885,15 @@ static bool customCompare(const QVariant::Private *a, const QVariant::Private *b
return !memcmp(a_ptr, b_ptr, QMetaType::sizeOf(a->type));
}
-static bool customConvert(const QVariant::Private *, int, void *, bool *ok)
+static bool customConvert(const QVariant::Private *d, int t, void *result, bool *ok)
{
+ if (d->type >= QMetaType::User || t >= QMetaType::User) {
+ const bool isOk = QMetaType::convert(constData(*d), d->type, result, t);
+ if (ok)
+ *ok = isOk;
+ return isOk;
+ }
+
if (ok)
*ok = false;
return false;
@@ -1958,6 +1983,12 @@ inline T qVariantToHelper(const QVariant::Private &d, const HandlersManager &han
return *v_cast<T>(&d);
T ret;
+ if (d.type >= QMetaType::User || targetType >= QMetaType::User) {
+ const void * const from = constData(d);
+ if (QMetaType::convert(from, d.type, &ret, targetType))
+ return ret;
+ }
+
handlerManager[d.type]->convert(&d, targetType, &ret, 0);
return ret;
}
@@ -2374,13 +2405,19 @@ template <typename T>
inline T qNumVariantToHelper(const QVariant::Private &d,
const HandlersManager &handlerManager, bool *ok, const T& val)
{
- uint t = qMetaTypeId<T>();
+ const uint t = qMetaTypeId<T>();
if (ok)
*ok = true;
+
if (d.type == t)
return val;
T ret = 0;
+ if ((d.type >= QMetaType::User || t >= QMetaType::User)
+ && QMetaType::convert(&val, d.type, &ret, t)) {
+ return ret;
+ }
+
if (!handlerManager[d.type]->convert(&d, t, &ret, ok) && ok)
*ok = false;
return ret;
@@ -2735,10 +2772,52 @@ static bool canConvertMetaObject(int fromId, int toId, QObject *fromObject)
function if a qobject_cast to the type described by \a targetTypeId would succeed. Note that
this only works for QObject subclasses which use the Q_OBJECT macro.
- \sa convert()
+ A QVariant containing a sequential container will also return true for this
+ function if the \a targetTypeId is QVariantList. It is possible to iterate over
+ the contents of the container without extracting it as a (copied) QVariantList:
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 9
+
+ This requires that the value_type of the container is itself a metatype.
+
+ 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
{
+ if (targetTypeId == QMetaType::QVariantList
+ && (d.type == QMetaType::QVariantList
+ || d.type == QMetaType::QStringList
+ || QMetaType::hasRegisteredConverterFunction(d.type,
+ qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>()))) {
+ 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 (targetTypeId == qMetaTypeId<QPair<QVariant, QVariant> >() &&
+ QMetaType::hasRegisteredConverterFunction(d.type,
+ qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) {
+ return true;
+ }
+
+ if ((d.type >= QMetaType::User || targetTypeId >= QMetaType::User)
+ && QMetaType::hasRegisteredConverterFunction(d.type, targetTypeId)) {
+ return true;
+ }
+
// TODO Reimplement this function, currently it works but it is a historical mess.
uint currentType = ((d.type == QMetaType::Float) ? QVariant::Double : d.type);
if (currentType == QMetaType::SChar || currentType == QMetaType::Char)
@@ -2867,7 +2946,7 @@ bool QVariant::convert(int targetTypeId)
if (oldValue.isNull())
return false;
- if ((QMetaType::typeFlags(d.type) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) {
+ if ((QMetaType::typeFlags(oldValue.userType()) & QMetaType::PointerToQObject) && (QMetaType::typeFlags(targetTypeId) & QMetaType::PointerToQObject)) {
create(targetTypeId, &oldValue.d.data.o);
return true;
}
@@ -2886,7 +2965,6 @@ bool QVariant::convert(int targetTypeId)
*/
bool QVariant::convert(const int type, void *ptr) const
{
- Q_ASSERT(type < int(QMetaType::User));
return handlerManager[type]->convert(&d, type, ptr, 0);
}
@@ -2908,8 +2986,9 @@ bool QVariant::convert(const int type, void *ptr) const
which means that two values can be equal even if one of them is null and
another is not.
- \warning This function doesn't support custom types registered
- with qRegisterMetaType().
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
*/
/*!
\fn bool operator!=(const QVariant &v1, const QVariant &v2)
@@ -2918,8 +2997,9 @@ bool QVariant::convert(const int type, void *ptr) const
Returns false if \a v1 and \a v2 are equal; otherwise returns true.
- \warning This function doesn't support custom types registered
- with qRegisterMetaType().
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
*/
/*! \fn bool QVariant::operator==(const QVariant &v) const
@@ -2932,8 +3012,9 @@ bool QVariant::convert(const int type, void *ptr) const
type is not the same as this variant's type. See canConvert() for
a list of possible conversions.
- \warning This function doesn't support custom types registered
- with qRegisterMetaType().
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
*/
/*!
@@ -2942,8 +3023,61 @@ bool QVariant::convert(const int type, void *ptr) const
Compares this QVariant with \a v and returns true if they are not
equal; otherwise returns false.
- \warning This function doesn't support custom types registered
- with qRegisterMetaType().
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
+*/
+
+/*!
+ \fn bool QVariant::operator<(const QVariant &v) const
+
+ Compares this QVariant with \a v and returns true if this is less than \a v.
+
+ \note Comparability might not be availabe for the type stored in this QVariant
+ or in \a v.
+
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
+*/
+
+/*!
+ \fn bool QVariant::operator<=(const QVariant &v) const
+
+ Compares this QVariant with \a v and returns true if this is less or equal than \a v.
+
+ \note Comparability might not be available for the type stored in this QVariant
+ or in \a v.
+
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
+*/
+
+/*!
+ \fn bool QVariant::operator>(const QVariant &v) const
+
+ Compares this QVariant with \a v and returns true if this is larger than \a v.
+
+ \note Comparability might not be available for the type stored in this QVariant
+ or in \a v.
+
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
+*/
+
+/*!
+ \fn bool QVariant::operator>=(const QVariant &v) const
+
+ Compares this QVariant with \a v and returns true if this is larger or equal than \a v.
+
+ \note Comparability might not be available for the type stored in this QVariant
+ or in \a v.
+
+ \warning To make this function work with a custom type registered with
+ qRegisterMetaType(), its comparison operator must be registered using
+ QMetaType::registerComparators().
*/
static bool qIsNumericType(uint tp)
@@ -2962,6 +3096,7 @@ static bool qIsFloatingPoint(uint tp)
*/
bool QVariant::cmp(const QVariant &v) const
{
+ QVariant v1 = *this;
QVariant v2 = v;
if (d.type != v2.d.type) {
if (qIsNumericType(d.type) && qIsNumericType(v.d.type)) {
@@ -2970,10 +3105,63 @@ bool QVariant::cmp(const QVariant &v) const
else
return toLongLong() == v.toLongLong();
}
- if (!v2.canConvert(d.type) || !v2.convert(d.type))
+ if (!v2.canConvert(v1.d.type) || !v2.convert(v1.d.type))
return false;
}
- return handlerManager[d.type]->compare(&d, &v2.d);
+ if (v1.d.type >= QMetaType::User) {
+ int result;
+ if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(v1.d)), QT_PREPEND_NAMESPACE(constData(v2.d)), v1.d.type, &result))
+ return result == 0;
+ }
+ return handlerManager[v1.d.type]->compare(&v1.d, &v2.d);
+}
+
+/*!
+ \internal
+ */
+int QVariant::compare(const QVariant &v) const
+{
+ if (cmp(v))
+ return 0;
+ QVariant v1 = *this;
+ QVariant v2 = v;
+ if (v1.d.type != v2.d.type) {
+ // if both types differ, try to convert
+ if (v2.canConvert(v1.d.type)) {
+ QVariant temp = v2;
+ if (temp.convert(v1.d.type))
+ v2 = temp;
+ }
+ if (v1.d.type != v2.d.type && v1.canConvert(v2.d.type)) {
+ QVariant temp = v1;
+ if (temp.convert(v2.d.type))
+ v1 = temp;
+ }
+ if (v1.d.type != v2.d.type) {
+ // if conversion fails, default to toString
+ return v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
+ }
+ }
+ if (v1.d.type >= QMetaType::User) {
+ int result;
+ if (QMetaType::compare(QT_PREPEND_NAMESPACE(constData(d)), QT_PREPEND_NAMESPACE(constData(v2.d)), d.type, &result))
+ return result;
+ }
+ if (qIsNumericType(v1.d.type)) {
+ if (qIsFloatingPoint(v1.d.type))
+ return v1.toReal() < v2.toReal() ? -1 : 1;
+ else
+ return v1.toLongLong() < v2.toLongLong() ? -1 : 1;
+ }
+ switch (v1.d.type) {
+ case QVariant::Date:
+ return v1.toDate() < v2.toDate() ? -1 : 1;
+ case QVariant::Time:
+ return v1.toTime() < v2.toTime() ? -1 : 1;
+ case QVariant::DateTime:
+ return v1.toDateTime() < v2.toDateTime() ? -1 : 1;
+ }
+ return v1.toString().compare(v2.toString(), Qt::CaseInsensitive);
}
/*!
@@ -3022,7 +3210,16 @@ QDebug operator<<(QDebug dbg, const QVariant &v)
dbg.nospace() << "QVariant(";
if (typeId != QMetaType::UnknownType) {
dbg.nospace() << QMetaType::typeName(typeId) << ", ";
- handlerManager[typeId]->debugStream(dbg, v);
+ bool userStream = false;
+ bool canConvertToString = false;
+ if (typeId >= QMetaType::User) {
+ userStream = QMetaType::debugStream(dbg, constData(v.d), typeId);
+ canConvertToString = v.canConvert<QString>();
+ }
+ if (!userStream && canConvertToString)
+ dbg << v.toString();
+ else if (!userStream)
+ handlerManager[typeId]->debugStream(dbg, v);
} else {
dbg.nospace() << "Invalid";
}
@@ -3074,7 +3271,12 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
returned. Note that this only works for QObject subclasses which use the
Q_OBJECT macro.
- \sa setValue(), fromValue(), canConvert()
+ If the QVariant contains a sequential container and \c{T} is QVariantList, the
+ elements of the container will be converted into QVariants and returned as a QVariantList.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 9
+
+ \sa setValue(), fromValue(), canConvert(), qRegisterSequentialConverter()
*/
/*! \fn bool QVariant::canConvert() const
@@ -3226,4 +3428,359 @@ QDebug operator<<(QDebug dbg, const QVariant::Type p)
\internal
*/
+/*!
+ \class QSequentialIterable
+
+ \inmodule QtCore
+ \brief The QSequentialIterable class is an iterable interface for a container in a QVariant.
+
+ This class allows several methods of accessing the elements of a container held within
+ a QVariant. An instance of QSequentialIterable can be extracted from a QVariant if it can
+ be converted to a QVariantList.
+
+ \snippet code/src_corelib_kernel_qvariant.cpp 9
+
+ The container itself is not copied before iterating over it.
+
+ \sa QVariant
+*/
+
+/*! \fn QSequentialIterable::QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl)
+
+ \internal
+*/
+
+/*! \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()
+*/
+
+/*! \fn QSequentialIterable::const_iterator QSequentialIterable::end() const
+
+ Returns a QSequentialIterable::const_iterator for the end of the container. This
+ can be used in stl-style iteration.
+
+ \sa begin()
+*/
+
+/*! \fn QVariant QSequentialIterable::at(int idx) const
+
+ Returns the element at position \a idx in the container.
+*/
+
+/*! \fn int QSequentialIterable::size() const
+
+ Returns the number of elements in the container.
+*/
+
+/*! \fn bool QSequentialIterable::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.
+*/
+
+/*!
+ \class QSequentialIterable::const_iterator
+
+ \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
+*/
+
+
+/*! \fn QSequentialIterable::const_iterator::~const_iterator()
+
+ Destroys the QSequentialIterable::const_iterator.
+*/
+
+/*! \fn QSequentialIterable::const_iterator::const_iterator(const const_iterator &other)
+
+ Creates a copy of \a other.
+*/
+
+/*! \fn QVariant QSequentialIterable::const_iterator::operator*() const
+
+ Returns the current item, converted to a QVariant.
+*/
+
+/*! \fn bool QSequentialIterable::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 QSequentialIterable::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 QSequentialIterable::const_iterator &QSequentialIterable::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 QSequentialIterable::end() leads to undefined results.
+
+ \sa operator--()
+*/
+
+/*! \fn QSequentialIterable::const_iterator QSequentialIterable::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 QSequentialIterable::const_iterator &QSequentialIterable::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 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 QSequentialIterable::const_iterator QSequentialIterable::const_iterator::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 QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator+=(int j)
+
+ Advances the iterator by \a j items.
+
+ \sa operator-=(), operator+()
+*/
+
+/*! \fn QSequentialIterable::const_iterator &QSequentialIterable::const_iterator::operator-=(int 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 QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator+(int j) const
+
+ Returns an iterator to the item at \a j positions forward from
+ this iterator.
+
+ \sa operator-(), operator+=()
+*/
+
+/*! \fn QSequentialIterable::const_iterator QSequentialIterable::const_iterator::operator-(int 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()
+*/
+
+/*!
+ \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 6f212f5000..3345131c0f 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -49,6 +49,7 @@
#include <QtCore/qmap.h>
#include <QtCore/qhash.h>
#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
#include <QtCore/qobject.h>
QT_BEGIN_NAMESPACE
@@ -432,6 +433,14 @@ class Q_CORE_EXPORT QVariant
{ return cmp(v); }
inline bool operator!=(const QVariant &v) const
{ return !cmp(v); }
+ inline bool operator<(const QVariant &v) const
+ { return compare(v) < 0; }
+ inline bool operator<=(const QVariant &v) const
+ { return compare(v) <= 0; }
+ inline bool operator>(const QVariant &v) const
+ { return compare(v) > 0; }
+ inline bool operator>=(const QVariant &v) const
+ { return compare(v) >= 0; }
protected:
friend inline bool operator==(const QVariant &, const QVariantComparisonHelper &);
@@ -449,6 +458,7 @@ public:
Private d;
void create(int type, const void *copy);
bool cmp(const QVariant &other) const;
+ int compare(const QVariant &other) const;
bool convert(const int t, void *ptr) const;
private:
@@ -562,6 +572,173 @@ inline bool operator!=(const QVariant &v1, const QVariantComparisonHelper &v2)
}
#endif
+class QSequentialIterable
+{
+ QtMetaTypePrivate::QSequentialIterableImpl m_impl;
+public:
+ struct const_iterator
+ {
+ private:
+ QtMetaTypePrivate::QSequentialIterableImpl m_impl;
+ QAtomicInt *ref;
+ friend class QSequentialIterable;
+ inline explicit const_iterator(const QSequentialIterable &iter, QAtomicInt *ref_)
+ : m_impl(iter.m_impl), ref(ref_) { ref->ref(); }
+
+ inline explicit const_iterator(const QtMetaTypePrivate::QSequentialIterableImpl &impl, QAtomicInt *ref_)
+ : m_impl(impl), ref(ref_) { ref->ref(); }
+
+ inline void begin() { m_impl.moveToBegin(); }
+ inline void end() { m_impl.moveToEnd(); }
+ 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 operator*() const {
+ const QtMetaTypePrivate::VariantData d = m_impl.getCurrent();
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return QVariant(d.metaTypeId, d.data, d.flags);
+ }
+ 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::QSequentialIterableImpl 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::QSequentialIterableImpl 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::QSequentialIterableImpl impl = m_impl; impl.advance(j); return const_iterator(impl, this->ref); }
+ inline const_iterator operator-(int j) const { QtMetaTypePrivate::QSequentialIterableImpl impl = m_impl; impl.advance(-j); return const_iterator(impl, this->ref); }
+ };
+
+ friend struct const_iterator;
+
+ explicit QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl 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 at(int idx) const {
+ const QtMetaTypePrivate::VariantData d = m_impl.at(idx);
+ if (d.metaTypeId == qMetaTypeId<QVariant>())
+ return *reinterpret_cast<const QVariant*>(d.data);
+ return QVariant(d.metaTypeId, d.data, d.flags);
+ }
+ int size() const { return m_impl.size(); }
+
+ bool canReverseIterate() const
+ { 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>
struct QVariantValueHelper : TreatAsQObjectBeforeMetaType<QVariantValueHelper<T>, T, const QVariant &, T>
@@ -571,26 +748,132 @@ namespace QtPrivate {
const int vid = qMetaTypeId<T>();
if (vid == v.userType())
return *reinterpret_cast<const T *>(v.constData());
- if (vid < int(QMetaType::User)) {
- T t;
- if (v.convert(vid, &t))
- return t;
- }
+ T t;
+ if (v.convert(vid, &t))
+ return t;
return T();
}
#ifndef QT_NO_QOBJECT
static T object(const QVariant &v)
{
- return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject ? v.d.data.o : 0);
+ return qobject_cast<T>(QMetaType::typeFlags(v.userType()) & QMetaType::PointerToQObject
+ ? v.d.data.o
+ : QVariantValueHelper::metaType(v));
}
#endif
};
+
+ template<typename T>
+ struct QVariantValueHelperInterface : QVariantValueHelper<T>
+ {
+ };
+
+ template<>
+ struct QVariantValueHelperInterface<QSequentialIterable>
+ {
+ static QSequentialIterable invoke(const QVariant &v)
+ {
+ if (v.userType() == qMetaTypeId<QVariantList>()) {
+ return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QVariantList*>(v.constData())));
+ }
+ if (v.userType() == qMetaTypeId<QStringList>()) {
+ return QSequentialIterable(QtMetaTypePrivate::QSequentialIterableImpl(reinterpret_cast<const QStringList*>(v.constData())));
+ }
+ return QSequentialIterable(v.value<QtMetaTypePrivate::QSequentialIterableImpl>());
+ }
+ };
+ 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)
+ {
+ if (v.userType() == qMetaTypeId<QStringList>() || QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QSequentialIterableImpl>())) {
+ QSequentialIterable iter = QVariantValueHelperInterface<QSequentialIterable>::invoke(v);
+ QVariantList l;
+ l.reserve(iter.size());
+ for (QSequentialIterable::const_iterator it = iter.begin(), end = iter.end(); it != end; ++it)
+ l << *it;
+ return l;
+ }
+ 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<>
+ struct QVariantValueHelperInterface<QPair<QVariant, QVariant> >
+ {
+ static QPair<QVariant, QVariant> invoke(const QVariant &v)
+ {
+ if (v.userType() == qMetaTypeId<QPair<QVariant, QVariant> >())
+ return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v);
+
+ if (QMetaType::hasRegisteredConverterFunction(v.userType(), qMetaTypeId<QtMetaTypePrivate::QPairVariantInterfaceImpl>())) {
+ QtMetaTypePrivate::QPairVariantInterfaceImpl pi = v.value<QtMetaTypePrivate::QPairVariantInterfaceImpl>();
+
+ const QtMetaTypePrivate::VariantData d1 = pi.first();
+ QVariant v1(d1.metaTypeId, d1.data, d1.flags);
+ if (d1.metaTypeId == qMetaTypeId<QVariant>())
+ v1 = *reinterpret_cast<const QVariant*>(d1.data);
+
+ const QtMetaTypePrivate::VariantData d2 = pi.second();
+ QVariant v2(d2.metaTypeId, d2.data, d2.flags);
+ if (d2.metaTypeId == qMetaTypeId<QVariant>())
+ v2 = *reinterpret_cast<const QVariant*>(d2.data);
+
+ return QPair<QVariant, QVariant>(v1, v2);
+ }
+ return QVariantValueHelper<QPair<QVariant, QVariant> >::invoke(v);
+ }
+ };
}
-#ifndef QT_MOC
template<typename T> inline T qvariant_cast(const QVariant &v)
{
- return QtPrivate::QVariantValueHelper<T>::invoke(v);
+ return QtPrivate::QVariantValueHelperInterface<T>::invoke(v);
}
template<> inline QVariant qvariant_cast<QVariant>(const QVariant &v)