diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-21 08:17:21 +0100 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2016-01-21 08:17:21 +0100 |
commit | 158a3a4159bdc5a49caecd63e021dacbc06cf23c (patch) | |
tree | c3ed9aee6cabd46e5e8615b3815b92d32857c4da /src/corelib | |
parent | 26ece94a68fb5ae680c5639716b06c4e1ae979a8 (diff) | |
parent | 7b2fb038ae4b8b9231ae989ad309b6eca107a858 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/corelib/io/qiodevice_p.h
src/corelib/kernel/qvariant_p.h
src/corelib/tools/qsimd.cpp
src/gui/kernel/qguiapplication.cpp
tests/auto/network/socket/qtcpsocket/tst_qtcpsocket.cpp
Change-Id: I742a093cbb231b282b43e463ec67173e0d29f57a
Diffstat (limited to 'src/corelib')
24 files changed, 292 insertions, 201 deletions
diff --git a/src/corelib/codecs/qutfcodec.cpp b/src/corelib/codecs/qutfcodec.cpp index 25c240d17a..230ec1ccb3 100644 --- a/src/corelib/codecs/qutfcodec.cpp +++ b/src/corelib/codecs/qutfcodec.cpp @@ -392,6 +392,7 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte // main body, stateless decoding res = 0; const uchar *nextAscii = src; + const uchar *start = src; while (res >= 0 && src < end) { if (src >= nextAscii && simdDecodeAscii(dst, nextAscii, src, end)) break; @@ -400,9 +401,11 @@ QString QUtf8::convertToUnicode(const char *chars, int len, QTextCodec::Converte res = QUtf8Functions::fromUtf8<QUtf8BaseTraits>(ch, dst, src, end); if (!headerdone && res >= 0) { headerdone = true; - // eat the UTF-8 BOM - if (dst[-1] == 0xfeff) - --dst; + if (src == start + 3) { // 3 == sizeof(utf8-bom) + // eat the UTF-8 BOM (it can only appear at the beginning of the string). + if (dst[-1] == 0xfeff) + --dst; + } } if (res == QUtf8BaseTraits::Error) { res = 0; diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index 0817dbec41..8ea2206e6b 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -566,7 +566,7 @@ qint64 QFileDevice::writeData(const char *data, qint64 len) char *writePointer = d->writeBuffer.reserve(len); if (len == 1) *writePointer = *data; - else + else if (len) ::memcpy(writePointer, data, len); return len; } diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 9cca3793a2..a84a03837d 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -229,9 +229,9 @@ QString QFileSelector::select(const QString &filePath) const static bool isLocalScheme(const QString &file) { - bool local = file == QStringLiteral("qrc"); + bool local = file == QLatin1String("qrc"); #ifdef Q_OS_ANDROID - local |= file == QStringLiteral("assets"); + local |= file == QLatin1String("assets"); #endif return local; } @@ -250,9 +250,16 @@ QUrl QFileSelector::select(const QUrl &filePath) const return filePath; QUrl ret(filePath); if (isLocalScheme(filePath.scheme())) { - QString equivalentPath = QLatin1Char(':') + filePath.path(); + QLatin1String scheme(":"); +#ifdef Q_OS_ANDROID + // use other scheme because ":" means "qrc" here + if (filePath.scheme() == QLatin1String("assets")) + scheme = QLatin1String("assets:"); +#endif + + QString equivalentPath = scheme + filePath.path(); QString selectedPath = d->select(equivalentPath); - ret.setPath(selectedPath.remove(0, 1)); + ret.setPath(selectedPath.remove(0, scheme.size())); } else { ret = QUrl::fromLocalFile(d->select(ret.toLocalFile())); } diff --git a/src/corelib/io/qfsfileengine.cpp b/src/corelib/io/qfsfileengine.cpp index 41feca8a77..7509307839 100644 --- a/src/corelib/io/qfsfileengine.cpp +++ b/src/corelib/io/qfsfileengine.cpp @@ -730,29 +730,33 @@ qint64 QFSFileEnginePrivate::writeFdFh(const char *data, qint64 len) qint64 writtenBytes = 0; - if (fh) { - // Buffered stdlib mode. - - size_t result; - do { - result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); - writtenBytes += result; - } while (result == 0 ? errno == EINTR : writtenBytes < len); + if (len) { // avoid passing nullptr to fwrite() or QT_WRITE() (UB) - } else if (fd != -1) { - // Unbuffered stdio mode. + if (fh) { + // Buffered stdlib mode. + + size_t result; + do { + result = fwrite(data + writtenBytes, 1, size_t(len - writtenBytes), fh); + writtenBytes += result; + } while (result == 0 ? errno == EINTR : writtenBytes < len); + + } else if (fd != -1) { + // Unbuffered stdio mode. + + SignedIOType result; + do { + // calculate the chunk size + // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks + // we limit to the size of the signed type, otherwise we could get a negative number as a result + quint64 wantedBytes = quint64(len) - quint64(writtenBytes); + UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max(); + if (chunkSize > wantedBytes) + chunkSize = wantedBytes; + result = QT_WRITE(fd, data + writtenBytes, chunkSize); + } while (result > 0 && (writtenBytes += result) < len); + } - SignedIOType result; - do { - // calculate the chunk size - // on Windows or 32-bit no-largefile Unix, we'll need to read in chunks - // we limit to the size of the signed type, otherwise we could get a negative number as a result - quint64 wantedBytes = quint64(len) - quint64(writtenBytes); - UnsignedIOType chunkSize = std::numeric_limits<SignedIOType>::max(); - if (chunkSize > wantedBytes) - chunkSize = wantedBytes; - result = QT_WRITE(fd, data + writtenBytes, chunkSize); - } while (result > 0 && (writtenBytes += result) < len); } if (len && writtenBytes == 0) { diff --git a/src/corelib/io/qlockfile_p.h b/src/corelib/io/qlockfile_p.h index 7ea79553e4..b41b9b4604 100644 --- a/src/corelib/io/qlockfile_p.h +++ b/src/corelib/io/qlockfile_p.h @@ -84,7 +84,7 @@ public: static QString processNameByPid(qint64 pid); #ifdef Q_OS_UNIX - static int checkFcntlWorksAfterFlock(); + static int checkFcntlWorksAfterFlock(const QString &fn); #endif QString fileName; diff --git a/src/corelib/io/qlockfile_unix.cpp b/src/corelib/io/qlockfile_unix.cpp index 8bb94ee6c1..14ad103c4e 100644 --- a/src/corelib/io/qlockfile_unix.cpp +++ b/src/corelib/io/qlockfile_unix.cpp @@ -45,6 +45,10 @@ #include "QtCore/qfileinfo.h" #include "QtCore/qdebug.h" #include "QtCore/qdatetime.h" +#include "QtCore/qfileinfo.h" +#include "QtCore/qcache.h" +#include "QtCore/qglobalstatic.h" +#include "QtCore/qmutex.h" #include "private/qcore_unix_p.h" // qt_safe_open #include "private/qabstractfileengine_p.h" @@ -100,10 +104,10 @@ static qint64 qt_write_loop(int fd, const char *data, qint64 len) return pos; } -int QLockFilePrivate::checkFcntlWorksAfterFlock() +int QLockFilePrivate::checkFcntlWorksAfterFlock(const QString &fn) { #ifndef QT_NO_TEMPORARYFILE - QTemporaryFile file; + QTemporaryFile file(fn); if (!file.open()) return 0; const int fd = file.d_func()->engine()->handle(); @@ -125,24 +129,34 @@ int QLockFilePrivate::checkFcntlWorksAfterFlock() #endif } -static QBasicAtomicInt fcntlOK = Q_BASIC_ATOMIC_INITIALIZER(-1); +// Cache the result of checkFcntlWorksAfterFlock for each directory a lock +// file is created in because in some filesystems, like NFS, both locks +// are the same. This does not take into account a filesystem changing. +// QCache is set to hold a maximum of 10 entries, this is to avoid unbounded +// growth, this is caching directories of files and it is assumed a low number +// will be sufficient. +typedef QCache<QString, bool> CacheType; +Q_GLOBAL_STATIC_WITH_ARGS(CacheType, fcntlOK, (10)); +static QBasicMutex fcntlLock; /*! \internal Checks that the OS isn't using POSIX locks to emulate flock(). OS X is one of those. */ -static bool fcntlWorksAfterFlock() +static bool fcntlWorksAfterFlock(const QString &fn) { - int value = fcntlOK.load(); - if (Q_UNLIKELY(value == -1)) { - value = QLockFilePrivate::checkFcntlWorksAfterFlock(); - fcntlOK.store(value); + QMutexLocker lock(&fcntlLock); + bool *worksPtr = fcntlOK->object(fn); + if (!worksPtr) { + worksPtr = new bool(QLockFilePrivate::checkFcntlWorksAfterFlock(fn)); + fcntlOK->insert(fn, worksPtr); } - return value == 1; + + return *worksPtr; } -static bool setNativeLocks(int fd) +static bool setNativeLocks(const QString &fileName, int fd) { #if defined(LOCK_EX) && defined(LOCK_NB) if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs @@ -154,8 +168,10 @@ static bool setNativeLocks(int fd) flockData.l_start = 0; flockData.l_len = 0; // 0 = entire file flockData.l_pid = getpid(); - if (fcntlWorksAfterFlock() && fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems + if (fcntlWorksAfterFlock(QDir::cleanPath(QFileInfo(fileName).absolutePath()) + QString('/')) + && fcntl(fd, F_SETLK, &flockData) == -1) { // for networked filesystems return false; + } return true; } @@ -182,7 +198,7 @@ QLockFile::LockError QLockFilePrivate::tryLock_sys() } } // Ensure nobody else can delete the file while we have it - if (!setNativeLocks(fd)) { + if (!setNativeLocks(fileName, fd)) { const int errnoSaved = errno; qWarning() << "setNativeLocks failed:" << qt_error_string(errnoSaved); } @@ -213,7 +229,7 @@ bool QLockFilePrivate::removeStaleLock() const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644); if (fd < 0) // gone already? return false; - bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0); + bool success = setNativeLocks(fileName, fd) && (::unlink(lockFileName) == 0); close(fd); return success; } diff --git a/src/corelib/io/qsettings.cpp b/src/corelib/io/qsettings.cpp index 956207961c..dcbd69c5e5 100644 --- a/src/corelib/io/qsettings.cpp +++ b/src/corelib/io/qsettings.cpp @@ -1408,13 +1408,17 @@ void QConfFileSettingsPrivate::syncConfFile(int confFileNo) Concurrent read and write are not a problem because the writing operation is atomic. */ QLockFile lockFile(confFile->name + QLatin1String(".lock")); +#endif if (!readOnly) { - if (!confFile->isWritable() || !lockFile.lock() ) { + if (!confFile->isWritable() +#ifndef QT_BOOTSTRAPPED + || !lockFile.lock() +#endif + ) { setStatus(QSettings::AccessError); return; } } -#endif /* We hold the lock. Let's reread the file if it has changed diff --git a/src/corelib/io/qurl.cpp b/src/corelib/io/qurl.cpp index e88024661d..ed119f61b6 100644 --- a/src/corelib/io/qurl.cpp +++ b/src/corelib/io/qurl.cpp @@ -562,6 +562,7 @@ public: inline bool hasFragment() const { return sectionIsPresent & Fragment; } inline bool isLocalFile() const { return flags & IsLocalFile; } + QString toLocalFile(QUrl::FormattingOptions options) const; QString mergePaths(const QString &relativePath) const; @@ -1466,6 +1467,33 @@ inline void QUrlPrivate::parse(const QString &url, QUrl::ParsingMode parsingMode validateComponent(Fragment, url, hash + 1, len); } +QString QUrlPrivate::toLocalFile(QUrl::FormattingOptions options) const +{ + QString tmp; + QString ourPath; + appendPath(ourPath, options, QUrlPrivate::Path); + + // magic for shared drive on windows + if (!host.isEmpty()) { + tmp = QStringLiteral("//") + host; +#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. + if (scheme == webDavScheme()) + tmp += webDavSslTag(); +#endif + if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/'))) + tmp += QLatin1Char('/'); + tmp += ourPath; + } else { + tmp = ourPath; +#ifdef Q_OS_WIN + // magic for drives on windows + if (ourPath.length() > 2 && ourPath.at(0) == QLatin1Char('/') && ourPath.at(2) == QLatin1Char(':')) + tmp.remove(0, 1); +#endif + } + return tmp; +} + /* From http://www.ietf.org/rfc/rfc3986.txt, 5.2.3: Merge paths @@ -3263,7 +3291,7 @@ QString QUrl::toString(FormattingOptions options) const && (!d->hasQuery() || options.testFlag(QUrl::RemoveQuery)) && (!d->hasFragment() || options.testFlag(QUrl::RemoveFragment)) && isLocalFile()) { - return path(options); + return d->toLocalFile(options); } QString url; @@ -3826,28 +3854,7 @@ QString QUrl::toLocalFile() const if (!isLocalFile()) return QString(); - QString tmp; - QString ourPath = path(QUrl::FullyDecoded); - - // magic for shared drive on windows - if (!d->host.isEmpty()) { - tmp = QStringLiteral("//") + host(); -#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only. - if (scheme() == webDavScheme()) - tmp += webDavSslTag(); -#endif - if (!ourPath.isEmpty() && !ourPath.startsWith(QLatin1Char('/'))) - tmp += QLatin1Char('/'); - tmp += ourPath; - } else { - tmp = ourPath; -#ifdef Q_OS_WIN - // magic for drives on windows - if (ourPath.length() > 2 && ourPath.at(0) == QLatin1Char('/') && ourPath.at(2) == QLatin1Char(':')) - tmp.remove(0, 1); -#endif - } - return tmp; + return d->toLocalFile(QUrl::FullyDecoded); } /*! diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp index 7c27a85e3e..3f599e464f 100644 --- a/src/corelib/io/qwinoverlappedionotifier.cpp +++ b/src/corelib/io/qwinoverlappedionotifier.cpp @@ -370,7 +370,7 @@ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped return false; if (triggeredOverlapped == overlapped) return true; - msecs = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); + t = qt_subtract_from_timeout(msecs, stopWatch.elapsed()); if (t == 0) return false; } diff --git a/src/corelib/json/qjson_p.h b/src/corelib/json/qjson_p.h index 9adb4b06e3..770f2c3785 100644 --- a/src/corelib/json/qjson_p.h +++ b/src/corelib/json/qjson_p.h @@ -311,7 +311,7 @@ public: { d->length = str.length(); #if Q_BYTE_ORDER == Q_BIG_ENDIAN - const qle_ushort *uc = (const qle_ushort *)str.unicode(); + const ushort *uc = (const ushort *)str.unicode(); for (int i = 0; i < str.length(); ++i) d->utf16[i] = uc[i]; #else diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 12296a3bec..d3242b6e67 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -84,6 +84,7 @@ extern uint qGlobalPostedEventsCount(); enum { WM_QT_SOCKETNOTIFIER = WM_USER, WM_QT_SENDPOSTEDEVENTS = WM_USER + 1, + WM_QT_ACTIVATENOTIFIERS = WM_USER + 2, SendPostedEventsWindowsTimerId = ~1u }; @@ -314,7 +315,7 @@ static void resolveTimerAPI() QEventDispatcherWin32Private::QEventDispatcherWin32Private() : threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0), getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), - wakeUps(0) + wakeUps(0), activateNotifiersPosted(false) { resolveTimerAPI(); } @@ -398,6 +399,7 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA if (sn) { d->doWsaAsyncSelect(sn->fd, 0); d->active_fd[sn->fd].selected = false; + d->postActivateSocketNotifiers(); if (type < 3) { QEvent event(QEvent::SockAct); QCoreApplication::sendEvent(sn->obj, &event); @@ -408,6 +410,20 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA } } return 0; + } else if (message == WM_QT_ACTIVATENOTIFIERS) { + Q_ASSERT(d != 0); + + // register all socket notifiers + for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end(); + it != end; ++it) { + QSockFd &sd = it.value(); + if (!sd.selected) { + d->doWsaAsyncSelect(it.key(), sd.event); + sd.selected = true; + } + } + d->activateNotifiersPosted = false; + return 0; } else if (message == WM_QT_SENDPOSTEDEVENTS // we also use a Windows timer to send posted events when the message queue is full || (message == WM_TIMER @@ -648,6 +664,12 @@ void QEventDispatcherWin32Private::doWsaAsyncSelect(int socket, long event) WSAAsyncSelect(socket, internalHwnd, event ? int(WM_QT_SOCKETNOTIFIER) : 0, event); } +void QEventDispatcherWin32Private::postActivateSocketNotifiers() +{ + if (!activateNotifiersPosted) + activateNotifiersPosted = PostMessage(internalHwnd, WM_QT_ACTIVATENOTIFIERS, 0, 0); +} + void QEventDispatcherWin32::createInternalHwnd() { Q_D(QEventDispatcherWin32); @@ -766,16 +788,6 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) d->queuedSocketEvents.append(msg); continue; } - } else if (!(flags & QEventLoop::ExcludeSocketNotifiers)) { - // register all socket notifiers - for (QSFDict::iterator it = d->active_fd.begin(), end = d->active_fd.end(); - it != end; ++it) { - QSockFd &sd = it.value(); - if (!sd.selected) { - d->doWsaAsyncSelect(it.key(), sd.event); - sd.selected = true; - } - } } } if (!haveMessage) { @@ -896,6 +908,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) "same socket %d and type %s", sockfd, t[type]); } + createInternalHwnd(); + QSockNot *sn = new QSockNot; sn->obj = notifier; sn->fd = sockfd; @@ -920,6 +934,8 @@ void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier) } else { d->active_fd.insert(sockfd, QSockFd(event)); } + + d->postActivateSocketNotifiers(); } void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) @@ -945,10 +961,12 @@ void QEventDispatcherWin32::unregisterSocketNotifier(QSocketNotifier *notifier) d->doWsaAsyncSelect(sockfd, 0); const long event[3] = { FD_READ | FD_CLOSE | FD_ACCEPT, FD_WRITE | FD_CONNECT, FD_OOB }; sd.event ^= event[type]; - if (sd.event == 0) + if (sd.event == 0) { d->active_fd.erase(it); - else + } else if (sd.selected) { sd.selected = false; + d->postActivateSocketNotifiers(); + } } QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except }; diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index 6efa81fe79..848dbaf475 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -184,7 +184,9 @@ public: QSNDict sn_write; QSNDict sn_except; QSFDict active_fd; + bool activateNotifiersPosted; void doWsaAsyncSelect(int socket, long event); + void postActivateSocketNotifiers(); QList<QWinEventNotifier *> winEventNotifierList; void activateEventNotifier(QWinEventNotifier * wen); diff --git a/src/corelib/kernel/qsignalmapper.cpp b/src/corelib/kernel/qsignalmapper.cpp index c738866d61..a483717da5 100644 --- a/src/corelib/kernel/qsignalmapper.cpp +++ b/src/corelib/kernel/qsignalmapper.cpp @@ -226,6 +226,9 @@ QObject *QSignalMapper::mapping(QObject *object) const Removes all mappings for \a sender. This is done automatically when mapped objects are destroyed. + + \note This does not disconnect any signals. If \a sender is not destroyed + then this will need to be done explicitly if required. */ void QSignalMapper::removeMappings(QObject *sender) { diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 143da62b63..01351f97ff 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2886,6 +2886,7 @@ static const quint32 qCanConvertMatrix[QVariant::LastCoreType + 1] = /*QUuid*/ 1 << QVariant::String }; +static const size_t qCanConvertMatrixMaximumTargetType = 8 * sizeof(*qCanConvertMatrix); #ifndef QT_BOOTSTRAPPED /*! @@ -3135,8 +3136,9 @@ bool QVariant::canConvert(int targetTypeId) const case QMetaType::ULong: case QMetaType::Short: case QMetaType::UShort: - return qCanConvertMatrix[QVariant::Int] & (1 << currentType) - || currentType == QVariant::Int + return currentType == QVariant::Int + || (currentType < qCanConvertMatrixMaximumTargetType + && qCanConvertMatrix[QVariant::Int] & (1U << currentType)) || QMetaType::typeFlags(currentType) & QMetaType::IsEnumeration; case QMetaType::QObjectStar: return canConvertMetaObject(currentType, targetTypeId, d.data.o); @@ -3147,7 +3149,8 @@ bool QVariant::canConvert(int targetTypeId) const if (targetTypeId == String && currentType == StringList) return v_cast<QStringList>(&d)->count() == 1; - return qCanConvertMatrix[targetTypeId] & (1 << currentType); + return currentType < qCanConvertMatrixMaximumTargetType + && qCanConvertMatrix[targetTypeId] & (1U << currentType); } /*! diff --git a/src/corelib/kernel/qvariant_p.h b/src/corelib/kernel/qvariant_p.h index 4d1f883651..d01f386032 100644 --- a/src/corelib/kernel/qvariant_p.h +++ b/src/corelib/kernel/qvariant_p.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2016 Intel Corporation. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -65,6 +66,7 @@ struct QVariantIntegrator { static const bool CanUseInternalSpace = sizeof(T) <= sizeof(QVariant::Private::Data) && ((QTypeInfoQuery<T>::isRelocatable) || Q_IS_ENUM(T)); + typedef QtPrivate::integral_constant<bool, CanUseInternalSpace> CanUseInternalSpace_t; }; Q_STATIC_ASSERT(QVariantIntegrator<double>::CanUseInternalSpace); Q_STATIC_ASSERT(QVariantIntegrator<long int>::CanUseInternalSpace); @@ -115,31 +117,49 @@ private: T m_t; }; -// constructs a new variant if copy is 0, otherwise copy-constructs template <class T> -inline void v_construct(QVariant::Private *x, const void *copy, T * = 0) +inline void v_construct_helper(QVariant::Private *x, const T &t, QtPrivate::true_type) { - if (!QVariantIntegrator<T>::CanUseInternalSpace) { - x->data.shared = copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T *>(copy)) - : new QVariantPrivateSharedEx<T>; - x->is_shared = true; - } else { - if (copy) - new (&x->data.ptr) T(*static_cast<const T *>(copy)); - else - new (&x->data.ptr) T; - } + new (&x->data) T(t); + x->is_shared = false; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, const T &t, QtPrivate::false_type) +{ + x->data.shared = new QVariantPrivateSharedEx<T>(t); + x->is_shared = true; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, QtPrivate::true_type) +{ + new (&x->data) T(); + x->is_shared = false; +} + +template <class T> +inline void v_construct_helper(QVariant::Private *x, QtPrivate::false_type) +{ + x->data.shared = new QVariantPrivateSharedEx<T>; + x->is_shared = true; } template <class T> inline void v_construct(QVariant::Private *x, const T &t) { - if (!QVariantIntegrator<T>::CanUseInternalSpace) { - x->data.shared = new QVariantPrivateSharedEx<T>(t); - x->is_shared = true; - } else { - new (&x->data.ptr) T(t); - } + // dispatch + v_construct_helper(x, t, typename QVariantIntegrator<T>::CanUseInternalSpace_t()); +} + +// constructs a new variant if copy is 0, otherwise copy-constructs +template <class T> +inline void v_construct(QVariant::Private *x, const void *copy, T * = 0) +{ + if (copy) + v_construct<T>(x, *static_cast<const T *>(copy)); + else + v_construct_helper<T>(x, typename QVariantIntegrator<T>::CanUseInternalSpace_t()); } // deletes the internal structures @@ -294,39 +314,11 @@ protected: template<class Filter> class QVariantConstructor { - template<typename T, bool CanUseInternalSpace = QVariantIntegrator<T>::CanUseInternalSpace> - struct CallConstructor {}; - - template<typename T> - struct CallConstructor<T, /* CanUseInternalSpace = */ true> - { - CallConstructor(const QVariantConstructor &tc) - { - if (tc.m_copy) - new (&tc.m_x->data.ptr) T(*static_cast<const T*>(tc.m_copy)); - else - new (&tc.m_x->data.ptr) T(); - tc.m_x->is_shared = false; - } - }; - - template<typename T> - struct CallConstructor<T, /* CanUseInternalSpace = */ false> - { - CallConstructor(const QVariantConstructor &tc) - { - Q_STATIC_ASSERT(QTypeInfo<T>::isComplex || sizeof(T) > sizeof(QVariant::Private::Data)); - tc.m_x->data.shared = tc.m_copy ? new QVariantPrivateSharedEx<T>(*static_cast<const T*>(tc.m_copy)) - : new QVariantPrivateSharedEx<T>; - tc.m_x->is_shared = true; - } - }; - template<typename T, bool IsAcceptedType = Filter::template Acceptor<T>::IsAccepted> struct FilteredConstructor { FilteredConstructor(const QVariantConstructor &tc) { - CallConstructor<T> tmp(tc); + v_construct<T>(tc.m_x, tc.m_copy); tc.m_x->is_null = !tc.m_copy; } }; diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp index 7c70a99baf..62a4c03d26 100644 --- a/src/corelib/statemachine/qstatemachine.cpp +++ b/src/corelib/statemachine/qstatemachine.cpp @@ -1894,12 +1894,14 @@ void QStateMachinePrivate::_q_process() } } if (enabledTransitions.isEmpty()) { - processing = false; - stopProcessingReason = EventQueueEmpty; - noMicrostep(); + if (isInternalEventQueueEmpty()) { + processing = false; + stopProcessingReason = EventQueueEmpty; + noMicrostep(); #ifdef QSTATEMACHINE_DEBUG - qDebug() << q << ": no transitions enabled"; + qDebug() << q << ": no transitions enabled"; #endif + } } else { didChange = true; q->beginMicrostep(e); diff --git a/src/corelib/thread/qexception.cpp b/src/corelib/thread/qexception.cpp index e45e6f4895..62c2b608d8 100644 --- a/src/corelib/thread/qexception.cpp +++ b/src/corelib/thread/qexception.cpp @@ -171,7 +171,7 @@ public: }; ExceptionHolder::ExceptionHolder(QException *exception) -: base(new Base(exception)) {} +: base(exception ? new Base(exception) : Q_NULLPTR) {} ExceptionHolder::ExceptionHolder(const ExceptionHolder &other) : base(other.base) @@ -187,6 +187,8 @@ ExceptionHolder::~ExceptionHolder() QException *ExceptionHolder::exception() const { + if (!base) + return Q_NULLPTR; return base->exception; } diff --git a/src/corelib/thread/qexception.h b/src/corelib/thread/qexception.h index 329b5610de..b14d386c69 100644 --- a/src/corelib/thread/qexception.h +++ b/src/corelib/thread/qexception.h @@ -92,7 +92,7 @@ class Q_CORE_EXPORT ExceptionHolder public: ExceptionHolder(QException *exception = Q_NULLPTR); ExceptionHolder(const ExceptionHolder &other); - void operator=(const ExceptionHolder &other); + void operator=(const ExceptionHolder &other); // ### Qt6: copy-assign operator shouldn't return void. Remove this method and the copy-ctor, they are unneeded. ~ExceptionHolder(); QException *exception() const; QExplicitlySharedDataPointer<Base> base; diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index fbe9a15d98..f54f7c705d 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -53,6 +53,8 @@ #include <QtCore/qmutex.h> +#include <functional> + QT_BEGIN_NAMESPACE /* @@ -63,8 +65,8 @@ class QOrderedMutexLocker { public: QOrderedMutexLocker(QMutex *m1, QMutex *m2) - : mtx1((m1 == m2) ? m1 : (m1 < m2 ? m1 : m2)), - mtx2((m1 == m2) ? 0 : (m1 < m2 ? m2 : m1)), + : mtx1((m1 == m2) ? m1 : (std::less<QMutex *>()(m1, m2) ? m1 : m2)), + mtx2((m1 == m2) ? 0 : (std::less<QMutex *>()(m1, m2) ? m2 : m1)), locked(false) { relock(); diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index afe53d6558..ae83943b7e 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -98,14 +98,25 @@ static inline QDate fixedDate(int y, int m, int d) return result; } +/* + Until C++11, rounding direction is implementation-defined. + + For negative operands, implementations may chose to round down instead of + towards zero (truncation). We only actually care about the case a < 0, as all + uses of floordiv have b > 0. In this case, if rounding is down we have a % b + >= 0 and simple division works fine; but a % b = a - (a / b) * b always, so + rounding towards zero gives a % b <= 0; when < 0, we need to adjust. + + Once we assume C++11, we can safely test a < 0 instead of a % b < 0. + */ static inline qint64 floordiv(qint64 a, int b) { - return (a - (a < 0 ? b-1 : 0)) / b; + return (a - (a % b < 0 ? b - 1 : 0)) / b; } static inline int floordiv(int a, int b) { - return (a - (a < 0 ? b-1 : 0)) / b; + return (a - (a % b < 0 ? b - 1 : 0)) / b; } static inline qint64 julianDayFromDate(int year, int month, int day) @@ -3660,6 +3671,40 @@ QString QDateTime::toString(const QString& format) const } #endif //QT_NO_DATESTRING +static void massageAdjustedDateTime(Qt::TimeSpec spec, +#ifndef QT_BOOTSTRAPPED + const QTimeZone &zone, +#endif // QT_BOOTSTRAPPED + QDate *date, + QTime *time) +{ + /* + If we have just adjusted to a day with a DST transition, our given time + may lie in the transition hour (either missing or duplicated). For any + other time, telling mktime (deep in the bowels of localMSecsToEpochMSecs) + we don't know its DST-ness will produce no adjustment (just a decision as + to its DST-ness); but for a time in spring's missing hour it'll adjust the + time while picking a DST-ness. (Handling of autumn is trickier, as either + DST-ness is valid, without adjusting the time. We might want to propagate + d->daylightStatus() in that case, but it's hard to do so without breaking + (far more common) other cases; and it makes little difference, as the two + answers do then differ only in DST-ness.) + */ + if (spec == Qt::LocalTime) { + QDateTimePrivate::DaylightStatus status = QDateTimePrivate::UnknownDaylightTime; + localMSecsToEpochMSecs(timeToMSecs(*date, *time), &status, date, time); +#ifndef QT_BOOTSTRAPPED + } else if (spec == Qt::TimeZone) { + QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(*date, *time), zone, date, time); +#endif // QT_BOOTSTRAPPED + } +} +#ifdef QT_BOOTSTRAPPED // Avoid duplicate #if-ery in uses. +#define MASSAGEADJUSTEDDATETIME(s, z, d, t) massageAdjustedDateTime(s, d, t) +#else +#define MASSAGEADJUSTEDDATETIME(s, z, d, t) massageAdjustedDateTime(s, z, d, t) +#endif // QT_BOOTSTRAPPED + /*! Returns a QDateTime object containing a datetime \a ndays days later than the datetime of this object (or earlier if \a ndays is @@ -3681,16 +3726,7 @@ QDateTime QDateTime::addDays(qint64 ndays) const QDate &date = p.first; QTime &time = p.second; date = date.addDays(ndays); - // Result might fall into "missing" DaylightTime transition hour, - // so call conversion and use the adjusted returned time - if (d->m_spec == Qt::LocalTime) { - QDateTimePrivate::DaylightStatus status = d->daylightStatus(); - localMSecsToEpochMSecs(timeToMSecs(date, time), &status, &date, &time); -#ifndef QT_BOOTSTRAPPED - } else if (d->m_spec == Qt::TimeZone) { - QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time); -#endif // QT_BOOTSTRAPPED - } + MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); dt.d->setDateTime(date, time); return dt; } @@ -3716,16 +3752,7 @@ QDateTime QDateTime::addMonths(int nmonths) const QDate &date = p.first; QTime &time = p.second; date = date.addMonths(nmonths); - // Result might fall into "missing" DaylightTime transition hour, - // so call conversion and use the adjusted returned time - if (d->m_spec == Qt::LocalTime) { - QDateTimePrivate::DaylightStatus status = d->daylightStatus(); - localMSecsToEpochMSecs(timeToMSecs(date, time), &status, &date, &time); -#ifndef QT_BOOTSTRAPPED - } else if (d->m_spec == Qt::TimeZone) { - QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time); -#endif // QT_BOOTSTRAPPED - } + MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); dt.d->setDateTime(date, time); return dt; } @@ -3751,19 +3778,11 @@ QDateTime QDateTime::addYears(int nyears) const QDate &date = p.first; QTime &time = p.second; date = date.addYears(nyears); - // Result might fall into "missing" DaylightTime transition hour, - // so call conversion and use the adjusted returned time - if (d->m_spec == Qt::LocalTime) { - QDateTimePrivate::DaylightStatus status = d->daylightStatus(); - localMSecsToEpochMSecs(timeToMSecs(date, time), &status, &date, &time); -#ifndef QT_BOOTSTRAPPED - } else if (d->m_spec == Qt::TimeZone) { - QDateTimePrivate::zoneMSecsToEpochMSecs(timeToMSecs(date, time), d->m_timeZone, &date, &time); -#endif // QT_BOOTSTRAPPED - } + MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); dt.d->setDateTime(date, time); return dt; } +#undef MASSAGEADJUSTEDDATETIME /*! Returns a QDateTime object containing a datetime \a s seconds diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 5ba1ca61d1..ace663ae30 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -388,7 +388,7 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) ++add; if (status != quote) { status = quote; - } else if (newFormat.at(i - 1) != slash) { + } else if (i > 0 && newFormat.at(i - 1) != slash) { status = zero; } } else if (status != quote) { @@ -500,15 +500,15 @@ bool QDateTimeParser::parseFormat(const QString &newFormat) } if ((newDisplay & (AmPmSection|Hour12Section)) == Hour12Section) { - const int max = newSectionNodes.size(); - for (int i=0; i<max; ++i) { + const int count = newSectionNodes.size(); + for (int i = 0; i < count; ++i) { SectionNode &node = newSectionNodes[i]; if (node.type == Hour12Section) node.type = Hour24Section; } } - if (index < newFormat.size()) { + if (index < max) { appendSeparator(&newSeparators, newFormat, index, index - max, lastQuote); } else { newSeparators.append(QString()); @@ -771,8 +771,8 @@ int QDateTimeParser::parseSection(const QDateTime ¤tValue, int sectionInde } else { state = Intermediate; } - break; } - // fall through + break; + } // else: fall through case DaySection: case YearSection: case YearSection2Digits: @@ -895,17 +895,17 @@ QDateTimeParser::StateNode QDateTimeParser::parse(QString &input, int &cursorPos QDTPDEBUG << "parse" << input; { - int year, month, day, hour12, hour, minute, second, msec, ampm, dayofweek, year2digits; + int year, month, day; currentValue.date().getDate(&year, &month, &day); - year2digits = year % 100; - hour = currentValue.time().hour(); - hour12 = -1; - minute = currentValue.time().minute(); - second = currentValue.time().second(); - msec = currentValue.time().msec(); - dayofweek = currentValue.date().dayOfWeek(); - - ampm = -1; + int year2digits = year % 100; + int hour = currentValue.time().hour(); + int hour12 = -1; + int minute = currentValue.time().minute(); + int second = currentValue.time().second(); + int msec = currentValue.time().msec(); + int dayofweek = currentValue.date().dayOfWeek(); + + int ampm = -1; Sections isSet = NoSection; int num; State tmpstate; diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 7d3ffe0b0b..90d2f99943 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -122,6 +122,13 @@ QLocale::Language QLocalePrivate::codeToLanguage(const QString &code) Q_STATIC_ASSERT(QLocale::Moldavian == QLocale::Romanian); return QLocale::Moldavian; } + // Android uses the following deprecated codes + if (uc1 == 'i' && uc2 == 'w' && uc3 == 0) // iw -> he + return QLocale::Hebrew; + if (uc1 == 'i' && uc2 == 'n' && uc3 == 0) // in -> id + return QLocale::Indonesian; + if (uc1 == 'j' && uc2 == 'i' && uc3 == 0) // ji -> yi + return QLocale::Yiddish; return QLocale::C; } diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h index 67183da778..901862e7a2 100644 --- a/src/corelib/tools/qsharedpointer.h +++ b/src/corelib/tools/qsharedpointer.h @@ -114,11 +114,11 @@ public: ~QWeakPointer(); - QWeakPointer<T> operator=(const QWeakPointer<T> &other); - QWeakPointer<T> operator=(const QSharedPointer<T> &other); + QWeakPointer<T> &operator=(const QWeakPointer<T> &other); + QWeakPointer<T> &operator=(const QSharedPointer<T> &other); QWeakPointer(const QObject *other); - QWeakPointer<T> operator=(const QObject *other); + QWeakPointer<T> &operator=(const QObject *other); void swap(QWeakPointer<T> &other); diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 21fdf9e252..0e3b1f2f82 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -92,7 +92,7 @@ public: Q_DECL_CONSTEXPR inline QLatin1String() Q_DECL_NOTHROW : m_size(0), m_data(Q_NULLPTR) {} Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) Q_DECL_NOTHROW : m_size(s ? int(strlen(s)) : 0), m_data(s) {} Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) Q_DECL_NOTHROW : m_size(sz), m_data(s) {} - inline explicit QLatin1String(const QByteArray &s) Q_DECL_NOTHROW : m_size(s.size()), m_data(s.constData()) {} + inline explicit QLatin1String(const QByteArray &s) Q_DECL_NOTHROW : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {} Q_DECL_CONSTEXPR const char *latin1() const Q_DECL_NOTHROW { return m_data; } Q_DECL_CONSTEXPR int size() const Q_DECL_NOTHROW { return m_size; } @@ -546,11 +546,11 @@ public: return fromLocal8Bit_helper(str, (str && size == -1) ? int(strlen(str)) : size); } static inline QString fromLatin1(const QByteArray &str) - { return str.isNull() ? QString() : fromLatin1(str.data(), str.size()); } + { return str.isNull() ? QString() : fromLatin1(str.data(), qstrnlen(str.constData(), str.size())); } static inline QString fromUtf8(const QByteArray &str) - { return str.isNull() ? QString() : fromUtf8(str.data(), str.size()); } + { return str.isNull() ? QString() : fromUtf8(str.data(), qstrnlen(str.constData(), str.size())); } static inline QString fromLocal8Bit(const QByteArray &str) - { return str.isNull() ? QString() : fromLocal8Bit(str.data(), str.size()); } + { return str.isNull() ? QString() : fromLocal8Bit(str.data(), qstrnlen(str.constData(), str.size())); } static QString fromUtf16(const ushort *, int size = -1); static QString fromUcs4(const uint *, int size = -1); static QString fromRawData(const QChar *, int size); @@ -663,7 +663,7 @@ public: : d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1)) {} inline QT_ASCII_CAST_WARN QString(const QByteArray &a) - : d(fromAscii_helper(a.constData(), a.size())) + : d(fromAscii_helper(a.constData(), qstrnlen(a.constData(), a.size()))) {} inline QT_ASCII_CAST_WARN QString &operator=(const char *ch) { return (*this = fromUtf8(ch)); } @@ -1232,9 +1232,9 @@ inline QT_ASCII_CAST_WARN bool QLatin1String::operator>=(const QByteArray &s) co { return QString::fromUtf8(s) <= *this; } inline QT_ASCII_CAST_WARN bool QString::operator==(const QByteArray &s) const -{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) == 0; } +{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) == 0; } inline QT_ASCII_CAST_WARN bool QString::operator!=(const QByteArray &s) const -{ return QString::compare_helper(constData(), size(), s.constData(), s.size()) != 0; } +{ return QString::compare_helper(constData(), size(), s.constData(), qstrnlen(s.constData(), s.size())) != 0; } inline QT_ASCII_CAST_WARN bool QString::operator<(const QByteArray &s) const { return QString::compare_helper(constData(), size(), s.constData(), s.size()) < 0; } inline QT_ASCII_CAST_WARN bool QString::operator>(const QByteArray &s) const @@ -1245,9 +1245,9 @@ inline QT_ASCII_CAST_WARN bool QString::operator>=(const QByteArray &s) const { return QString::compare_helper(constData(), size(), s.constData(), s.size()) >= 0; } inline bool QByteArray::operator==(const QString &s) const -{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) == 0; } +{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) == 0; } inline bool QByteArray::operator!=(const QString &s) const -{ return QString::compare_helper(s.constData(), s.size(), constData(), size()) != 0; } +{ return QString::compare_helper(s.constData(), s.size(), constData(), qstrnlen(constData(), size())) != 0; } inline bool QByteArray::operator<(const QString &s) const { return QString::compare_helper(s.constData(), s.size(), constData(), size()) > 0; } inline bool QByteArray::operator>(const QString &s) const |