diff options
Diffstat (limited to 'src/corelib')
47 files changed, 2793 insertions, 207 deletions
diff --git a/src/corelib/Qt5CoreConfigExtras.cmake.in b/src/corelib/Qt5CoreConfigExtras.cmake.in index e01b448351..36a54787b3 100644 --- a/src/corelib/Qt5CoreConfigExtras.cmake.in +++ b/src/corelib/Qt5CoreConfigExtras.cmake.in @@ -55,11 +55,8 @@ set_property(TARGET Qt5::Core APPEND PROPERTY COMPATIBLE_INTERFACE_STRING QT_MAJOR_VERSION ) -!!IF isEmpty(CMAKE_HOST_DATA_DIR_IS_ABSOLUTE) -set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_HOST_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") -!!ELSE -set(_qt5_corelib_extra_includes \"$${CMAKE_HOST_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") -!!ENDIF +include(\"${CMAKE_CURRENT_LIST_DIR}/Qt5CoreConfigExtrasMkspecDir.cmake\") + foreach(_dir ${_qt5_corelib_extra_includes}) _qt5_Core_check_file_exists(${_dir}) endforeach() diff --git a/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in b/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in new file mode 100644 index 0000000000..c357237d0e --- /dev/null +++ b/src/corelib/Qt5CoreConfigExtrasMkspecDir.cmake.in @@ -0,0 +1,6 @@ + +!!IF isEmpty(CMAKE_HOST_DATA_DIR_IS_ABSOLUTE) +set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_HOST_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") +!!ELSE +set(_qt5_corelib_extra_includes \"$${CMAKE_HOST_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") +!!ENDIF diff --git a/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in b/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in new file mode 100644 index 0000000000..706304cf34 --- /dev/null +++ b/src/corelib/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in @@ -0,0 +1,6 @@ + +!!IF isEmpty(CMAKE_INSTALL_DATA_DIR_IS_ABSOLUTE) +set(_qt5_corelib_extra_includes \"${_qt5Core_install_prefix}/$${CMAKE_INSTALL_DATA_DIR}/mkspecs/$${CMAKE_MKSPEC}\") +!!ELSE +set(_qt5_corelib_extra_includes \"$${CMAKE_INSTALL_DATA_DIR}mkspecs/$${CMAKE_MKSPEC}\") +!!ENDIF diff --git a/src/corelib/corelib.pro b/src/corelib/corelib.pro index 44a3f06f50..766529c587 100644 --- a/src/corelib/corelib.pro +++ b/src/corelib/corelib.pro @@ -77,12 +77,32 @@ cmake_umbrella_config_file.output = $$DESTDIR/cmake/Qt5/Qt5Config.cmake cmake_umbrella_config_version_file.input = $$PWD/../../mkspecs/features/data/cmake/Qt5ConfigVersion.cmake.in cmake_umbrella_config_version_file.output = $$DESTDIR/cmake/Qt5/Qt5ConfigVersion.cmake +load(cmake_functions) + +CMAKE_HOST_DATA_DIR = $$cmakeRelativePath($$[QT_HOST_DATA/src], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_HOST_DATA_DIR, "^\\.\\./.*"):!isEmpty(CMAKE_HOST_DATA_DIR) { + CMAKE_HOST_DATA_DIR = $$[QT_HOST_DATA/src]/ + CMAKE_HOST_DATA_DIR_IS_ABSOLUTE = True +} + +cmake_extras_mkspec_dir.input = $$PWD/Qt5CoreConfigExtrasMkspecDir.cmake.in +cmake_extras_mkspec_dir.output = $$DESTDIR/cmake/Qt5Core/Qt5CoreConfigExtrasMkspecDir.cmake + +CMAKE_INSTALL_DATA_DIR = $$cmakeRelativePath($$[QT_HOST_DATA], $$[QT_INSTALL_PREFIX]) +contains(CMAKE_INSTALL_DATA_DIR, "^\\.\\./.*"):!isEmpty(CMAKE_INSTALL_DATA_DIR) { + CMAKE_INSTALL_DATA_DIR = $$[QT_HOST_DATA]/ + CMAKE_INSTALL_DATA_DIR_IS_ABSOLUTE = True +} + +cmake_extras_mkspec_dir_for_install.input = $$PWD/Qt5CoreConfigExtrasMkspecDirForInstall.cmake.in +cmake_extras_mkspec_dir_for_install.output = $$DESTDIR/cmake/install/Qt5Core/Qt5CoreConfigExtrasMkspecDir.cmake + cmake_qt5_umbrella_module_files.files = $$cmake_umbrella_config_file.output $$cmake_umbrella_config_version_file.output cmake_qt5_umbrella_module_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5 -QMAKE_SUBSTITUTES += ctest_macros_file cmake_umbrella_config_file cmake_umbrella_config_version_file +QMAKE_SUBSTITUTES += ctest_macros_file cmake_umbrella_config_file cmake_umbrella_config_version_file cmake_extras_mkspec_dir cmake_extras_mkspec_dir_for_install -ctest_qt5_module_files.files += $$ctest_macros_file.output +ctest_qt5_module_files.files += $$ctest_macros_file.output $$cmake_extras_mkspec_dir_for_install.output ctest_qt5_module_files.path = $$[QT_INSTALL_LIBS]/cmake/Qt5Core diff --git a/src/corelib/doc/qtcore.qdocconf b/src/corelib/doc/qtcore.qdocconf index 0e275ee8d4..c74a2b4761 100644 --- a/src/corelib/doc/qtcore.qdocconf +++ b/src/corelib/doc/qtcore.qdocconf @@ -39,3 +39,6 @@ exampledirs += \ ../../../examples/tools/ imagedirs += images + +navigation.landingpage = "Qt Core" +navigation.cppclassespage = "Qt Core C++ Classes" diff --git a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp index 25d24185ee..ab909e5065 100644 --- a/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp +++ b/src/corelib/doc/snippets/code/src_corelib_kernel_qvariant.cpp @@ -134,3 +134,61 @@ return QVariant::fromValue(s); QObject *object = getObjectFromSomewhere(); QVariant data = QVariant::fromValue(object); //! [8] + +//! [9] + +QList<int> intList; +intList.push_back(7); +intList.push_back(11); +intList.push_back(42); + +QVariant variant = QVariant::fromValue(intList); +if (variant.canConvert<QVariantList>()) { + QSequentialIterable iterable = variant.value<QSequentialIterable>(); + // Can use foreach: + foreach (const QVariant &v, iterable) { + qDebug() << v; + } + // Can use C++11 range-for: + for (const QVariant &v : iterable) { + qDebug() << v; + } + // Can use iterators: + QSequentialIterable::const_iterator it = iterable.begin(); + const QSequentialIterable::const_iterator end = iterable.end(); + for ( ; it != end; ++it) { + qDebug() << *it; + } +} + +//! [9] + +//! [10] + +QHash<int, QString> mapping; +mapping.insert(7, "Seven"); +mapping.insert(11, "Eleven"); +mapping.insert(42, "Forty-two"); + +QVariant variant = QVariant::fromValue(mapping); +if (variant.canConvert<QVariantHash>()) { + QAssociativeIterable iterable = variant.value<QAssociativeIterable>(); + // Can use foreach over the values: + foreach (const QVariant &v, iterable) { + qDebug() << v; + } + // Can use C++11 range-for over the values: + for (const QVariant &v : iterable) { + qDebug() << v; + } + // Can use iterators: + QAssociativeIterable::const_iterator it = iterable.begin(); + const QAssociativeIterable::const_iterator end = iterable.end(); + for ( ; it != end; ++it) { + qDebug() << *it; // The current value + qDebug() << it.key(); + qDebug() << it.value(); + } +} + +//! [10] diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h index b685c1fe0d..27fc2d4038 100644 --- a/src/corelib/global/qcompilerdetection.h +++ b/src/corelib/global/qcompilerdetection.h @@ -881,4 +881,26 @@ Q_UNUSED(valueOfExpression); /* the value may not be used if Q_ASSERT_X and Q_ASSUME_IMPL are noop */\ } while (0) + +/* + Sanitize compiler feature availability +*/ +#if !defined(Q_PROCESSOR_X86) +# undef QT_COMPILER_SUPPORTS_SSE2 +# undef QT_COMPILER_SUPPORTS_SSE3 +# undef QT_COMPILER_SUPPORTS_SSSE3 +# undef QT_COMPILER_SUPPORTS_SSE4_1 +# undef QT_COMPILER_SUPPORTS_SSE4_2 +# undef QT_COMPILER_SUPPORTS_AVX +# undef QT_COMPILER_SUPPORTS_AVX2 +#endif +#if !defined(Q_PROCESSOR_ARM) +# undef QT_COMPILER_SUPPORTS_IWMMXT +# undef QT_COMPILER_SUPPORTS_NEON +#endif +#if !defined(Q_PROCESSOR_MIPS) +# undef QT_COMPILER_SUPPORTS_MIPS_DSP +# undef QT_COMPILER_SUPPORTS_MIPS_DSPR2 +#endif + #endif // QCOMPILERDETECTION_H diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index bcd0d06777..ac347655bc 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -934,7 +934,7 @@ bool qSharedBuild() Q_DECL_NOTHROW \endlist Some constants are defined only on certain platforms. You can use - the preprocessor symbols Q_OS_WIN and Q_OS_MACX to test that + the preprocessor symbols Q_OS_WIN and Q_OS_OSX to test that the application is compiled under Windows or OS X. \sa QLibraryInfo @@ -1077,18 +1077,20 @@ bool qSharedBuild() Q_DECL_NOTHROW \macro Q_OS_DARWIN \relates <QtGlobal> - Defined on Darwin OS (synonym for Q_OS_MAC). + Defined on Darwin-based operating systems such as OS X and iOS, + including any open source version(s) of Darwin. */ /*! \macro Q_OS_MAC \relates <QtGlobal> - Defined on OS X and iOS (synonym for Q_OS_DARWIN). + Defined on Darwin-based operating systems distributed by Apple, which + currently includes OS X and iOS, but not the open source version. */ /*! - \macro Q_OS_MACX + \macro Q_OS_OSX \relates <QtGlobal> Defined on OS X. diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 4e63e5d0ba..2132e555cd 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -45,11 +45,11 @@ #include <stddef.h> -#define QT_VERSION_STR "5.1.1" +#define QT_VERSION_STR "5.2.0" /* QT_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_VERSION 0x050101 +#define QT_VERSION 0x050200 /* can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) */ @@ -68,8 +68,8 @@ #define QT_STRINGIFY(x) QT_STRINGIFY2(x) #include <QtCore/qsystemdetection.h> -#include <QtCore/qcompilerdetection.h> #include <QtCore/qprocessordetection.h> +#include <QtCore/qcompilerdetection.h> #if defined (__ELF__) # define Q_OF_ELF diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp index 53a3ebbc10..18f293bba5 100644 --- a/src/corelib/global/qlibraryinfo.cpp +++ b/src/corelib/global/qlibraryinfo.cpp @@ -78,6 +78,7 @@ struct QLibrarySettings QLibrarySettings(); QScopedPointer<QSettings> settings; #ifdef QT_BOOTSTRAPPED + bool haveEffectiveSourcePaths; bool haveEffectivePaths; bool havePaths; #endif @@ -99,8 +100,10 @@ public: static bool haveGroup(QLibraryInfo::PathGroup group) { QLibrarySettings *ls = qt_library_settings(); - return ls ? (group == QLibraryInfo::EffectivePaths - ? ls->haveEffectivePaths : ls->havePaths) : false; + return ls ? (group == QLibraryInfo::EffectiveSourcePaths + ? ls->haveEffectiveSourcePaths + : group == QLibraryInfo::EffectivePaths + ? ls->haveEffectivePaths : ls->havePaths) : false; } #endif static QSettings *configuration() @@ -122,7 +125,12 @@ QLibrarySettings::QLibrarySettings() // This code needs to be in the regular library, as otherwise a qt.conf that // works for qmake would break things for dynamically built Qt tools. QStringList children = settings->childGroups(); +#ifdef QT_BOOTSTRAPPED + haveEffectiveSourcePaths = children.contains(QLatin1String("EffectiveSourcePaths")); + haveEffectivePaths = haveEffectiveSourcePaths || children.contains(QLatin1String("EffectivePaths")); +#else haveEffectivePaths = children.contains(QLatin1String("EffectivePaths")); +#endif // Backwards compat: an existing but empty file is claimed to contain the Paths section. havePaths = !haveEffectivePaths || children.contains(QLatin1String("Paths")); #ifndef QT_BOOTSTRAPPED @@ -130,6 +138,9 @@ QLibrarySettings::QLibrarySettings() settings.reset(0); #else } else { +#ifdef QT_BOOTSTRAPPED + haveEffectiveSourcePaths = false; +#endif haveEffectivePaths = false; havePaths = false; #endif @@ -334,9 +345,12 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) // and qt.conf with that section is present, use it, otherwise fall back to // FinalPaths. For FinalPaths, use qt.conf if present and contains not only // [EffectivePaths], otherwise fall back to builtins. + // EffectiveSourcePaths falls back to EffectivePaths. if (!QLibraryInfoPrivate::haveGroup(group) - && (group == FinalPaths - || !(group = FinalPaths, QLibraryInfoPrivate::haveGroup(FinalPaths)))) + && !(group == EffectiveSourcePaths + && (group = EffectivePaths, QLibraryInfoPrivate::haveGroup(group))) + && !(group == EffectivePaths + && (group = FinalPaths, QLibraryInfoPrivate::haveGroup(group)))) #elif !defined(QT_NO_SETTINGS) if (!QLibraryInfoPrivate::configuration()) #endif @@ -368,6 +382,7 @@ QLibraryInfo::rawLocation(LibraryLocation loc, PathGroup group) QSettings *config = QLibraryInfoPrivate::configuration(); config->beginGroup(QLatin1String( #ifdef QT_BOOTSTRAPPED + group == EffectiveSourcePaths ? "EffectiveSourcePaths" : group == EffectivePaths ? "EffectivePaths" : #endif "Paths")); diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h index b275e018a0..17864b555b 100644 --- a/src/corelib/global/qlibraryinfo.h +++ b/src/corelib/global/qlibraryinfo.h @@ -92,7 +92,7 @@ public: }; static QString location(LibraryLocation); // ### Qt 6: consider renaming it to path() #ifdef QT_BOOTSTRAPPED - enum PathGroup { FinalPaths, EffectivePaths }; + enum PathGroup { FinalPaths, EffectivePaths, EffectiveSourcePaths }; static QString rawLocation(LibraryLocation, PathGroup); #endif diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 25c47d5d34..6f1a089670 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -982,6 +982,14 @@ public: Key_MicMute = 0x01000113, + Key_Red = 0x01000114, + Key_Green = 0x01000115, + Key_Yellow = 0x01000116, + Key_Blue = 0x01000117, + + Key_ChannelUp = 0x01000118, + Key_ChannelDown = 0x01000119, + Key_MediaLast = 0x0100ffff, // Keypad navigation keys diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index f9248eb68d..5cd1812b54 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -1622,6 +1622,12 @@ \value Key_TouchpadOn \value Key_TouchpadOff \value Key_MicMute + \value Key_Red + \value Key_Green + \value Key_Yellow + \value Key_Blue + \value Key_ChannelUp + \value Key_ChannelDown \value Key_MediaLast \value Key_unknown diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h index cb55fa808b..5e68226b60 100644 --- a/src/corelib/global/qsystemdetection.h +++ b/src/corelib/global/qsystemdetection.h @@ -49,9 +49,9 @@ /* The operating system, must be one of: (Q_OS_x) - DARWIN - Darwin OS (synonym for Q_OS_MAC) - MAC - OS X or iOS (synonym for Q_OS_DARWIN) - MACX - OS X + DARWIN - Any Darwin system + MAC - OS X and iOS + OSX - OS X IOS - iOS MSDOS - MS-DOS and Windows OS2 - OS/2 @@ -175,8 +175,9 @@ # include <TargetConditionals.h> # if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE # define Q_OS_IOS -# else -# define Q_OS_MACX +# elif defined(TARGET_OS_MAC) && TARGET_OS_MAC +# define Q_OS_OSX +# define Q_OS_MACX // compatibility synonym # endif #endif diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index b6926bc544..52b80badb8 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -251,7 +251,7 @@ QT_BEGIN_NAMESPACE return retVal; enum { - DefaultStreamVersion = QDataStream::Qt_5_1 + DefaultStreamVersion = QDataStream::Qt_5_2 }; /*! @@ -539,7 +539,8 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_4_8 Same as Qt_4_6. \value Qt_4_9 Same as Qt_4_6. \value Qt_5_0 Version 13 (Qt 5.0) - \value Qt_5_1 Version 14 (Qt 5.1) + \value Qt_5_1 Version 14 (Qt 5.1, Qt 5.2) + \value Qt_5_2 Same as Qt_5_1. \sa setVersion(), version() */ diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 969cdf4517..eb064b3fe2 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -86,8 +86,9 @@ public: Qt_4_8 = Qt_4_7, Qt_4_9 = Qt_4_8, Qt_5_0 = 13, - Qt_5_1 = 14 -#if QT_VERSION >= 0x050200 + Qt_5_1 = 14, + Qt_5_2 = Qt_5_1 +#if QT_VERSION >= 0x050300 #error Add the datastream version for this Qt version #endif }; diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index f2e1f9bbc7..16263ad736 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -225,6 +225,9 @@ \value RemoveQuery The query part of the URL (following a '?' character) is removed. \value RemoveFragment + \value RemoveFilename The filename (i.e. everything after the last '/' in the path) is removed. + The trailing '/' is kept, unless StripTrailingSlash is set. + Only valid if RemovePath is not set. \value PreferLocalFile If the URL is a local file according to isLocalFile() and contains no query or fragment, a local file path is returned. \value StripTrailingSlash The trailing slash is removed if one is present. @@ -799,12 +802,23 @@ inline void QUrlPrivate::appendPassword(QString &appendTo, QUrl::FormattingOptio inline void QUrlPrivate::appendPath(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const { + QString thePath = path; + if (options & QUrl::RemoveFilename) { + const int slash = path.lastIndexOf(QLatin1Char('/')); + if (slash == -1) + return; + thePath = path.left(slash+1); + } + // check if we need to remove trailing slashes + if ((options & QUrl::StripTrailingSlash) && !thePath.isEmpty() && thePath != QLatin1String("/") && thePath.endsWith(QLatin1Char('/'))) + thePath.chop(1); + if (appendingTo != Path && !(options & QUrl::EncodeDelimiters)) { - if (!qt_urlRecode(appendTo, path.constData(), path.constEnd(), options, decodedPathInUrlActions)) - appendTo += path; + if (!qt_urlRecode(appendTo, thePath.constData(), thePath.constEnd(), options, decodedPathInUrlActions)) + appendTo += thePath; } else { - appendToUser(appendTo, path, options, encodedPathActions, decodedPathInIsolationActions); + appendToUser(appendTo, thePath, options, encodedPathActions, decodedPathInIsolationActions); } } @@ -1059,7 +1073,7 @@ inline void QUrlPrivate::appendHost(QString &appendTo, QUrl::FormattingOptions o // this is either an IPv4Address or a reg-name // if it is a reg-name, it is already stored in Unicode form if (options == QUrl::EncodeUnicode) - appendTo += qt_ACE_do(host, ToAceOnly); + appendTo += qt_ACE_do(host, ToAceOnly, AllowLeadingDot); else appendTo += host; } @@ -1207,7 +1221,7 @@ inline bool QUrlPrivate::setHost(const QString &value, int from, int iend, QUrl: return setHost(s, 0, s.length(), QUrl::StrictMode); } - s = qt_ACE_do(QString::fromRawData(begin, len), NormalizeAce); + s = qt_ACE_do(QString::fromRawData(begin, len), NormalizeAce, ForbidLeadingDot); if (s.isEmpty()) { setError(InvalidRegNameError, value); return false; @@ -2976,7 +2990,7 @@ QString QUrl::topLevelDomain(ComponentFormattingOptions options) const { QString tld = qTopLevelDomain(host()); if (options & EncodeUnicode) { - return qt_ACE_do(tld, ToAceOnly); + return qt_ACE_do(tld, ToAceOnly, AllowLeadingDot); } return tld; } @@ -3148,12 +3162,8 @@ QString QUrl::toString(FormattingOptions options) const url += QLatin1String("//"); } - if (!(options & QUrl::RemovePath)) { + if (!(options & QUrl::RemovePath)) d->appendPath(url, options, QUrlPrivate::FullUrl); - // check if we need to remove trailing slashes - if ((options & StripTrailingSlash) && !d->path.isEmpty() && d->path != QLatin1String("/") && url.endsWith(QLatin1Char('/'))) - url.chop(1); - } if (!(options & QUrl::RemoveQuery) && d->hasQuery()) { url += QLatin1Char('?'); @@ -3188,6 +3198,52 @@ QString QUrl::toDisplayString(FormattingOptions options) const } /*! + \since 5.2 + + Returns an adjusted version of the URL. + The output can be customized by passing flags with \a options. + + The encoding options from QUrl::ComponentFormattingOption don't make + much sense for this method, nor does QUrl::PreferLocalFile. + + This is always equivalent to QUrl(url.toString(options)). + + \sa FormattingOptions, toEncoded(), toString() +*/ +QUrl QUrl::adjusted(QUrl::FormattingOptions options) const +{ + if (!isValid()) { + // also catches isEmpty() + return QUrl(); + } + QUrl that = *this; + if (options & RemoveScheme) + that.setScheme(QString()); + if ((options & RemoveAuthority) == RemoveAuthority) { + that.setAuthority(QString()); + } else { + if ((options & RemoveUserInfo) == RemoveUserInfo) + that.setUserInfo(QString()); + else if (options & RemovePassword) + that.setPassword(QString()); + if (options & RemovePort) + that.setPort(-1); + } + if (options & RemoveQuery) + that.setQuery(QString()); + if (options & RemoveFragment) + that.setFragment(QString()); + if (options & RemovePath) { + that.setPath(QString()); + } else if (options & (StripTrailingSlash | RemoveFilename)) { + QString path; + d->appendPath(path, options, QUrlPrivate::Path); + that.setPath(path); + } + return that; +} + +/*! Returns the encoded representation of the URL if it's valid; otherwise an empty QByteArray is returned. The output can be customized by passing flags with \a options. @@ -3296,7 +3352,7 @@ QString QUrl::fromEncodedComponent_helper(const QByteArray &ba) */ QString QUrl::fromAce(const QByteArray &domain) { - return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce); + return qt_ACE_do(QString::fromLatin1(domain), NormalizeAce, ForbidLeadingDot /*FIXME: make configurable*/); } /*! @@ -3317,7 +3373,7 @@ QString QUrl::fromAce(const QByteArray &domain) */ QByteArray QUrl::toAce(const QString &domain) { - QString result = qt_ACE_do(domain, ToAceOnly); + QString result = qt_ACE_do(domain, ToAceOnly, ForbidLeadingDot /*FIXME: make configurable*/); return result.toLatin1(); } diff --git a/src/corelib/io/qurl.h b/src/corelib/io/qurl.h index cf208bf71e..453e0be1d2 100644 --- a/src/corelib/io/qurl.h +++ b/src/corelib/io/qurl.h @@ -140,7 +140,8 @@ public: RemoveFragment = 0x80, // 0x100 was a private code in Qt 4, keep unused for a while PreferLocalFile = 0x200, - StripTrailingSlash = 0x400 + StripTrailingSlash = 0x400, + RemoveFilename = 0x800 }; enum ComponentFormattingOption { @@ -185,6 +186,7 @@ public: QString url(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; QString toDisplayString(FormattingOptions options = FormattingOptions(PrettyDecoded)) const; + QUrl adjusted(FormattingOptions options) const; QByteArray toEncoded(FormattingOptions options = FullyEncoded) const; static QUrl fromEncoded(const QByteArray &url, ParsingMode mode = TolerantMode); diff --git a/src/corelib/io/qurl_p.h b/src/corelib/io/qurl_p.h index a0c1882162..9c8fe1cfc6 100644 --- a/src/corelib/io/qurl_p.h +++ b/src/corelib/io/qurl_p.h @@ -63,8 +63,9 @@ extern Q_AUTOTEST_EXPORT int qt_urlRecode(QString &appendTo, const QChar *begin, QUrl::ComponentFormattingOptions encoding, const ushort *tableModifications = 0); // in qurlidna.cpp +enum AceLeadingDot { AllowLeadingDot, ForbidLeadingDot }; enum AceOperation { ToAceOnly, NormalizeAce }; -extern QString qt_ACE_do(const QString &domain, AceOperation op); +extern QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot); extern Q_AUTOTEST_EXPORT void qt_nameprep(QString *source, int from); extern Q_AUTOTEST_EXPORT bool qt_check_std3rules(const QChar *uc, int len); extern Q_AUTOTEST_EXPORT void qt_punycodeEncoder(const QChar *s, int ucLength, QString *output); diff --git a/src/corelib/io/qurlidna.cpp b/src/corelib/io/qurlidna.cpp index 70db9e09eb..e959faccd2 100644 --- a/src/corelib/io/qurlidna.cpp +++ b/src/corelib/io/qurlidna.cpp @@ -2461,7 +2461,7 @@ static int nextDotDelimiter(const QString &domain, int from = 0) return ch - b; } -QString qt_ACE_do(const QString &domain, AceOperation op) +QString qt_ACE_do(const QString &domain, AceOperation op, AceLeadingDot dot) { if (domain.isEmpty()) return domain; @@ -2479,7 +2479,8 @@ QString qt_ACE_do(const QString &domain, AceOperation op) if (labelLength == 0) { if (idx == domain.length()) break; - return QString(); // two delimiters in a row -- empty label not allowed + if (dot == ForbidLeadingDot || idx > 0) + return QString(); // two delimiters in a row -- empty label not allowed } // RFC 3490 says, about the ToASCII operation: diff --git a/src/corelib/itemmodels/qabstractitemmodel.h b/src/corelib/itemmodels/qabstractitemmodel.h index f3bf2c1019..ac98476492 100644 --- a/src/corelib/itemmodels/qabstractitemmodel.h +++ b/src/corelib/itemmodels/qabstractitemmodel.h @@ -113,6 +113,11 @@ public: inline bool operator!=(const QPersistentModelIndex &other) const { return !operator==(other); } QPersistentModelIndex &operator=(const QPersistentModelIndex &other); +#ifdef Q_COMPILER_RVALUE_REFS + inline QPersistentModelIndex(QPersistentModelIndex &&other) : d(other.d) { other.d = 0; } + inline QPersistentModelIndex &operator=(QPersistentModelIndex &&other) + { qSwap(d, other.d); return *this; } +#endif inline void swap(QPersistentModelIndex &other) { qSwap(d, other.d); } bool operator==(const QModelIndex &other) const; bool operator!=(const QModelIndex &other) const; diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index 06885ad972..7d0162938d 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -60,8 +60,10 @@ #include <qatomic.h> #include <qstring.h> #include <qendian.h> +#include <qnumeric.h> #include <limits.h> +#include <limits> QT_BEGIN_NAMESPACE diff --git a/src/corelib/json/qjsonvalue.cpp b/src/corelib/json/qjsonvalue.cpp index a540626579..d0b06c6924 100644 --- a/src/corelib/json/qjsonvalue.cpp +++ b/src/corelib/json/qjsonvalue.cpp @@ -156,6 +156,18 @@ QJsonValue::QJsonValue(int n) } /*! + \overload + Creates a value of type Double, with value \a n. + NOTE: the integer limits for IEEE 754 double precision data is 2^53 (-9007199254740992 to +9007199254740992). + If you pass in values outside this range expect a loss of precision to occur. + */ +QJsonValue::QJsonValue(qint64 n) + : d(0), t(Double) +{ + this->dbl = n; +} + +/*! Creates a value of type String, with value \a s. */ QJsonValue::QJsonValue(const QString &s) diff --git a/src/corelib/json/qjsonvalue.h b/src/corelib/json/qjsonvalue.h index b8bdf55aa3..c8efab5d5f 100644 --- a/src/corelib/json/qjsonvalue.h +++ b/src/corelib/json/qjsonvalue.h @@ -79,6 +79,7 @@ public: QJsonValue(bool b); QJsonValue(double n); QJsonValue(int n); + QJsonValue(qint64 n); QJsonValue(const QString &s); QJsonValue(QLatin1String s); QJsonValue(const QJsonArray &a); diff --git a/src/corelib/json/qjsonwriter.cpp b/src/corelib/json/qjsonwriter.cpp index 3ac16c6fd1..8426b351f6 100644 --- a/src/corelib/json/qjsonwriter.cpp +++ b/src/corelib/json/qjsonwriter.cpp @@ -169,9 +169,14 @@ static void valueToJson(const QJsonPrivate::Base *b, const QJsonPrivate::Value & case QJsonValue::Bool: json += v.toBoolean() ? "true" : "false"; break; - case QJsonValue::Double: - json += QByteArray::number(v.toDouble(b), 'g', 17); + case QJsonValue::Double: { + const double d = v.toDouble(b); + if (qIsFinite(d)) // +2 to format to ensure the expected precision + json += QByteArray::number(d, 'g', std::numeric_limits<double>::digits10 + 2); // ::digits10 is 15 + else + json += "null"; // +INF || -INF || NaN (see RFC4627#section2.4) break; + } case QJsonValue::String: json += '"'; json += escapedString(v.toString(b)); 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 c3a05551b8..386ee9cbda 100644 --- a/src/corelib/kernel/qcoreapplication.cpp +++ b/src/corelib/kernel/qcoreapplication.cpp @@ -1954,7 +1954,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 @@ -1963,11 +1962,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()) { @@ -1986,34 +1985,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 } 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/qmetatype.cpp b/src/corelib/kernel/qmetatype.cpp index 50f3a1814b..586d6cf29f 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,198 @@ 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) +{ + 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 +965,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 +2083,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..005199080d 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,183 @@ 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) + 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 +503,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 +634,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 +677,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,6 +752,484 @@ 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; @@ -509,6 +1318,176 @@ 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> + { + static bool 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; + } + }; + + 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 +1525,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 +1577,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 +1585,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> @@ -846,19 +1838,6 @@ struct QMetaTypeId< SMART_POINTER<T> > : public QMetaTypeId_ ## SMART_POINTER ## { \ }; -#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) \ @@ -872,6 +1851,9 @@ 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) \ template <class T1, class T2> CPPTYPE TEMPLATENAME; \ Q_DECLARE_METATYPE_TEMPLATE_2ARG(TEMPLATENAME) @@ -880,6 +1862,9 @@ 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) @@ -987,5 +1972,50 @@ 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 + +#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 02794e9fe3..997a65169d 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -4255,7 +4255,7 @@ void qDeleteInEventHandler(QObject *o) must not have an overloaded or templated operator(). */ -/** +/*! \internal Implementation of the template version of connect @@ -4280,12 +4280,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()) { @@ -4299,6 +4300,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); @@ -4469,6 +4491,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..24bf25baea 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) @@ -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..d5ea491288 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,11 +748,9 @@ 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 @@ -585,12 +760,118 @@ namespace QtPrivate { } #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) diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index e3b76886f1..8337afcb9d 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -516,6 +516,73 @@ Q_OUTOFLINE_TEMPLATE RandomAccessIterator qBinaryFindHelper(RandomAccessIterator } //namespace QAlgorithmsPrivate + +// Use __builtin_popcount on gcc. Clang claims to be gcc +// but has a bug where __builtin_popcount is not marked as +// constexpr. +#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) +#define QALGORITHMS_USE_BUILTIN_POPCOUNT +#endif + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint32 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint8 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint16 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcount(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(quint64 v) +{ +#ifdef QALGORITHMS_USE_BUILTIN_POPCOUNT + return __builtin_popcountll(v); +#else + return + (((v ) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 12) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 24) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 36) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 48) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f + + (((v >> 60) & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; +#endif +} + +Q_DECL_CONSTEXPR inline uint qPopulationCount(long unsigned int v) +{ + return qPopulationCount(static_cast<quint64>(v)); +} + +#if defined(Q_CC_GNU) && !defined(Q_CC_CLANG) +#undef QALGORITHMS_USE_BUILTIN_POPCOUNT +#endif + + QT_END_NAMESPACE #endif // QALGORITHMS_H diff --git a/src/corelib/tools/qalgorithms.qdoc b/src/corelib/tools/qalgorithms.qdoc index ad6c3d913c..f3dfddec77 100644 --- a/src/corelib/tools/qalgorithms.qdoc +++ b/src/corelib/tools/qalgorithms.qdoc @@ -635,3 +635,34 @@ of \a value in the variable passed as a reference in argument \a n. \sa {qLess()}{qLess<T>()} */ + + +/*! + \fn uint qPopulationCount(quint8 v) + \relates <QtAlgorithms> + \since 5.2 + + Returns the number of bits set in \a v. This number also called + the Hamming Weight of \a v. + */ + +/*! + \fn uint qPopulationCount(quint16 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ + +/*! + \fn uint qPopulationCount(quint32 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ + +/*! + \fn uint qPopulationCount(quint64 v) + \relates <QtAlgorithms> + \since 5.2 + \overload + */ diff --git a/src/corelib/tools/qbitarray.cpp b/src/corelib/tools/qbitarray.cpp index b04c4f9c3d..54c1ff8843 100644 --- a/src/corelib/tools/qbitarray.cpp +++ b/src/corelib/tools/qbitarray.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qbitarray.h" +#include <qalgorithms.h> #include <qdatastream.h> #include <qdebug.h> #include <string.h> @@ -160,24 +161,18 @@ int QBitArray::count(bool on) const for (int i = 0; i < len; ++i) numBits += testBit(i); #else - // See http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetParallel const quint8 *bits = reinterpret_cast<const quint8 *>(d.data()) + 1; while (len >= 32) { quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16) | (quint32(bits[3]) << 24); - quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += ((v >> 24) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; len -= 32; bits += 4; - numBits += int(c); + numBits += int(qPopulationCount(v)); } while (len >= 24) { quint32 v = quint32(bits[0]) | (quint32(bits[1]) << 8) | (quint32(bits[2]) << 16); - quint32 c = ((v & 0xfff) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; - c += (((v & 0xfff000) >> 12) * Q_UINT64_C(0x1001001001001) & Q_UINT64_C(0x84210842108421)) % 0x1f; len -= 24; bits += 3; - numBits += int(c); + numBits += int(qPopulationCount(v)); } while (len >= 0) { if (bits[len / 8] & (1 << ((len - 1) & 7))) diff --git a/src/corelib/tools/qbitarray.h b/src/corelib/tools/qbitarray.h index 1103712627..eaf9b2ff25 100644 --- a/src/corelib/tools/qbitarray.h +++ b/src/corelib/tools/qbitarray.h @@ -61,6 +61,7 @@ public: QBitArray(const QBitArray &other) : d(other.d) {} inline QBitArray &operator=(const QBitArray &other) { d = other.d; return *this; } #ifdef Q_COMPILER_RVALUE_REFS + inline QBitArray(QBitArray &&other) : d(std::move(other.d)) {} inline QBitArray &operator=(QBitArray &&other) { qSwap(d, other.d); return *this; } #endif diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 75900e9775..188deb4f94 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -556,6 +556,7 @@ QByteArray qUncompress(const uchar* data, int nbytes) d.take(); // realloc was successful d.reset(p); d->offset = sizeof(QByteArrayData); + d->size = 0; // Shut up valgrind "uninitialized variable" warning int res = ::uncompress((uchar*)d->data(), &len, (uchar*)data+4, nbytes-4); diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index d8e3a78cdf..0b4761d5b4 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -1474,15 +1474,15 @@ int QTime::msec() const /*! \overload - Returns the time as a string. Milliseconds are not included. The - \a format parameter determines the format of the string. + Returns the time as a string. The \a format parameter determines + the format of the string. - If \a format is Qt::TextDate, the string format is HH:MM:SS; e.g. 1 - second before midnight would be "23:59:59". + If \a format is Qt::TextDate, the string format is HH:MM:SS.zzz; + e.g. 1 second before midnight would be "23:59:59.000". If \a format is Qt::ISODate, the string format corresponds to the - ISO 8601 extended specification for representations of dates, - which is also HH:MM:SS. + ISO 8601 extended specification (with decimal fractions) for + representations of dates; also HH:MM:SS.zzz. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -1521,10 +1521,11 @@ QString QTime::toString(Qt::DateFormat format) const default: case Qt::ISODate: case Qt::TextDate: - return QString::fromLatin1("%1:%2:%3") + return QString::fromLatin1("%1:%2:%3.%4") .arg(hour(), 2, 10, QLatin1Char('0')) .arg(minute(), 2, 10, QLatin1Char('0')) - .arg(second(), 2, 10, QLatin1Char('0')); + .arg(second(), 2, 10, QLatin1Char('0')) + .arg(msec(), 3, 10, QLatin1Char('0')); } } @@ -2465,15 +2466,15 @@ void QDateTime::setTime_t(uint secsSince1Jan1970UTC) the default way. QDate::shortDayName(), QDate::shortMonthName(), and QTime::toString() are used to generate the string, so the day and month names will be localized names. An example of this - formatting is "Wed May 20 03:40:13 1998". + formatting is "Wed May 20 03:40:13.456 1998". If the \a format is Qt::ISODate, the string format corresponds - to the ISO 8601 extended specification for representations of - dates and times, taking the form YYYY-MM-DDTHH:MM:SS[Z|[+|-]HH:MM], - depending on the timeSpec() of the QDateTime. If the timeSpec() - is Qt::UTC, Z will be appended to the string; if the timeSpec() is - Qt::OffsetFromUTC, the offset in hours and minutes from UTC will - be appended to the string. + to the ISO 8601 extended specification (with decimal fractions) for + representations of dates and times, taking the form + YYYY-MM-DDTHH:MM:SS.zzz[Z|[+|-]HH:MM], depending on the timeSpec() + of the QDateTime. If the timeSpec() is Qt::UTC, Z will be appended + to the string; if the timeSpec() is Qt::OffsetFromUTC, the offset + in hours and minutes from UTC will be appended to the string. If the \a format is Qt::SystemLocaleShortDate or Qt::SystemLocaleLongDate, the string format depends on the locale @@ -3408,13 +3409,29 @@ QDateTime QDateTime::fromString(const QString& s, Qt::DateFormat f) return QDateTime(); } - int second = (timeParts.count() > 2) ? timeParts.at(2).toInt(&ok) : 0; - if (!ok) { - return QDateTime(); + int second = 0; + int millisecond = 0; + if (timeParts.count() > 2) { + QStringList secondParts = timeParts.at(2).split(QLatin1Char('.')); + if (secondParts.size() > 2) { + return QDateTime(); + } + + second = secondParts.first().toInt(&ok); + if (!ok) { + return QDateTime(); + } + + if (secondParts.size() > 1) { + millisecond = secondParts.last().toInt(&ok); + if (!ok) { + return QDateTime(); + } + } } QDate date(year, month, day); - QTime time(hour, minute, second); + QTime time(hour, minute, second, millisecond); if (parts.count() == 5) return QDateTime(date, time, Qt::LocalTime); diff --git a/src/corelib/tools/qharfbuzz_p.h b/src/corelib/tools/qharfbuzz_p.h index 27ddb44e91..1471fd5712 100644 --- a/src/corelib/tools/qharfbuzz_p.h +++ b/src/corelib/tools/qharfbuzz_p.h @@ -140,20 +140,6 @@ typedef enum { HB_ScriptCount = HB_Script_Inherited } HB_Script; -typedef enum { - HB_NoJustification= 0, /* Justification can't be applied after this glyph */ - HB_Arabic_Space = 1, /* This glyph represents a space inside arabic text */ - HB_Character = 2, /* Inter-character justification point follows this glyph */ - HB_Space = 4, /* This glyph represents a blank outside an Arabic run */ - HB_Arabic_Normal = 7, /* Normal Middle-Of-Word glyph that connects to the right (begin) */ - HB_Arabic_Waw = 8, /* Next character is final form of Waw/Ain/Qaf/Fa */ - HB_Arabic_BaRa = 9, /* Next two chars are Ba + Ra/Ya/AlefMaksura */ - HB_Arabic_Alef = 10, /* Next character is final form of Alef/Tah/Lam/Kaf/Gaf */ - HB_Arabic_HaaDal = 11, /* Next character is final form of Haa/Dal/Taa Marbutah */ - HB_Arabic_Seen = 12, /* Initial or Medial form Of Seen/Sad */ - HB_Arabic_Kashida = 13 /* Kashida(U+640) in middle of word */ -} HB_JustificationClass; - #ifdef __xlC__ typedef unsigned hb_bitfield; #else diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index 56ed6c7534..34223d5af9 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_SYSTEMLOCALE -class QSystemLocale +class Q_CORE_EXPORT QSystemLocale { public: QSystemLocale(); diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h index 96b1b65e33..9b8691a3d8 100644 --- a/src/corelib/tools/qpair.h +++ b/src/corelib/tools/qpair.h @@ -57,6 +57,19 @@ struct QPair QPair(const T1 &t1, const T2 &t2) : first(t1), second(t2) {} // compiler-generated copy/move ctor/assignment operators are fine! + template <typename TT1, typename TT2> + QPair(const QPair<TT1, TT2> &p) : first(p.first), second(p.second) {} + template <typename TT1, typename TT2> + QPair &operator=(const QPair<TT1, TT2> &p) + { first = p.first; second = p.second; return *this; } +#ifdef Q_COMPILER_RVALUE_REFS + template <typename TT1, typename TT2> + QPair(QPair<TT1, TT2> &&p) : first(std::move(p.first)), second(std::move(p.second)) {} + template <typename TT1, typename TT2> + QPair &operator=(QPair<TT1, TT2> &&p) + { first = std::move(p.first); second = std::move(p.second); return *this; } +#endif + T1 first; T2 second; }; diff --git a/src/corelib/tools/qpair.qdoc b/src/corelib/tools/qpair.qdoc index b0caf1aaf0..dd3df8c464 100644 --- a/src/corelib/tools/qpair.qdoc +++ b/src/corelib/tools/qpair.qdoc @@ -96,6 +96,26 @@ \sa qMakePair() */ +/*! + \fn QPair::QPair(const QPair<TT1, TT2> &p) + \since 5.2 + + Constructs a pair from the other pair \a p, of types TT1 and TT2. This + constructor will fail if \c first cannot be initialized from \c p.first or + if \c second cannot be initialized from \c p.second. + + \sa qMakePair() +*/ + +/*! + \fn QPair &QPair::operator=(const QPair<TT1, TT2> &p) + \since 5.2 + + Copies the pair \a p onto this pair. + + \sa qMakePair() +*/ + /*! \fn bool operator==(const QPair<T1, T2> &p1, const QPair<T1, T2> &p2) \relates QPair diff --git a/src/corelib/tools/qset.h b/src/corelib/tools/qset.h index d5c3637293..265861198d 100644 --- a/src/corelib/tools/qset.h +++ b/src/corelib/tools/qset.h @@ -70,6 +70,7 @@ public: inline QSet<T> &operator=(const QSet<T> &other) { q_hash = other.q_hash; return *this; } #ifdef Q_COMPILER_RVALUE_REFS + inline QSet(QSet &&other) : q_hash(qMove(other.q_hash)) {} inline QSet<T> &operator=(QSet<T> &&other) { qSwap(q_hash, other.q_hash); return *this; } #endif @@ -253,8 +254,16 @@ Q_INLINE_TEMPLATE QSet<T> &QSet<T>::unite(const QSet<T> &other) template <class T> Q_INLINE_TEMPLATE QSet<T> &QSet<T>::intersect(const QSet<T> &other) { - QSet<T> copy1(*this); - QSet<T> copy2(other); + QSet<T> copy1; + QSet<T> copy2; + if (size() <= other.size()) { + copy1 = *this; + copy2 = other; + } else { + copy1 = other; + copy2 = *this; + *this = copy1; + } typename QSet<T>::const_iterator i = copy1.constEnd(); while (i != copy1.constBegin()) { --i; |