diff options
33 files changed, 466 insertions, 358 deletions
diff --git a/src/corelib/global/qhooks.cpp b/src/corelib/global/qhooks.cpp index 40a7c88f13..88df9c2be9 100644 --- a/src/corelib/global/qhooks.cpp +++ b/src/corelib/global/qhooks.cpp @@ -61,7 +61,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = { // The required sizes and offsets are tested in tests/auto/other/toolsupport. // When this fails and the change was intentional, adjust the test and // adjust this value here. - 0 + 1 }; Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0])); diff --git a/src/corelib/io/qfiledevice.cpp b/src/corelib/io/qfiledevice.cpp index 4c5ed0aef6..e94da6de64 100644 --- a/src/corelib/io/qfiledevice.cpp +++ b/src/corelib/io/qfiledevice.cpp @@ -355,7 +355,7 @@ bool QFileDevice::atEnd() const Q_D(const QFileDevice); // If there's buffered data left, we're not at the end. - if (!d->buffer.isEmpty()) + if (!d->isBufferEmpty()) return false; if (!isOpen()) diff --git a/src/corelib/io/qfilesystemengine_unix.cpp b/src/corelib/io/qfilesystemengine_unix.cpp index 8f6d9911e8..2f066aa37a 100644 --- a/src/corelib/io/qfilesystemengine_unix.cpp +++ b/src/corelib/io/qfilesystemengine_unix.cpp @@ -113,7 +113,7 @@ static bool isPackage(const QFileSystemMetaData &data, const QFileSystemEntry &e // Find if an application other than Finder claims to know how to handle the package QCFType<CFURLRef> application; LSGetApplicationForURL(url, - kLSRolesEditor|kLSRolesViewer|kLSRolesViewer, + kLSRolesEditor|kLSRolesViewer, NULL, &application); diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 64078b5c54..00b50af5ca 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -143,7 +143,9 @@ static void checkWarnMessage(const QIODevice *device, const char *function, cons */ QIODevicePrivate::QIODevicePrivate() : openMode(QIODevice::NotOpen), buffer(QIODEVICE_BUFFERSIZE), - pos(0), devicePos(0) + pos(0), devicePos(0), + transactionPos(0), + transactionStarted(false) , baseReadLineDataCalled(false) , accessMode(Unset) #ifdef QT_NO_QOBJECT @@ -264,6 +266,12 @@ QIODevicePrivate::~QIODevicePrivate() subclassing QIODevice, remember to bypass any buffer you may use when the device is open in Unbuffered mode. + Usually, the incoming data stream from an asynchronous device is + fragmented, and chunks of data can arrive at arbitrary points in time. + To handle incomplete reads of data structures, use the transaction + mechanism implemented by QIODevice. See startTransaction() and related + functions for more details. + \sa QBuffer, QFile, QTcpSocket */ @@ -588,6 +596,8 @@ void QIODevice::close() d->openMode = NotOpen; d->errorString.clear(); d->pos = 0; + d->transactionStarted = false; + d->transactionPos = 0; d->buffer.clear(); } @@ -660,18 +670,8 @@ bool QIODevice::seek(qint64 pos) this, pos, d->pos, d->buffer.size()); #endif - qint64 offset = pos - d->pos; - d->pos = pos; d->devicePos = pos; - - if (offset < 0 || offset >= d->buffer.size()) - // When seeking backwards, an operation that is only allowed for - // random-access devices, the buffer is cleared. The next read - // operation will then refill the buffer. We can optimize this, if we - // find that seeking backwards becomes a significant performance hit. - d->buffer.clear(); - else - d->buffer.skip(offset); + d->seekBuffer(pos); #if defined QIODEVICE_DEBUG printf("%p \tafter: d->pos == %lld, d->buffer.size() == %lld\n", this, d->pos, @@ -681,6 +681,24 @@ bool QIODevice::seek(qint64 pos) } /*! + \internal +*/ +void QIODevicePrivate::seekBuffer(qint64 newPos) +{ + const qint64 offset = newPos - pos; + pos = newPos; + + if (offset < 0 || offset >= buffer.size()) { + // When seeking backwards, an operation that is only allowed for + // random-access devices, the buffer is cleared. The next read + // operation will then refill the buffer. + buffer.clear(); + } else { + buffer.free(offset); + } +} + +/*! Returns \c true if the current read and write position is at the end of the device (i.e. there is no more data available for reading on the device); otherwise returns \c false. @@ -695,7 +713,7 @@ bool QIODevice::seek(qint64 pos) bool QIODevice::atEnd() const { Q_D(const QIODevice); - const bool result = (d->openMode == NotOpen || (d->buffer.isEmpty() + const bool result = (d->openMode == NotOpen || (d->isBufferEmpty() && bytesAvailable() == 0)); #if defined QIODEVICE_DEBUG printf("%p QIODevice::atEnd() returns %s, d->openMode == %d, d->pos == %lld\n", this, @@ -740,7 +758,7 @@ qint64 QIODevice::bytesAvailable() const Q_D(const QIODevice); if (!d->isSequential()) return qMax(size() - d->pos, qint64(0)); - return d->buffer.size(); + return d->buffer.size() - d->transactionPos; } /*! For buffered devices, this function returns the number of bytes @@ -777,9 +795,10 @@ qint64 QIODevice::read(char *data, qint64 maxSize) #endif const bool sequential = d->isSequential(); + const bool keepDataInBuffer = sequential && d->transactionStarted; // Short circuit for getChar() - if (maxSize == 1) { + if (maxSize == 1 && !keepDataInBuffer) { int chint; while ((chint = d->buffer.getChar()) != -1) { if (!sequential) @@ -806,9 +825,13 @@ qint64 QIODevice::read(char *data, qint64 maxSize) char *readPtr = data; forever { // Try reading from the buffer. - qint64 bufferReadChunkSize = d->buffer.read(data, maxSize); + qint64 bufferReadChunkSize = keepDataInBuffer + ? d->buffer.peek(data, maxSize, d->transactionPos) + : d->buffer.read(data, maxSize); if (bufferReadChunkSize > 0) { - if (!sequential) + if (keepDataInBuffer) + d->transactionPos += bufferReadChunkSize; + else if (!sequential) d->pos += bufferReadChunkSize; readSoFar += bufferReadChunkSize; data += bufferReadChunkSize; @@ -826,7 +849,8 @@ qint64 QIODevice::read(char *data, qint64 maxSize) // Make sure the device is positioned correctly. if (sequential || d->pos == d->devicePos || seek(d->pos)) { madeBufferReadsOnly = false; // fix readData attempt - if (maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered)) { + if ((maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered)) + && !keepDataInBuffer) { // Read big chunk directly to output buffer readFromDevice = readData(data, maxSize); deviceAtEof = (readFromDevice != maxSize); @@ -844,7 +868,9 @@ qint64 QIODevice::read(char *data, qint64 maxSize) } } } else { - const qint64 bytesToBuffer = QIODEVICE_BUFFERSIZE; + // Do not read more than maxSize on unbuffered devices + const qint64 bytesToBuffer = (d->openMode & Unbuffered) + ? qMin(maxSize, QIODEVICE_BUFFERSIZE) : QIODEVICE_BUFFERSIZE; // Try to fill QIODevice buffer by single read readFromDevice = readData(d->buffer.reserve(bytesToBuffer), bytesToBuffer); deviceAtEof = (readFromDevice != bytesToBuffer); @@ -907,10 +933,8 @@ qint64 QIODevice::read(char *data, qint64 maxSize) debugBinaryString(data - readSoFar, readSoFar); #endif - if (madeBufferReadsOnly && d->buffer.isEmpty()) { - d->buffer.clear(); + if (madeBufferReadsOnly && d->isBufferEmpty()) readData(data, 0); - } return readSoFar; } @@ -992,7 +1016,9 @@ QByteArray QIODevice::readAll() qint64 readBytes = (d->isSequential() ? Q_INT64_C(0) : size()); if (readBytes == 0) { // Size is unknown, read incrementally. - qint64 readChunkSize = qMax(d->buffer.size(), QIODEVICE_BUFFERSIZE); + qint64 readChunkSize = qMax(QIODEVICE_BUFFERSIZE, + d->isSequential() ? (d->buffer.size() - d->transactionPos) + : d->buffer.size()); qint64 readResult; do { if (readBytes + readChunkSize >= MaxByteArraySize) { @@ -1077,21 +1103,35 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) --maxSize; const bool sequential = d->isSequential(); + const bool keepDataInBuffer = sequential && d->transactionStarted; qint64 readSoFar = 0; - if (!d->buffer.isEmpty()) { - readSoFar = d->buffer.readLine(data, maxSize); + if (keepDataInBuffer) { + if (d->transactionPos < d->buffer.size()) { + // Peek line from the specified position + const qint64 i = d->buffer.indexOf('\n', maxSize, d->transactionPos); + readSoFar = d->buffer.peek(data, i >= 0 ? (i - d->transactionPos + 1) : maxSize, + d->transactionPos); + d->transactionPos += readSoFar; + if (d->transactionPos == d->buffer.size()) + readData(data, 0); + } + } else if (!d->buffer.isEmpty()) { + // QRingBuffer::readLine() terminates the line with '\0' + readSoFar = d->buffer.readLine(data, maxSize + 1); if (d->buffer.isEmpty()) readData(data,0); if (!sequential) d->pos += readSoFar; + } + + if (readSoFar) { #if defined QIODEVICE_DEBUG printf("%p \tread from buffer: %lld bytes, last character read: %hhx\n", this, readSoFar, data[readSoFar - 1]); - if (readSoFar) - debugBinaryString(data, int(readSoFar)); + debugBinaryString(data, int(readSoFar)); #endif - if (readSoFar && data[readSoFar - 1] == '\n') { + if (data[readSoFar - 1] == '\n') { if (d->openMode & Text) { // QRingBuffer::readLine() isn't Text aware. if (readSoFar > 1 && data[readSoFar - 2] == '\r') { @@ -1107,7 +1147,11 @@ qint64 QIODevice::readLine(char *data, qint64 maxSize) if (d->pos != d->devicePos && !sequential && !seek(d->pos)) return qint64(-1); d->baseReadLineDataCalled = false; - qint64 readBytes = readLineData(data + readSoFar, maxSize - readSoFar); + // Force base implementation for transaction on sequential device + // as it stores the data in internal buffer automatically. + qint64 readBytes = keepDataInBuffer + ? QIODevice::readLineData(data + readSoFar, maxSize - readSoFar) + : readLineData(data + readSoFar, maxSize - readSoFar); #if defined QIODEVICE_DEBUG printf("%p \tread from readLineData: %lld bytes, readSoFar = %lld bytes\n", this, readBytes, readSoFar); @@ -1262,7 +1306,95 @@ qint64 QIODevice::readLineData(char *data, qint64 maxSize) */ bool QIODevice::canReadLine() const { - return d_func()->buffer.canReadLine(); + Q_D(const QIODevice); + return d->buffer.indexOf('\n', d->buffer.size(), + d->isSequential() ? d->transactionPos : Q_INT64_C(0)) >= 0; +} + +/*! + \since 5.7 + + Starts a new read transaction on the device. + + Defines a restorable point within the sequence of read operations. For + sequential devices, read data will be duplicated internally to allow + recovery in case of incomplete reads. For random-access devices, + this function saves the current position. Call commitTransaction() or + rollbackTransaction() to finish the transaction. + + \note Nesting transactions is not supported. + + \sa commitTransaction(), rollbackTransaction() +*/ +void QIODevice::startTransaction() +{ + Q_D(QIODevice); + if (d->transactionStarted) { + checkWarnMessage(this, "startTransaction", "Called while transaction already in progress"); + return; + } + d->transactionPos = d->pos; + d->transactionStarted = true; +} + +/*! + \since 5.7 + + Completes a read transaction. + + For sequential devices, all data recorded in the internal buffer during + the transaction will be discarded. + + \sa startTransaction(), rollbackTransaction() +*/ +void QIODevice::commitTransaction() +{ + Q_D(QIODevice); + if (!d->transactionStarted) { + checkWarnMessage(this, "commitTransaction", "Called while no transaction in progress"); + return; + } + if (d->isSequential()) + d->buffer.free(d->transactionPos); + d->transactionStarted = false; + d->transactionPos = 0; +} + +/*! + \since 5.7 + + Rolls back a read transaction. + + Restores the input stream to the point of the startTransaction() call. + This function is commonly used to rollback the transaction when an + incomplete read was detected prior to committing the transaction. + + \sa startTransaction(), commitTransaction() +*/ +void QIODevice::rollbackTransaction() +{ + Q_D(QIODevice); + if (!d->transactionStarted) { + checkWarnMessage(this, "rollbackTransaction", "Called while no transaction in progress"); + return; + } + if (!d->isSequential()) + d->seekBuffer(d->transactionPos); + d->transactionStarted = false; + d->transactionPos = 0; +} + +/*! + \since 5.7 + + Returns \c true if a transaction is in progress on the device, otherwise + \c false. + + \sa startTransaction() +*/ +bool QIODevice::isTransactionStarted() const +{ + return d_func()->transactionStarted; } /*! @@ -1386,12 +1518,19 @@ qint64 QIODevice::write(const char *data) If \a c was not previously read from the device, the behavior is undefined. + + \note This function is not available while a transaction is in progress. */ void QIODevice::ungetChar(char c) { Q_D(QIODevice); CHECK_READABLE(read, Q_VOID); + if (d->transactionStarted) { + checkWarnMessage(this, "ungetChar", "Called while transaction is in progress"); + return; + } + #if defined QIODEVICE_DEBUG printf("%p QIODevice::ungetChar(0x%hhx '%c')\n", this, c, isprint(c) ? c : '?'); #endif @@ -1426,13 +1565,26 @@ bool QIODevicePrivate::putCharHelper(char c) */ qint64 QIODevicePrivate::peek(char *data, qint64 maxSize) { - qint64 readBytes = q_func()->read(data, maxSize); - if (readBytes <= 0) + Q_Q(QIODevice); + + if (transactionStarted) { + const qint64 savedTransactionPos = transactionPos; + const qint64 savedPos = pos; + + qint64 readBytes = q->read(data, maxSize); + + // Restore initial position + if (isSequential()) + transactionPos = savedTransactionPos; + else + seekBuffer(savedPos); return readBytes; + } + + q->startTransaction(); + qint64 readBytes = q->read(data, maxSize); + q->rollbackTransaction(); - buffer.ungetBlock(data, readBytes); - if (!isSequential()) - pos -= readBytes; return readBytes; } @@ -1441,14 +1593,26 @@ qint64 QIODevicePrivate::peek(char *data, qint64 maxSize) */ QByteArray QIODevicePrivate::peek(qint64 maxSize) { - QByteArray result = q_func()->read(maxSize); + Q_Q(QIODevice); + + if (transactionStarted) { + const qint64 savedTransactionPos = transactionPos; + const qint64 savedPos = pos; + + QByteArray result = q->read(maxSize); - if (result.isEmpty()) + // Restore initial position + if (isSequential()) + transactionPos = savedTransactionPos; + else + seekBuffer(savedPos); return result; + } + + q->startTransaction(); + QByteArray result = q->read(maxSize); + q->rollbackTransaction(); - buffer.ungetBlock(result.constData(), result.size()); - if (!isSequential()) - pos -= result.size(); return result; } diff --git a/src/corelib/io/qiodevice.h b/src/corelib/io/qiodevice.h index b62c8d266c..49f6848540 100644 --- a/src/corelib/io/qiodevice.h +++ b/src/corelib/io/qiodevice.h @@ -111,6 +111,11 @@ public: QByteArray readLine(qint64 maxlen = 0); virtual bool canReadLine() const; + void startTransaction(); + void commitTransaction(); + void rollbackTransaction(); + bool isTransactionStarted() const; + qint64 write(const char *data, qint64 len); qint64 write(const char *data); inline qint64 write(const QByteArray &data) diff --git a/src/corelib/io/qiodevice_p.h b/src/corelib/io/qiodevice_p.h index 56a89ab680..45f5219240 100644 --- a/src/corelib/io/qiodevice_p.h +++ b/src/corelib/io/qiodevice_p.h @@ -62,138 +62,6 @@ QT_BEGIN_NAMESPACE Q_CORE_EXPORT int qt_subtract_from_timeout(int timeout, int elapsed); -// This is QIODevice's read buffer, optimized for read(), isEmpty() and getChar() -class QIODevicePrivateLinearBuffer -{ -public: - QIODevicePrivateLinearBuffer(int) : len(0), first(0), buf(0), capacity(0) { - } - ~QIODevicePrivateLinearBuffer() { - delete [] buf; - } - void clear() { - len = 0; - delete [] buf; - buf = 0; - first = buf; - capacity = 0; - } - qint64 size() const { - return len; - } - bool isEmpty() const { - return len == 0; - } - void skip(qint64 n) { - if (n >= len) { - clear(); - } else { - len -= n; - first += n; - } - } - int getChar() { - if (len == 0) - return -1; - int ch = uchar(*first); - len--; - first++; - return ch; - } - qint64 read(char* target, qint64 size) { - qint64 r = qMin(size, len); - memcpy(target, first, r); - len -= r; - first += r; - return r; - } - qint64 peek(char* target, qint64 size) { - qint64 r = qMin(size, len); - memcpy(target, first, r); - return r; - } - char* reserve(qint64 size) { - makeSpace(size + len, freeSpaceAtEnd); - char* writePtr = first + len; - len += size; - return writePtr; - } - void chop(qint64 size) { - if (size >= len) { - clear(); - } else { - len -= size; - } - } - QByteArray readAll() { - QByteArray retVal(first, len); - clear(); - return retVal; - } - qint64 readLine(char* target, qint64 size) { - qint64 r = qMin(size, len); - char* eol = static_cast<char*>(memchr(first, '\n', r)); - if (eol) - r = 1+(eol-first); - memcpy(target, first, r); - len -= r; - first += r; - return r; - } - bool canReadLine() const { - return memchr(first, '\n', len); - } - void ungetChar(char c) { - if (first == buf) { - // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer - makeSpace(len+1, freeSpaceAtStart); - } - first--; - len++; - *first = c; - } - void ungetBlock(const char* block, qint64 size) { - if ((first - buf) < size) { - // underflow, the existing valid data needs to move to the end of the (potentially bigger) buffer - makeSpace(len + size, freeSpaceAtStart); - } - first -= size; - len += size; - memcpy(first, block, size); - } - -private: - enum FreeSpacePos {freeSpaceAtStart, freeSpaceAtEnd}; - void makeSpace(size_t required, FreeSpacePos where) { - size_t newCapacity = qMax(capacity, size_t(QIODEVICE_BUFFERSIZE)); - while (newCapacity < required) - newCapacity *= 2; - const size_t moveOffset = (where == freeSpaceAtEnd) ? 0 : newCapacity - size_t(len); - if (newCapacity > capacity) { - // allocate more space - char* newBuf = new char[newCapacity]; - memmove(newBuf + moveOffset, first, len); - delete [] buf; - buf = newBuf; - capacity = newCapacity; - } else { - // shift any existing data to make space - memmove(buf + moveOffset, first, len); - } - first = buf + moveOffset; - } - -private: - // length of the unread data - qint64 len; - // start of the unread data - char* first; - // the allocated buffer - char* buf; - // allocated buffer size - size_t capacity; -}; - class Q_CORE_EXPORT QIODevicePrivate #ifndef QT_NO_QOBJECT : public QObjectPrivate @@ -208,9 +76,11 @@ public: QIODevice::OpenMode openMode; QString errorString; - QIODevicePrivateLinearBuffer buffer; + QRingBuffer buffer; qint64 pos; qint64 devicePos; + qint64 transactionPos; + bool transactionStarted; bool baseReadLineDataCalled; virtual bool putCharHelper(char c); @@ -228,6 +98,13 @@ public: return accessMode == Sequential; } + inline bool isBufferEmpty() const + { + return buffer.isEmpty() || (transactionStarted && isSequential() + && transactionPos == buffer.size()); + } + void seekBuffer(qint64 newPos); + virtual qint64 peek(char *data, qint64 maxSize); virtual QByteArray peek(qint64 maxSize); diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp index 823dc4c144..2392f7cbfd 100644 --- a/src/corelib/io/qprocess.cpp +++ b/src/corelib/io/qprocess.cpp @@ -1395,15 +1395,17 @@ QProcess::ProcessChannel QProcess::readChannel() const void QProcess::setReadChannel(ProcessChannel channel) { Q_D(QProcess); + + if (d->transactionStarted) { + qWarning("QProcess::setReadChannel: Failed due to the active read transaction"); + return; + } + if (d->processChannel != channel) { - QByteArray buf = d->buffer.readAll(); - if (d->processChannel == QProcess::StandardOutput) { - for (int i = buf.size() - 1; i >= 0; --i) - d->stdoutChannel.buffer.ungetChar(buf.at(i)); - } else { - for (int i = buf.size() - 1; i >= 0; --i) - d->stderrChannel.buffer.ungetChar(buf.at(i)); - } + QRingBuffer *buffer = (d->processChannel == QProcess::StandardOutput) + ? &d->stdoutChannel.buffer + : &d->stderrChannel.buffer; + d->buffer.read(buffer->reserveFront(d->buffer.size()), d->buffer.size()); } d->processChannel = channel; } diff --git a/src/corelib/kernel/qcfsocketnotifier.cpp b/src/corelib/kernel/qcfsocketnotifier.cpp index 7f4c26d978..62272c1bca 100644 --- a/src/corelib/kernel/qcfsocketnotifier.cpp +++ b/src/corelib/kernel/qcfsocketnotifier.cpp @@ -235,7 +235,7 @@ void QCFSocketNotifier::unregisterSocketNotifier(QSocketNotifier *notifier) void QCFSocketNotifier::removeSocketNotifiers() { // Remove CFSockets from the runloop. - foreach (MacSocketInfo *socketInfo, macSockets) { + for (MacSocketInfo *socketInfo : qAsConst(macSockets)) { unregisterSocketInfo(socketInfo); delete socketInfo; } @@ -272,9 +272,9 @@ void QCFSocketNotifier::enableSocketNotifiers(CFRunLoopObserverRef ref, CFRunLoo Q_UNUSED(ref); Q_UNUSED(activity); - QCFSocketNotifier *that = static_cast<QCFSocketNotifier *>(info); + const QCFSocketNotifier *that = static_cast<QCFSocketNotifier *>(info); - foreach (MacSocketInfo *socketInfo, that->macSockets) { + for (MacSocketInfo *socketInfo : that->macSockets) { if (!CFSocketIsValid(socketInfo->socket)) continue; diff --git a/src/corelib/kernel/qcoreapplication_win.cpp b/src/corelib/kernel/qcoreapplication_win.cpp index 324b664a1a..f427f6d062 100644 --- a/src/corelib/kernel/qcoreapplication_win.cpp +++ b/src/corelib/kernel/qcoreapplication_win.cpp @@ -154,7 +154,7 @@ void qWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdParam, const QStringList wArgv = qWinCmdArgs(QString::fromLocal8Bit(cmdParam)); argv.clear(); argc = wArgv.size(); - foreach (const QString &wArg, wArgv) + for (const QString &wArg : wArgv) argv.append(_strdup(wArg.toLocal8Bit().constData())); } diff --git a/src/corelib/kernel/qeventdispatcher_winrt.cpp b/src/corelib/kernel/qeventdispatcher_winrt.cpp index df070dd1ae..37738198e2 100644 --- a/src/corelib/kernel/qeventdispatcher_winrt.cpp +++ b/src/corelib/kernel/qeventdispatcher_winrt.cpp @@ -376,7 +376,8 @@ bool QEventDispatcherWinRT::unregisterTimers(QObject *object) } Q_D(QEventDispatcherWinRT); - foreach (int id, d->timerIdToObject.keys()) { + const auto timerIds = d->timerIdToObject.keys(); // ### FIXME: iterate over hash directly? But unregisterTimer() modifies the hash! + for (int id : timerIds) { if (d->timerIdToObject.value(id) == object) unregisterTimer(id); } @@ -395,7 +396,7 @@ QList<QAbstractEventDispatcher::TimerInfo> QEventDispatcherWinRT::registeredTime Q_D(const QEventDispatcherWinRT); QList<TimerInfo> timerInfos; - foreach (const WinRTTimerInfo &info, d->timerInfos) { + for (const WinRTTimerInfo &info : d->timerInfos) { if (info.object == object && info.timerId != INVALID_TIMER_ID) timerInfos.append(info); } diff --git a/src/corelib/kernel/qjnihelpers.cpp b/src/corelib/kernel/qjnihelpers.cpp index 0a5a5dffb9..f372230ff6 100644 --- a/src/corelib/kernel/qjnihelpers.cpp +++ b/src/corelib/kernel/qjnihelpers.cpp @@ -69,7 +69,7 @@ static jboolean dispatchGenericMotionEvent(JNIEnv *, jclass, jobject event) { jboolean ret = JNI_FALSE; QMutexLocker locker(&g_genericMotionEventListeners()->mutex); - foreach (auto listener, g_genericMotionEventListeners()->listeners) + for (auto *listener : qAsConst(g_genericMotionEventListeners()->listeners)) ret |= listener->handleGenericMotionEvent(event); return ret; } @@ -86,7 +86,7 @@ static jboolean dispatchKeyEvent(JNIEnv *, jclass, jobject event) { jboolean ret = JNI_FALSE; QMutexLocker locker(&g_keyEventListeners()->mutex); - foreach (auto listener, g_keyEventListeners()->listeners) + for (auto *listener : qAsConst(g_keyEventListeners()->listeners)) ret |= listener->handleKeyEvent(event); return ret; } diff --git a/src/corelib/kernel/qppsobject.cpp b/src/corelib/kernel/qppsobject.cpp index 76508f12c5..065a053bec 100644 --- a/src/corelib/kernel/qppsobject.cpp +++ b/src/corelib/kernel/qppsobject.cpp @@ -349,7 +349,8 @@ QVariant QPpsObjectPrivate::variantFromPpsAttribute(const QPpsAttribute &attribu return attribute.toString(); case QPpsAttribute::Array: { QVariantList variantList; - Q_FOREACH (const QPpsAttribute &attr, attribute.toList()) { + const auto attrs = attribute.toList(); + for (const QPpsAttribute &attr : attrs) { QVariant variant = variantFromPpsAttribute(attr); if (!variant.isValid()) return QVariantList(); diff --git a/src/corelib/kernel/qtcore_eval.cpp b/src/corelib/kernel/qtcore_eval.cpp index 0dd0e64977..1447d7033c 100644 --- a/src/corelib/kernel/qtcore_eval.cpp +++ b/src/corelib/kernel/qtcore_eval.cpp @@ -136,7 +136,6 @@ static QString qt_eval_string() break; default: return QString(); - msg = 0; } return QString::fromLatin1(msg) diff --git a/src/corelib/kernel/qtranslator.cpp b/src/corelib/kernel/qtranslator.cpp index dad471c1b0..f8523eaded 100644 --- a/src/corelib/kernel/qtranslator.cpp +++ b/src/corelib/kernel/qtranslator.cpp @@ -652,7 +652,7 @@ static QString find_translation(const QLocale & locale, #endif // try explicit locales names first - foreach (QString localeName, languages) { + for (QString localeName : qAsConst(languages)) { localeName.replace(QLatin1Char('-'), QLatin1Char('_')); realname += localeName + suffixOrDotQM; @@ -668,7 +668,8 @@ static QString find_translation(const QLocale & locale, } // start guessing - foreach (QString localeName, fuzzyLocales) { + for (const QString &fuzzyLocale : qAsConst(fuzzyLocales)) { + QStringRef localeName(&fuzzyLocale); for (;;) { int rightmost = localeName.lastIndexOf(QLatin1Char('_')); // no truncations? fail @@ -708,7 +709,8 @@ static QString find_translation(const QLocale & locale, if (is_readable_file(realname)) return realname; - return QString(); + realname.truncate(0); + return realname; } /*! @@ -1046,7 +1048,7 @@ QString QTranslatorPrivate::do_translate(const char *context, const char *source } searchDependencies: - foreach (QTranslator *translator, subTranslators) { + for (QTranslator *translator : subTranslators) { QString tn = translator->translate(context, sourceText, comment, n); if (!tn.isNull()) return tn; diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index 1f4d0c88c5..af2522acc3 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -869,6 +869,14 @@ bool QLocale::operator!=(const QLocale &other) const } /*! + \fn void QLocale::swap(QLocale &other) + \since 5.6 + + Swaps locale \a other with this locale. This operation is very fast and + never fails. +*/ + +/*! \since 5.6 \relates QLocale @@ -3452,12 +3460,23 @@ QString QLocale::toCurrencyString(qulonglong value, const QString &symbol) const return format.arg(str, sym); } +#if QT_VERSION < QT_VERSION_CHECK(6,0,0) /*! \since 4.8 \overload */ QString QLocale::toCurrencyString(double value, const QString &symbol) const { + return toCurrencyString(value, symbol, d->m_data->m_currency_digits); +} +#endif + +/*! + \since 5.7 + \overload + */ +QString QLocale::toCurrencyString(double value, const QString &symbol, int precision) const +{ #ifndef QT_NO_SYSTEMLOCALE if (d->m_data == systemData()) { QSystemLocale::CurrencyToStringArgument arg(value, symbol); @@ -3474,7 +3493,7 @@ QString QLocale::toCurrencyString(double value, const QString &symbol) const size = data->m_currency_negative_format_size; value = -value; } - QString str = toString(value, 'f', d->m_data->m_currency_digits); + QString str = toString(value, 'f', precision == -1 ? d->m_data->m_currency_digits : precision); QString sym = symbol.isNull() ? currencySymbol() : symbol; if (sym.isEmpty()) sym = currencySymbol(QLocale::CurrencyIsoCode); diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index e90354138c..1f4083950c 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -866,9 +866,13 @@ public: QLocale(Language language, Country country = AnyCountry); QLocale(Language language, Script script, Country country); QLocale(const QLocale &other); +#ifdef Q_COMPILER_RVALUE_REFS + QLocale &operator=(QLocale &&other) Q_DECL_NOTHROW { swap(other); return *this; } +#endif + QLocale &operator=(const QLocale &other); ~QLocale(); - QLocale &operator=(const QLocale &other); + void swap(QLocale &other) Q_DECL_NOTHROW { qSwap(d, other.d); } Language language() const; Script script() const; @@ -959,8 +963,18 @@ public: inline QString toCurrencyString(ushort, const QString &symbol = QString()) const; inline QString toCurrencyString(int, const QString &symbol = QString()) const; inline QString toCurrencyString(uint, const QString &symbol = QString()) const; +#if QT_VERSION >= QT_VERSION_CHECK(6,0,0) + QString toCurrencyString(double, const QString &symbol = QString(), int precision = -1) const; + inline QString toCurrencyString(float i, const QString &symbol = QString(), int precision = -1) const + { return toCurrencyString(double(i), symbol, precision); } +#else QString toCurrencyString(double, const QString &symbol = QString()) const; - inline QString toCurrencyString(float, const QString &symbol = QString()) const; + QString toCurrencyString(double, const QString &symbol, int precision) const; + inline QString toCurrencyString(float i, const QString &symbol = QString()) const + { return toCurrencyString(double(i), symbol); } + inline QString toCurrencyString(float i, const QString &symbol, int precision) const + { return toCurrencyString(double(i), symbol, precision); } +#endif QStringList uiLanguages() const; @@ -994,7 +1008,7 @@ private: QSharedDataPointer<QLocalePrivate> d; }; -Q_DECLARE_TYPEINFO(QLocale, Q_MOVABLE_TYPE); +Q_DECLARE_SHARED(QLocale) Q_DECLARE_OPERATORS_FOR_FLAGS(QLocale::NumberOptions) inline QString QLocale::toString(short i) const @@ -1016,8 +1030,6 @@ inline QString QLocale::toCurrencyString(int i, const QString &symbol) const { return toCurrencyString(qlonglong(i), symbol); } inline QString QLocale::toCurrencyString(uint i, const QString &symbol) const { return toCurrencyString(qulonglong(i), symbol); } -inline QString QLocale::toCurrencyString(float i, const QString &symbol) const -{ return toCurrencyString(double(i), symbol); } #ifndef QT_NO_DATASTREAM Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, const QLocale &); diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index 96c4f9acb6..a03007f606 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -135,7 +135,7 @@ private: QList<QByteArray> buffers; int head, tail; int tailBuffer; // always buffers.size() - 1 - const int basicBlockSize; + int basicBlockSize; qint64 bufferSize; }; diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index f030a3ff8c..c126e3636e 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -138,7 +138,6 @@ public: inline ObjectTreeNode() : obj(0), flags(0) { } inline ObjectTreeNode(const QString &n) // intentionally implicit : name(n), obj(0), flags(0) { } - inline ~ObjectTreeNode() { } inline bool operator<(const QString &other) const { return name < other; } inline bool operator<(const QStringRef &other) const diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index 678ce2a97c..bae1c04054 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -427,9 +427,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) int data_size = idata.size() + (header->methodCount * (5+intsPerMethod)) + methodParametersDataSize + (header->propertyCount * (3+intsPerProperty)); - foreach (const Method &mm, signals_) + for (const Method &mm : qAsConst(signals_)) data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count(); - foreach (const Method &mm, methods) + for (const Method &mm : qAsConst(methods)) data_size += 2 + mm.inputTypes.count() + mm.outputTypes.count(); idata.resize(data_size + 1); diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index babb270da0..6b5166508f 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -99,9 +99,8 @@ QDBusServer::~QDBusServer() { if (QDBusConnectionManager::instance()) { QMutexLocker locker(&QDBusConnectionManager::instance()->mutex); - Q_FOREACH (const QString &name, d->serverConnectionNames) { + for (const QString &name : qAsConst(d->serverConnectionNames)) QDBusConnectionManager::instance()->removeConnection(name); - } d->serverConnectionNames.clear(); } d->ref.store(0); diff --git a/src/dbus/qdbusservicewatcher.cpp b/src/dbus/qdbusservicewatcher.cpp index 72c1a12f2c..eb90b149c8 100644 --- a/src/dbus/qdbusservicewatcher.cpp +++ b/src/dbus/qdbusservicewatcher.cpp @@ -78,7 +78,7 @@ void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBus { if (connection.isConnected()) { // remove older rules - foreach (const QString &s, servicesWatched) + for (const QString &s : qAsConst(servicesWatched)) removeService(s); } @@ -88,7 +88,7 @@ void QDBusServiceWatcherPrivate::setConnection(const QStringList &s, const QDBus if (connection.isConnected()) { // add new rules - foreach (const QString &s, servicesWatched) + for (const QString &s : qAsConst(servicesWatched)) addService(s); } } diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 371b7b184e..04e805d173 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -77,8 +77,8 @@ static bool variantToString(const QVariant &arg, QString &out) if (argType == QVariant::StringList) { out += QLatin1Char('{'); - QStringList list = arg.toStringList(); - foreach (const QString &item, list) + const QStringList list = arg.toStringList(); + for (const QString &item : list) out += QLatin1Char('\"') + item + QLatin1String("\", "); if (!list.isEmpty()) out.chop(2); @@ -95,8 +95,8 @@ static bool variantToString(const QVariant &arg, QString &out) out += QLatin1Char('}'); } else if (argType == QVariant::List) { out += QLatin1Char('{'); - QList<QVariant> list = arg.toList(); - foreach (const QVariant &item, list) { + const QList<QVariant> list = arg.toList(); + for (const QVariant &item : list) { if (!variantToString(item, out)) return false; out += QLatin1String(", "); diff --git a/src/gui/painting/qcolor.cpp b/src/gui/painting/qcolor.cpp index 3f30c061dc..1f92c8b145 100644 --- a/src/gui/painting/qcolor.cpp +++ b/src/gui/painting/qcolor.cpp @@ -2415,8 +2415,7 @@ bool QColor::operator==(const QColor &color) const { if (cspec == Hsl && cspec == color.cspec) { return (ct.argb.alpha == color.ct.argb.alpha - && ((((ct.ahsl.hue % 36000) == (color.ct.ahsl.hue % 36000))) - || (ct.ahsl.hue == color.ct.ahsl.hue)) + && ct.ahsl.hue % 36000 == color.ct.ahsl.hue % 36000 && (qAbs(ct.ahsl.saturation - color.ct.ahsl.saturation) < 50 || ct.ahsl.lightness == 0 || color.ct.ahsl.lightness == 0 diff --git a/src/gui/text/qstatictext.cpp b/src/gui/text/qstatictext.cpp index 74f4b10305..62c24797dc 100644 --- a/src/gui/text/qstatictext.cpp +++ b/src/gui/text/qstatictext.cpp @@ -700,25 +700,4 @@ void QStaticTextPrivate::init() needsRelayout = false; } -QStaticTextItem::~QStaticTextItem() -{ - if (m_userData != 0 && !m_userData->ref.deref()) - delete m_userData; - setFontEngine(0); -} - -void QStaticTextItem::setFontEngine(QFontEngine *fe) -{ - if (m_fontEngine == fe) - return; - - if (m_fontEngine != 0 && !m_fontEngine->ref.deref()) - delete m_fontEngine; - - m_fontEngine = fe; - - if (m_fontEngine != 0) - m_fontEngine->ref.ref(); -} - QT_END_NAMESPACE diff --git a/src/gui/text/qstatictext_p.h b/src/gui/text/qstatictext_p.h index 49ca24d51c..e654b8329d 100644 --- a/src/gui/text/qstatictext_p.h +++ b/src/gui/text/qstatictext_p.h @@ -75,46 +75,18 @@ public: userDataNeedsUpdate(0), usesRawFont(0), m_fontEngine(0), m_userData(0) {} - QStaticTextItem(const QStaticTextItem &other) - { - operator=(other); - } - - void operator=(const QStaticTextItem &other) + void setUserData(QStaticTextUserData *newUserData) { - glyphPositions = other.glyphPositions; - glyphs = other.glyphs; - numGlyphs = other.numGlyphs; - font = other.font; - color = other.color; - useBackendOptimizations = other.useBackendOptimizations; - userDataNeedsUpdate = other.userDataNeedsUpdate; - usesRawFont = other.usesRawFont; - - m_fontEngine = 0; - m_userData = 0; - setUserData(other.userData()); - setFontEngine(other.fontEngine()); + m_userData = newUserData; } + QStaticTextUserData *userData() const { return m_userData.data(); } - ~QStaticTextItem(); - - void setUserData(QStaticTextUserData *newUserData) + void setFontEngine(QFontEngine *fe) { - if (m_userData == newUserData) - return; - - if (m_userData != 0 && !m_userData->ref.deref()) - delete m_userData; - - m_userData = newUserData; - if (m_userData != 0) - m_userData->ref.ref(); + m_fontEngine = fe; } - QStaticTextUserData *userData() const { return m_userData; } - void setFontEngine(QFontEngine *fe); - QFontEngine *fontEngine() const { return m_fontEngine; } + QFontEngine *fontEngine() const { return m_fontEngine.data(); } union { QFixedPoint *glyphPositions; // 8 bytes per glyph @@ -135,11 +107,11 @@ public: char userDataNeedsUpdate : 1; // char usesRawFont : 1; // -private: // Needs special handling in setters, so private to avoid abuse - QFontEngine *m_fontEngine; // 4 bytes per item - QStaticTextUserData *m_userData; // 8 bytes per item - // ================ - // 43 bytes per item +private: // private to avoid abuse + QExplicitlySharedDataPointer<QFontEngine> m_fontEngine; // 4 bytes per item + QExplicitlySharedDataPointer<QStaticTextUserData> m_userData; // 8 bytes per item + // ================ + // 43 bytes per item }; class QStaticText; diff --git a/src/network/bearer/qnetworkconfigmanager_p.cpp b/src/network/bearer/qnetworkconfigmanager_p.cpp index 9c761f9479..4e74595909 100644 --- a/src/network/bearer/qnetworkconfigmanager_p.cpp +++ b/src/network/bearer/qnetworkconfigmanager_p.cpp @@ -51,11 +51,6 @@ QT_BEGIN_NAMESPACE -#ifndef QT_NO_LIBRARY -Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, - (QBearerEngineFactoryInterface_iid, QLatin1String("/bearer"))) -#endif - QNetworkConfigurationManagerPrivate::QNetworkConfigurationManagerPrivate() : QObject(), pollTimer(0), mutex(QMutex::Recursive), forcedPolling(0), firstUpdate(true) { @@ -382,7 +377,8 @@ void QNetworkConfigurationManagerPrivate::updateConfigurations() bool envOK = false; const int skipGeneric = qEnvironmentVariableIntValue("QT_EXCLUDE_GENERIC_BEARER", &envOK); QBearerEngine *generic = 0; - QFactoryLoader *l = loader(); + static QFactoryLoader loader(QBearerEngineFactoryInterface_iid, QLatin1String("/bearer")); + QFactoryLoader *l = &loader; const PluginKeyMap keyMap = l->keyMap(); const PluginKeyMapConstIterator cend = keyMap.constEnd(); QStringList addedEngines; diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 6110131484..7b42f3eb14 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -2479,22 +2479,25 @@ qint64 QAbstractSocket::writeData(const char *data, qint64 size) qint64 written = d->socketEngine->write(data, size); if (written < 0) { d->setError(d->socketEngine->error(), d->socketEngine->errorString()); - return written; } else if (written < size) { // Buffer what was not written yet char *ptr = d->writeBuffer.reserve(size - written); memcpy(ptr, data + written, size - written); + written = size; d->socketEngine->setWriteNotificationEnabled(true); } - return size; // size=actually written + what has been buffered + +#if defined (QABSTRACTSOCKET_DEBUG) + qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data, + qt_prettyDebug(data, qMin((int)size, 32), size).data(), + size, written); +#endif + return written; // written = actually written + what has been buffered } else if (!d->isBuffered && d->socketType != TcpSocket) { // This is for a QUdpSocket that was connect()ed qint64 written = d->socketEngine->write(data, size); - if (written < 0) { + if (written < 0) d->setError(d->socketEngine->error(), d->socketEngine->errorString()); - } else if (!d->writeBuffer.isEmpty()) { - d->socketEngine->setWriteNotificationEnabled(true); - } #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocket::writeData(%p \"%s\", %lli) == %lli", data, diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 1dfd87a0f8..6f3ed58e18 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2531,7 +2531,7 @@ qint64 QSslSocketPrivate::peek(char *data, qint64 maxSize) if (mode == QSslSocket::UnencryptedMode && !autoStartHandshake) { //unencrypted mode - do not use QIODevice::peek, as it reads ahead data from the plain socket //peek at data already in the QIODevice buffer (from a previous read) - qint64 r = buffer.peek(data, maxSize); + qint64 r = buffer.peek(data, maxSize, transactionPos); if (r == maxSize) return r; data += r; @@ -2560,7 +2560,7 @@ QByteArray QSslSocketPrivate::peek(qint64 maxSize) //peek at data already in the QIODevice buffer (from a previous read) QByteArray ret; ret.reserve(maxSize); - ret.resize(buffer.peek(ret.data(), maxSize)); + ret.resize(buffer.peek(ret.data(), maxSize, transactionPos)); if (ret.length() == maxSize) return ret; //peek at data in the plain socket diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp index 726d1972f1..0cdf9918ab 100644 --- a/src/tools/moc/moc.cpp +++ b/src/tools/moc/moc.cpp @@ -1444,7 +1444,7 @@ bool Moc::until(Token target) { case LPAREN: ++parenCount; break; case RPAREN: --parenCount; break; case LANGLE: - if (parenCount == 0 && braceCount == 0 && parenCount == 0) + if (parenCount == 0 && braceCount == 0) ++angleCount; break; case RANGLE: diff --git a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp index 334f5aba05..9271630b32 100644 --- a/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp +++ b/tests/auto/corelib/io/qiodevice/tst_qiodevice.cpp @@ -57,9 +57,11 @@ private slots: void readLine2_data(); void readLine2(); - void peekBug(); void readAllKeepPosition(); void writeInTextMode(); + + void transaction_data(); + void transaction(); }; void tst_QIODevice::initTestCase() @@ -528,77 +530,23 @@ void tst_QIODevice::readLine2() } } - -class PeekBug : public QIODevice { - Q_OBJECT -public: - char alphabet[27]; - qint64 counter; - PeekBug() : QIODevice(), counter(0) { - memcpy(alphabet,"abcdefghijklmnopqrstuvqxyz",27); - }; - qint64 readData(char *data, qint64 maxlen) { - qint64 pos = 0; - while (pos < maxlen) { - *(data + pos) = alphabet[counter]; - pos++; - counter++; - if (counter == 26) - counter = 0; - } - return maxlen; - } - qint64 writeData(const char * /* data */, qint64 /* maxlen */) { - return -1; - } - -}; - -// This is a regression test for an old bug where peeking at -// more than one character failed to put them back. -void tst_QIODevice::peekBug() -{ - PeekBug peekBug; - peekBug.open(QIODevice::ReadOnly | QIODevice::Unbuffered); - - char onetwo[2]; - peekBug.peek(onetwo, 2); - QCOMPARE(onetwo[0], 'a'); - QCOMPARE(onetwo[1], 'b'); - - peekBug.read(onetwo, 1); - QCOMPARE(onetwo[0], 'a'); - - peekBug.peek(onetwo, 2); - QCOMPARE(onetwo[0], 'b'); - QCOMPARE(onetwo[1], 'c'); - - peekBug.read(onetwo, 1); - QCOMPARE(onetwo[0], 'b'); - peekBug.read(onetwo, 1); - QCOMPARE(onetwo[0], 'c'); - peekBug.read(onetwo, 1); - QCOMPARE(onetwo[0], 'd'); - - peekBug.peek(onetwo, 2); - QCOMPARE(onetwo[0], 'e'); - QCOMPARE(onetwo[1], 'f'); - -} - class SequentialReadBuffer : public QIODevice { public: - SequentialReadBuffer(const char *data) : QIODevice(), buf(data), offset(0) { } + SequentialReadBuffer(const char *data) + : QIODevice(), buf(new QByteArray(data)), offset(0), ownbuf(true) { } + SequentialReadBuffer(QByteArray *byteArray) + : QIODevice(), buf(byteArray), offset(0), ownbuf(false) { } + virtual ~SequentialReadBuffer() { if (ownbuf) delete buf; } bool isSequential() const Q_DECL_OVERRIDE { return true; } - const QByteArray &buffer() const { return buf; } + const QByteArray &buffer() const { return *buf; } protected: qint64 readData(char *data, qint64 maxSize) Q_DECL_OVERRIDE { - maxSize = qMin(maxSize, qint64(buf.size() - offset)); - memcpy(data, buf.constData() + offset, maxSize); + maxSize = qMin(maxSize, qint64(buf->size() - offset)); + memcpy(data, buf->constData() + offset, maxSize); offset += maxSize; return maxSize; } @@ -608,8 +556,9 @@ protected: } private: - QByteArray buf; + QByteArray *buf; int offset; + bool ownbuf; }; // Test readAll() on position change for sequential device @@ -669,5 +618,117 @@ void tst_QIODevice::writeInTextMode() #endif } +void tst_QIODevice::transaction_data() +{ + QTest::addColumn<bool>("sequential"); + QTest::addColumn<qint8>("i8Data"); + QTest::addColumn<qint16>("i16Data"); + QTest::addColumn<qint32>("i32Data"); + QTest::addColumn<qint64>("i64Data"); + QTest::addColumn<bool>("bData"); + QTest::addColumn<float>("fData"); + QTest::addColumn<double>("dData"); + QTest::addColumn<QByteArray>("strData"); + + bool sequential = true; + do { + QByteArray devName(sequential ? "sequential" : "random-access"); + + QTest::newRow(qPrintable(devName + '1')) << sequential << qint8(1) << qint16(2) + << qint32(3) << qint64(4) << true + << 5.0f << double(6.0) + << QByteArray("Hello world!"); + QTest::newRow(qPrintable(devName + '2')) << sequential << qint8(1 << 6) << qint16(1 << 14) + << qint32(1 << 30) << (qint64(1) << 62) << false + << 123.0f << double(234.0) + << QByteArray("abcdefghijklmnopqrstuvwxyz"); + QTest::newRow(qPrintable(devName + '3')) << sequential << qint8(-1) << qint16(-2) + << qint32(-3) << qint64(-4) << true + << -123.0f << double(-234.0) + << QByteArray("Qt rocks!"); + sequential = !sequential; + } while (!sequential); +} + +// Test transaction integrity +void tst_QIODevice::transaction() +{ + QByteArray testBuffer; + + QFETCH(bool, sequential); + QFETCH(qint8, i8Data); + QFETCH(qint16, i16Data); + QFETCH(qint32, i32Data); + QFETCH(qint64, i64Data); + QFETCH(bool, bData); + QFETCH(float, fData); + QFETCH(double, dData); + QFETCH(QByteArray, strData); + + { + QDataStream stream(&testBuffer, QIODevice::WriteOnly); + + stream << i8Data << i16Data << i32Data << i64Data + << bData << fData << dData << strData.constData(); + } + + for (int splitPos = 0; splitPos <= testBuffer.size(); ++splitPos) { + QByteArray readBuffer(testBuffer.left(splitPos)); + QIODevice *dev = sequential ? (QIODevice *) new SequentialReadBuffer(&readBuffer) + : (QIODevice *) new QBuffer(&readBuffer); + dev->open(QIODevice::ReadOnly); + QDataStream stream(dev); + + qint8 i8; + qint16 i16; + qint32 i32; + qint64 i64; + bool b; + float f; + double d; + char *str; + + forever { + QVERIFY(!dev->isTransactionStarted()); + dev->startTransaction(); + QVERIFY(dev->isTransactionStarted()); + + // Try to read all data in one go. If the status of the data stream + // indicates an unsuccessful operation, restart a read transaction + // on the completed buffer. + stream >> i8 >> i16 >> i32 >> i64 >> b >> f >> d >> str; + + QVERIFY(stream.atEnd()); + if (stream.status() == QDataStream::Ok) { + dev->commitTransaction(); + break; + } + + dev->rollbackTransaction(); + QVERIFY(splitPos == 0 || !stream.atEnd()); + QCOMPARE(dev->pos(), Q_INT64_C(0)); + QCOMPARE(dev->bytesAvailable(), qint64(readBuffer.size())); + QVERIFY(readBuffer.size() < testBuffer.size()); + delete [] str; + readBuffer.append(testBuffer.right(testBuffer.size() - splitPos)); + stream.resetStatus(); + } + + QVERIFY(!dev->isTransactionStarted()); + QVERIFY(stream.atEnd()); + QCOMPARE(i8, i8Data); + QCOMPARE(i16, i16Data); + QCOMPARE(i32, i32Data); + QCOMPARE(i64, i64Data); + QCOMPARE(b, bData); + QCOMPARE(f, fData); + QCOMPARE(d, dData); + QVERIFY(strData == str); + delete [] str; + stream.setDevice(0); + delete dev; + } +} + QTEST_MAIN(tst_QIODevice) #include "tst_qiodevice.moc" diff --git a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp index 51f691b1a4..f8058f2240 100644 --- a/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp +++ b/tests/auto/corelib/tools/qlocale/tst_qlocale.cpp @@ -2187,12 +2187,18 @@ void tst_QLocale::currency() QCOMPARE(c.toCurrencyString(qlonglong(-1234)), QString("-1234")); QCOMPARE(c.toCurrencyString(double(1234.56)), QString("1234.56")); QCOMPARE(c.toCurrencyString(double(-1234.56)), QString("-1234.56")); + QCOMPARE(c.toCurrencyString(double(-1234.5678)), QString("-1234.57")); + QCOMPARE(c.toCurrencyString(double(-1234.5678), NULL, 4), QString("-1234.5678")); + QCOMPARE(c.toCurrencyString(double(-1234.56), NULL, 4), QString("-1234.5600")); const QLocale en_US("en_US"); QCOMPARE(en_US.toCurrencyString(qulonglong(1234)), QString("$1,234")); QCOMPARE(en_US.toCurrencyString(qlonglong(-1234)), QString("$-1,234")); QCOMPARE(en_US.toCurrencyString(double(1234.56)), QString("$1,234.56")); QCOMPARE(en_US.toCurrencyString(double(-1234.56)), QString("$-1,234.56")); + QCOMPARE(en_US.toCurrencyString(double(-1234.5678)), QString("$-1,234.57")); + QCOMPARE(en_US.toCurrencyString(double(-1234.5678), NULL, 4), QString("$-1,234.5678")); + QCOMPARE(en_US.toCurrencyString(double(-1234.56), NULL, 4), QString("$-1,234.5600")); const QLocale ru_RU("ru_RU"); QCOMPARE(ru_RU.toCurrencyString(qulonglong(1234)), QString::fromUtf8("1" "\xc2\xa0" "234\xc2\xa0\xd1\x80\xd1\x83\xd0\xb1.")); diff --git a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp index b77fe23bd6..9cc66cd5e2 100644 --- a/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp +++ b/tests/auto/corelib/tools/qringbuffer/tst_qringbuffer.cpp @@ -34,12 +34,14 @@ #include <QtTest/QtTest> #include <private/qringbuffer_p.h> +#include <qvector.h> class tst_QRingBuffer : public QObject { Q_OBJECT private slots: void constructing(); + void usingInVector(); void readPointerAtPositionWriteRead(); void readPointerAtPositionEmptyRead(); void readPointerAtPositionWithHead(); @@ -74,6 +76,16 @@ void tst_QRingBuffer::constructing() QCOMPARE(ringBuffer.peek(buf, sizeof(buf)), Q_INT64_C(0)); } +void tst_QRingBuffer::usingInVector() +{ + QRingBuffer ringBuffer; + QVector<QRingBuffer> buffers; + + ringBuffer.reserve(5); + buffers.append(ringBuffer); + QCOMPARE(buffers[0].size(), Q_INT64_C(5)); +} + void tst_QRingBuffer::sizeWhenReserved() { QRingBuffer ringBuffer; diff --git a/tests/auto/other/toolsupport/tst_toolsupport.cpp b/tests/auto/other/toolsupport/tst_toolsupport.cpp index 7942a84615..93cbb2809d 100644 --- a/tests/auto/other/toolsupport/tst_toolsupport.cpp +++ b/tests/auto/other/toolsupport/tst_toolsupport.cpp @@ -124,7 +124,7 @@ void tst_toolsupport::offsets_data() { QTestData &data = QTest::newRow("QFilePrivate::fileName") << pmm_to_offsetof(&QFilePrivate::fileName); - data << 168 << 248; + data << 184 << 256; } #endif |