diff options
Diffstat (limited to 'src/corelib/kernel')
-rw-r--r-- | src/corelib/kernel/qcore_mac_p.h | 6 | ||||
-rw-r--r-- | src/corelib/kernel/qcoreapplication.cpp | 61 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_blackberry.cpp | 82 | ||||
-rw-r--r-- | src/corelib/kernel/qmetaobjectbuilder.cpp | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.cpp | 285 | ||||
-rw-r--r-- | src/corelib/kernel/qmetatype.h | 1134 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 62 | ||||
-rw-r--r-- | src/corelib/kernel/qobject_p.h | 7 | ||||
-rw-r--r-- | src/corelib/kernel/qobjectdefs.h | 1 | ||||
-rw-r--r-- | src/corelib/kernel/qsocketnotifier.cpp | 9 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 591 | ||||
-rw-r--r-- | src/corelib/kernel/qvariant.h | 299 |
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) |