diff options
Diffstat (limited to 'src/corelib')
36 files changed, 1171 insertions, 668 deletions
diff --git a/src/corelib/doc/snippets/qstring/main.cpp b/src/corelib/doc/snippets/qstring/main.cpp index bf45a31c29..f5c6b69695 100644 --- a/src/corelib/doc/snippets/qstring/main.cpp +++ b/src/corelib/doc/snippets/qstring/main.cpp @@ -394,6 +394,13 @@ void Widget::firstIndexOfFunction() QString str = "the minimum"; str.indexOf(QRegularExpression("m[aeiou]"), 0); // returns 4 //! [93] + + //! [97] + QString str = "the minimum"; + QRegularExpressionMatch match; + str.indexOf(QRegularExpression("m[aeiou]"), 0, &match); // returns 4 + // match.captured() == mi + //! [97] } void Widget::insertFunction() @@ -444,6 +451,13 @@ void Widget::lastIndexOfFunction() QString str = "the minimum"; str.lastIndexOf(QRegularExpression("m[aeiou]")); // returns 8 //! [94] + + //! [98] + QString str = "the minimum"; + QRegularExpressionMatch match; + str.lastIndexOf(QRegularExpression("m[aeiou]"), -1, &match); // returns 8 + // match.captured() == mu + //! [98] } void Widget::leftFunction() diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 2696df9e39..e86d986581 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -39,6 +39,7 @@ #include "qthreadstorage.h" #include "qdir.h" #include "qdatetime.h" +#include <private/qlocale_tools_p.h> #ifndef QT_NO_QOBJECT #include <private/qthread_p.h> @@ -1845,16 +1846,14 @@ Q_CORE_EXPORT QString qt_mac_from_pascal_string(const Str255 pstr) { QSysInfo::MacVersion QSysInfo::macVersion() { + const QAppleOperatingSystemVersion version = qt_apple_os_version(); // qtcore_mac_objc.mm #if defined(Q_OS_OSX) - SInt32 gestalt_version; - if (Gestalt(gestaltSystemVersionMinor, &gestalt_version) == noErr) { - // add 2 because OS X 10.0 is 0x02 in the enum - return QSysInfo::MacVersion(gestalt_version + 2); - } + return QSysInfo::MacVersion(Q_MV_OSX(version.major, version.minor)); #elif defined(Q_OS_IOS) - return qt_ios_version(); // qtcore_mac_objc.mm -#endif + return QSysInfo::MacVersion(Q_MV_IOS(version.major, version.minor)); +#else return QSysInfo::MV_Unknown; +#endif } const QSysInfo::MacVersion QSysInfo::MacintoshVersion = QSysInfo::macVersion(); @@ -2493,25 +2492,9 @@ QString QSysInfo::productType() */ QString QSysInfo::productVersion() { -#if defined(Q_OS_IOS) - int major = (int(MacintoshVersion) >> 4) & 0xf; - int minor = int(MacintoshVersion) & 0xf; - if (Q_LIKELY(major < 10 && minor < 10)) { - char buf[4] = { char(major + '0'), '.', char(minor + '0'), '\0' }; - return QString::fromLatin1(buf, 3); - } - return QString::number(major) + QLatin1Char('.') + QString::number(minor); -#elif defined(Q_OS_OSX) - int minor = int(MacintoshVersion) - 2; // we're not running on Mac OS 9 - Q_ASSERT(minor < 100); - char buf[] = "10.0\0"; - if (Q_LIKELY(minor < 10)) { - buf[3] += minor; - } else { - buf[3] += minor / 10; - buf[4] = '0' + minor % 10; - } - return QString::fromLatin1(buf); +#if defined(Q_OS_MAC) + const QAppleOperatingSystemVersion version = qt_apple_os_version(); + return QString::number(version.major) + QLatin1Char('.') + QString::number(version.minor); #elif defined(Q_OS_WIN) const char *version = winVer_helper(); if (version) @@ -3005,6 +2988,53 @@ bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT /*! \relates <QtGlobal> + \since 5.5 + + Returns the numerical value of the environment variable \a varName. + If \a ok is not null, sets \c{*ok} to \c true or \c false depending + on the success of the conversion. + + Equivalent to + \code + qgetenv(varName).toInt() + \endcode + except that it's much faster, and can't throw exceptions. + + \sa qgetenv(), qEnvironmentVariableIsSet() +*/ +int qEnvironmentVariableIntValue(const char *varName, bool *ok) Q_DECL_NOEXCEPT +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + // we provide a buffer that can hold any int value: + static const int NumBinaryDigitsPerOctalDigit = 3; + static const int MaxDigitsForOctalInt = + (std::numeric_limits<uint>::digits + NumBinaryDigitsPerOctalDigit - 1) / NumBinaryDigitsPerOctalDigit; + char buffer[MaxDigitsForOctalInt + 2]; // +1 for NUL +1 for optional '-' + size_t dummy; + if (getenv_s(&dummy, buffer, sizeof buffer, varName) != 0) { + if (ok) + *ok = false; + return 0; + } +#else + const char * const buffer = ::getenv(varName); + if (!buffer || !*buffer) { + if (ok) + *ok = false; + return 0; + } +#endif + const qlonglong value = qstrtoll(buffer, Q_NULLPTR, 0, ok); + if (int(value) != value) { // this is the check in QByteArray::toInt(), keep it in sync + if (ok) + *ok = false; + return 0; + } + return int(value); +} + +/*! + \relates <QtGlobal> \since 5.1 Returns whether the environment variable \a varName is set. diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 8bc489e509..928bf13835 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -37,11 +37,11 @@ #include <stddef.h> -#define QT_VERSION_STR "5.4.0" +#define QT_VERSION_STR "5.5.0" /* QT_VERSION is (major << 16) + (minor << 8) + patch. */ -#define QT_VERSION 0x050400 +#define QT_VERSION 0x050500 /* can be used like #if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) */ @@ -1027,6 +1027,7 @@ Q_CORE_EXPORT bool qunsetenv(const char *varName); Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) Q_DECL_NOEXCEPT; Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) Q_DECL_NOEXCEPT; +Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=0) Q_DECL_NOEXCEPT; inline int qIntCast(double f) { return int(f); } inline int qIntCast(float f) { return int(f); } diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h index 277caa8db6..2ac18f2ed8 100644 --- a/src/corelib/global/qsysinfo.h +++ b/src/corelib/global/qsysinfo.h @@ -112,6 +112,7 @@ public: #endif #ifdef Q_OS_MAC +# define Q_MV_OSX(major, minor) (major == 10 ? minor + 2 : (major == 9 ? 1 : 0)) # define Q_MV_IOS(major, minor) (QSysInfo::MV_IOS | major << 4 | minor) enum MacVersion { MV_Unknown = 0x0000, diff --git a/src/corelib/io/qdatastream.cpp b/src/corelib/io/qdatastream.cpp index 49526ea2d5..8d757a7773 100644 --- a/src/corelib/io/qdatastream.cpp +++ b/src/corelib/io/qdatastream.cpp @@ -531,6 +531,7 @@ void QDataStream::setByteOrder(ByteOrder bo) \value Qt_5_2 Version 15 (Qt 5.2) \value Qt_5_3 Same as Qt_5_2 \value Qt_5_4 Version 16 (Qt 5.4) + \value Qt_5_5 Same as Qt_5_4 \omitvalue Qt_DefaultCompiledVersion \sa setVersion(), version() diff --git a/src/corelib/io/qdatastream.h b/src/corelib/io/qdatastream.h index 75ffa11543..8e1d777011 100644 --- a/src/corelib/io/qdatastream.h +++ b/src/corelib/io/qdatastream.h @@ -82,10 +82,11 @@ public: Qt_5_2 = 15, Qt_5_3 = Qt_5_2, Qt_5_4 = 16, -#if QT_VERSION >= 0x050500 + Qt_5_5 = Qt_5_4, +#if QT_VERSION >= 0x050600 #error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion #endif - Qt_DefaultCompiledVersion = Qt_5_4 + Qt_DefaultCompiledVersion = Qt_5_5 }; enum ByteOrder { diff --git a/src/corelib/io/qfileselector.cpp b/src/corelib/io/qfileselector.cpp index 5d1d5dfe23..95fa970b2d 100644 --- a/src/corelib/io/qfileselector.cpp +++ b/src/corelib/io/qfileselector.cpp @@ -335,7 +335,7 @@ void QFileSelectorPrivate::updateSelectors() if (envSelectors.count()) sharedData->staticSelectors << envSelectors; - if (!qgetenv(env_override).isEmpty()) + if (!qEnvironmentVariableIsEmpty(env_override)) return; sharedData->staticSelectors << sharedData->preloadedStatics; //Potential for static selectors from other modules diff --git a/src/corelib/io/qiodevice.cpp b/src/corelib/io/qiodevice.cpp index 89209e6118..0896432837 100644 --- a/src/corelib/io/qiodevice.cpp +++ b/src/corelib/io/qiodevice.cpp @@ -783,27 +783,20 @@ qint64 QIODevice::read(char *data, qint64 maxSize) CHECK_MAXLEN(read, qint64(-1)); qint64 readSoFar = 0; - bool moreToRead = true; - do { + bool madeBufferReadsOnly = true; + bool deviceAtEof = false; + char *readPtr = data; + forever { // Try reading from the buffer. - int lastReadChunkSize = d->buffer.read(data, maxSize); - if (lastReadChunkSize > 0) { - *d->pPos += lastReadChunkSize; - readSoFar += lastReadChunkSize; - // fast exit when satisfied by buffer - if (lastReadChunkSize == maxSize && !(d->openMode & Text)) { - if (d->buffer.isEmpty()) { - d->buffer.clear(); - readData(data, 0); - } - return readSoFar; - } - - data += lastReadChunkSize; - maxSize -= lastReadChunkSize; + int bufferReadChunkSize = d->buffer.read(data, maxSize); + if (bufferReadChunkSize > 0) { + *d->pPos += bufferReadChunkSize; + readSoFar += bufferReadChunkSize; + data += bufferReadChunkSize; + maxSize -= bufferReadChunkSize; #if defined QIODEVICE_DEBUG - printf("%p \treading %d bytes from buffer into position %d\n", this, lastReadChunkSize, - int(readSoFar) - lastReadChunkSize); + printf("%p \treading %d bytes from buffer into position %d\n", this, + bufferReadChunkSize, int(readSoFar) - bufferReadChunkSize); #endif } else { if (d->firstRead) { @@ -816,100 +809,84 @@ qint64 QIODevice::read(char *data, qint64 maxSize) d->pDevicePos = &d->seqDumpPos; } } + } - if (!maxSize) - return readSoFar; - - if ((d->openMode & Unbuffered) == 0 && maxSize < QIODEVICE_BUFFERSIZE) { - // In buffered mode, we try to fill up the QIODevice buffer before - // we do anything else. - // buffer is empty at this point, try to fill it - const int bytesToBuffer = QIODEVICE_BUFFERSIZE; - char *writePointer = d->buffer.reserve(bytesToBuffer); - - // Make sure the device is positioned correctly. - if (d->pos != d->devicePos && !d->isSequential() && !seek(d->pos)) - return readSoFar ? readSoFar : qint64(-1); - qint64 readFromDevice = readData(writePointer, bytesToBuffer); - d->buffer.chop(bytesToBuffer - (readFromDevice < 0 ? 0 : int(readFromDevice))); - - if (readFromDevice > 0) { - *d->pDevicePos += readFromDevice; + if (maxSize > 0 && !deviceAtEof) { + qint64 readFromDevice = 0; + // Make sure the device is positioned correctly. + if (d->pos == d->devicePos || d->isSequential() || seek(d->pos)) { + madeBufferReadsOnly = false; // fix readData attempt + if (maxSize >= QIODEVICE_BUFFERSIZE || (d->openMode & Unbuffered)) { + // Read big chunk directly to output buffer + readFromDevice = readData(data, maxSize); + deviceAtEof = (readFromDevice != maxSize); #if defined QIODEVICE_DEBUG - printf("%p \treading %d from device into buffer\n", this, int(readFromDevice)); + printf("%p \treading %d bytes from device (total %d)\n", this, + int(readFromDevice), int(readSoFar)); #endif - - if (!d->buffer.isEmpty()) { - lastReadChunkSize = d->buffer.read(data, maxSize); - readSoFar += lastReadChunkSize; - data += lastReadChunkSize; - maxSize -= lastReadChunkSize; - *d->pPos += lastReadChunkSize; + if (readFromDevice > 0) { + readSoFar += readFromDevice; + data += readFromDevice; + maxSize -= readFromDevice; + *d->pPos += readFromDevice; + *d->pDevicePos += readFromDevice; + } + } else { + const int bytesToBuffer = QIODEVICE_BUFFERSIZE; + // Try to fill QIODevice buffer by single read + readFromDevice = readData(d->buffer.reserve(bytesToBuffer), bytesToBuffer); + deviceAtEof = (readFromDevice != bytesToBuffer); + d->buffer.chop(bytesToBuffer - qMax(0, int(readFromDevice))); + if (readFromDevice > 0) { + *d->pDevicePos += readFromDevice; #if defined QIODEVICE_DEBUG - printf("%p \treading %d bytes from buffer at position %d\n", this, - lastReadChunkSize, int(readSoFar)); + printf("%p \treading %d from device into buffer\n", this, + int(readFromDevice)); #endif + continue; } } + } else { + readFromDevice = -1; } - } - // If we need more, try reading from the device. - if (maxSize > 0) { - // Make sure the device is positioned correctly. - if (d->pos != d->devicePos && !d->isSequential() && !seek(d->pos)) - return readSoFar ? readSoFar : qint64(-1); - qint64 readFromDevice = readData(data, maxSize); -#if defined QIODEVICE_DEBUG - printf("%p \treading %d bytes from device (total %d)\n", this, int(readFromDevice), int(readSoFar)); -#endif - if (readFromDevice == -1 && readSoFar == 0) { + if (readFromDevice < 0 && readSoFar == 0) { // error and we haven't read anything: return immediately - return -1; - } - if (readFromDevice > 0) { - lastReadChunkSize += int(readFromDevice); - readSoFar += readFromDevice; - data += readFromDevice; - maxSize -= readFromDevice; - *d->pPos += readFromDevice; - *d->pDevicePos += readFromDevice; + return qint64(-1); } } - // Best attempt has been made to read data, don't try again except for text mode adjustment below - moreToRead = false; - if (readSoFar && d->openMode & Text) { - char *readPtr = data - lastReadChunkSize; + if ((d->openMode & Text) && readPtr < data) { const char *endPtr = data; - if (readPtr < endPtr) { - // optimization to avoid initial self-assignment - while (*readPtr != '\r') { - if (++readPtr == endPtr) - return readSoFar; - } + // optimization to avoid initial self-assignment + while (*readPtr != '\r') { + if (++readPtr == endPtr) + break; + } - char *writePtr = readPtr; + char *writePtr = readPtr; - while (readPtr < endPtr) { - char ch = *readPtr++; - if (ch != '\r') - *writePtr++ = ch; - else { - --readSoFar; - --data; - ++maxSize; - } + while (readPtr < endPtr) { + char ch = *readPtr++; + if (ch != '\r') + *writePtr++ = ch; + else { + --readSoFar; + --data; + ++maxSize; } - - // Make sure we get more data if there is room for more. This - // is very important for when someone seeks to the start of a - // '\r\n' and reads one character - they should get the '\n'. - moreToRead = (readPtr != writePtr); } + + // Make sure we get more data if there is room for more. This + // is very important for when someone seeks to the start of a + // '\r\n' and reads one character - they should get the '\n'. + readPtr = data; + continue; } - } while (moreToRead); + + break; + } #if defined QIODEVICE_DEBUG printf("%p \treturning %d, d->pos == %d, d->buffer.size() == %d\n", this, @@ -917,8 +894,10 @@ qint64 QIODevice::read(char *data, qint64 maxSize) debugBinaryString(data - readSoFar, readSoFar); #endif - if (d->buffer.isEmpty()) + if (madeBufferReadsOnly && d->buffer.isEmpty()) { + d->buffer.clear(); readData(data, 0); + } return readSoFar; } diff --git a/src/corelib/io/qresource.cpp b/src/corelib/io/qresource.cpp index ed6bfb4e0d..9eca0ab8dc 100644 --- a/src/corelib/io/qresource.cpp +++ b/src/corelib/io/qresource.cpp @@ -876,7 +876,13 @@ public: virtual QString mappingRoot() const { return root; } virtual ResourceRootType type() const { return Resource_Buffer; } - bool registerSelf(const uchar *b) { + // size == -1 means "unknown" + bool registerSelf(const uchar *b, int size) + { + // 5 int "pointers" + if (size >= 0 && size < 20) + return false; + //setup the data now int offset = 0; @@ -903,6 +909,10 @@ public: (b[offset+2] << 8) + (b[offset+3] << 0); offset += 4; + // Some sanity checking for sizes. This is _not_ a security measure. + if (size >= 0 && (tree_offset >= size || data_offset >= size || name_offset >= size)) + return false; + if(version == 0x01) { buffer = b; setSource(b+tree_offset, b+name_offset, b+data_offset); @@ -1009,7 +1019,7 @@ public: } fromMM = false; } - if(data && QDynamicBufferResourceRoot::registerSelf(data)) { + if (data && QDynamicBufferResourceRoot::registerSelf(data, data_len)) { if(fromMM) { unmapPointer = data; unmapLength = data_len; @@ -1124,7 +1134,7 @@ QResource::registerResource(const uchar *rccData, const QString &resourceRoot) } QDynamicBufferResourceRoot *root = new QDynamicBufferResourceRoot(r); - if(root->registerSelf(rccData)) { + if (root->registerSelf(rccData, -1)) { root->ref.ref(); QMutexLocker lock(resourceMutex()); resourceList()->append(root); diff --git a/src/corelib/io/qtextstream.cpp b/src/corelib/io/qtextstream.cpp index 66727e7dc4..6cbe91fab2 100644 --- a/src/corelib/io/qtextstream.cpp +++ b/src/corelib/io/qtextstream.cpp @@ -827,6 +827,21 @@ inline void QTextStreamPrivate::write(const QString &data) /*! \internal */ +inline void QTextStreamPrivate::write(QChar ch) +{ + if (string) { + // ### What about seek()?? + string->append(ch); + } else { + writeBuffer += ch; + if (writeBuffer.size() > QTEXTSTREAM_BUFFERSIZE) + flushWriteBuffer(); + } +} + +/*! + \internal +*/ inline bool QTextStreamPrivate::getChar(QChar *ch) { if ((string && stringOffset == string->size()) @@ -865,6 +880,17 @@ inline void QTextStreamPrivate::ungetChar(QChar ch) /*! \internal */ +inline void QTextStreamPrivate::putChar(QChar ch) +{ + if (params.fieldWidth > 0) + putString(QString(ch)); + else + write(ch); +} + +/*! + \internal +*/ inline void QTextStreamPrivate::putString(const QString &s, bool number) { QString tmp = s; @@ -2232,7 +2258,7 @@ QTextStream &QTextStream::operator<<(QChar c) { Q_D(QTextStream); CHECK_VALID_STREAM(*this); - d->putString(QString(c)); + d->putChar(c); return *this; } @@ -2245,7 +2271,7 @@ QTextStream &QTextStream::operator<<(char c) { Q_D(QTextStream); CHECK_VALID_STREAM(*this); - d->putString(QString(QChar::fromLatin1(c))); + d->putChar(QChar::fromLatin1(c)); return *this; } diff --git a/src/corelib/io/qtextstream_p.h b/src/corelib/io/qtextstream_p.h index 5f99f44cc2..b7281e42ad 100644 --- a/src/corelib/io/qtextstream_p.h +++ b/src/corelib/io/qtextstream_p.h @@ -166,7 +166,9 @@ public: bool getReal(double *f); inline void write(const QString &data); + inline void write(QChar ch); inline void putString(const QString &ch, bool number = false); + inline void putChar(QChar ch); void putNumber(qulonglong number, bool negative); // buffers diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 55625f3571..0ece4a395c 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -99,20 +99,22 @@ winrt { } mac { + HEADERS += \ + kernel/qcore_mac_p.h + SOURCES += \ - kernel/qcoreapplication_mac.cpp -} + kernel/qcoreapplication_mac.cpp \ + kernel/qcore_mac.cpp + + OBJECTIVE_SOURCES += \ + kernel/qcore_mac_objc.mm + + LIBS_PRIVATE += -framework Foundation -mac:!nacl { - HEADERS += \ - kernel/qcore_mac_p.h - SOURCES += \ - kernel/qcore_mac.cpp - OBJECTIVE_SOURCES += \ - kernel/qcore_mac_objc.mm + osx: LIBS_PRIVATE += -framework CoreServices - # We need UIKit for UIDevice - ios: LIBS_PRIVATE += -framework UIKit + # We need UIKit for UIDevice + ios: LIBS_PRIVATE += -framework UIKit } nacl { diff --git a/src/corelib/kernel/qcore_mac_objc.mm b/src/corelib/kernel/qcore_mac_objc.mm index 73f8296021..8ac062a154 100644 --- a/src/corelib/kernel/qcore_mac_objc.mm +++ b/src/corelib/kernel/qcore_mac_objc.mm @@ -1,6 +1,7 @@ /**************************************************************************** ** - ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). + ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). + ** Copyright (C) 2014 Petroules Corporation. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -47,6 +48,8 @@ QT_BEGIN_NAMESPACE +typedef qint16 (*GestaltFunction)(quint32 selector, qint32 *response); + NSString *QCFString::toNSString(const QString &string) { // The const cast below is safe: CfStringRef is immutable and so is NSString. @@ -58,31 +61,49 @@ QString QCFString::toQString(const NSString *nsstr) return toQString(reinterpret_cast<CFStringRef>(nsstr)); } -#ifdef Q_OS_IOS -QSysInfo::MacVersion qt_ios_version() +QAppleOperatingSystemVersion qt_apple_os_version() { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; - - int major = 0, minor = 0; - NSArray *components = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."]; - switch ([components count]) { - case 3: - // We don't care about the patch version - case 2: - minor = [[components objectAtIndex:1] intValue]; - // fall through - case 1: - major = [[components objectAtIndex:0] intValue]; - break; - default: - Q_UNREACHABLE(); + QAppleOperatingSystemVersion v = {0, 0, 0}; +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_10, __IPHONE_8_0) + if ([NSProcessInfo instancesRespondToSelector:@selector(operatingSystemVersion)]) { + NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion; + v.major = osv.majorVersion; + v.minor = osv.minorVersion; + v.patch = osv.patchVersion; + return v; } - - [pool release]; - - return QSysInfo::MacVersion(Q_MV_IOS(major, minor)); -} #endif + // Use temporary variables so we can return 0.0.0 (unknown version) + // in case of an error partway through determining the OS version + qint32 major = 0, minor = 0, patch = 0; +#if defined(Q_OS_IOS) + @autoreleasepool { + NSArray *parts = [UIDevice.currentDevice.systemVersion componentsSeparatedByString:@"."]; + major = parts.count > 0 ? [[parts objectAtIndex:0] intValue] : 0; + minor = parts.count > 1 ? [[parts objectAtIndex:1] intValue] : 0; + patch = parts.count > 2 ? [[parts objectAtIndex:2] intValue] : 0; + } +#elif defined(Q_OS_OSX) + static GestaltFunction pGestalt = 0; + if (!pGestalt) { + CFBundleRef b = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.CoreServices")); + pGestalt = reinterpret_cast<GestaltFunction>(CFBundleGetFunctionPointerForName(b, + CFSTR("Gestalt"))); + } + if (!pGestalt) + return v; + if (pGestalt('sys1', &major) != 0) + return v; + if (pGestalt('sys2', &minor) != 0) + return v; + if (pGestalt('sys3', &patch) != 0) + return v; +#endif + v.major = major; + v.minor = minor; + v.patch = patch; + return v; +} QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h index 842e2ef9f1..9b13f8d2b1 100644 --- a/src/corelib/kernel/qcore_mac_p.h +++ b/src/corelib/kernel/qcore_mac_p.h @@ -135,9 +135,11 @@ private: QString string; }; -#ifdef Q_OS_IOS -QSysInfo::MacVersion qt_ios_version(); -#endif +typedef struct { + int major, minor, patch; +} QAppleOperatingSystemVersion; + +QAppleOperatingSystemVersion qt_apple_os_version(); QT_END_NAMESPACE diff --git a/src/corelib/kernel/qmetatype.h b/src/corelib/kernel/qmetatype.h index 3d859021b5..53bfa769ac 100644 --- a/src/corelib/kernel/qmetatype.h +++ b/src/corelib/kernel/qmetatype.h @@ -1512,6 +1512,9 @@ struct QMetaTypeId2 template <typename T> struct QMetaTypeId2<const T&> : QMetaTypeId2<T> {}; +template <typename T> +struct QMetaTypeId2<T&> { enum {Defined = false }; }; + namespace QtPrivate { template <typename T, bool Defined = QMetaTypeId2<T>::Defined> struct QMetaTypeIdHelper { diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 492031d7fe..d153b2e4f9 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -2661,8 +2661,8 @@ QMetaObject::Connection QObject::connect(const QObject *sender, const char *sign const char *method_arg = method; ++method; // skip code - QByteArray methodName; QArgumentTypeArray methodTypes; + QByteArray methodName = QMetaObjectPrivate::decodeMethodSignature(method, methodTypes); const QMetaObject *rmeta = receiver->metaObject(); int method_index_relative = -1; Q_ASSERT(QMetaObjectPrivate::get(rmeta)->revision >= 7); diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 832ee250c7..7bc6d1cc47 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -1121,10 +1121,7 @@ QLibrary::LoadHints QLibrary::loadHints() const /* Internal, for debugging */ bool qt_debug_component() { - static int debug_env = -1; - if (debug_env == -1) - debug_env = QT_PREPEND_NAMESPACE(qgetenv)("QT_DEBUG_PLUGINS").toInt(); - + static int debug_env = QT_PREPEND_NAMESPACE(qEnvironmentVariableIntValue)("QT_DEBUG_PLUGINS"); return debug_env != 0; } diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index dd235ef7a5..a069e441df 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Intel Corporation. ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -38,6 +39,7 @@ #include "qlist.h" #include "qlocale.h" #include "qlocale_p.h" +#include "qstringalgorithms_p.h" #include "qscopedpointer.h" #include <qdatastream.h> #include <qmath.h> @@ -54,6 +56,64 @@ QT_BEGIN_NAMESPACE +// Latin 1 case system, used by QByteArray::to{Upper,Lower}() and qstr(n)icmp(): +/* +#!/usr/bin/perl -l +use feature "unicode_strings"; +for (0..255) { + $up = uc(chr($_)); + $up = chr($_) if ord($up) > 0x100 || length $up > 1; + printf "0x%02x,", ord($up); + print "" if ($_ & 0xf) == 0xf; +} +*/ +static const uchar latin1_uppercased[256] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, + 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, + 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, + 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xf7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xff +}; + +/* +#!/usr/bin/perl -l +use feature "unicode_strings"; +for (0..255) { + $up = lc(chr($_)); + $up = chr($_) if ord($up) > 0x100 || length $up > 1; + printf "0x%02x,", ord($up); + print "" if ($_ & 0xf) == 0xf; +} +*/ +static const uchar latin1_lowercased[256] = { + 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, + 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, + 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, + 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f, + 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, + 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, + 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, + 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, + 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, + 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, + 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xd7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xdf, + 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff +}; int qFindByteArray( const char *haystack0, int haystackLen, int from, @@ -248,7 +308,7 @@ int qstricmp(const char *str1, const char *str2) uchar c; if (!s1 || !s2) return s1 ? 1 : (s2 ? -1 : 0); - for (; !(res = (c = QChar::toLower((ushort)*s1)) - QChar::toLower((ushort)*s2)); s1++, s2++) + for (; !(res = (c = latin1_lowercased[*s1]) - latin1_lowercased[*s2]); s1++, s2++) if (!c) // strings are equal break; return res; @@ -283,7 +343,7 @@ int qstrnicmp(const char *str1, const char *str2, uint len) if (!s1 || !s2) return s1 ? 1 : (s2 ? -1 : 0); for (; len--; s1++, s2++) { - if ((res = (c = QChar::toLower((ushort)*s1)) - QChar::toLower((ushort)*s2))) + if ((res = (c = latin1_lowercased[*s1]) - latin1_lowercased[*s2])) return res; if (!c) // strings are equal break; @@ -2677,6 +2737,8 @@ QByteArray QByteArray::mid(int pos, int len) const } /*! + \fn QByteArray QByteArray::toLower() const + Returns a lowercase copy of the byte array. The bytearray is interpreted as a Latin-1 encoded string. @@ -2685,21 +2747,56 @@ QByteArray QByteArray::mid(int pos, int len) const \sa toUpper(), {8-bit Character Comparisons} */ -QByteArray QByteArray::toLower() const + +// noinline so that the compiler won't inline the function in each of +// toLower and toUpper when the only difference is the table being used +// (even with constant propagation, there's no gain in performance). +template <typename T> +#ifdef Q_CC_MSVC +__declspec(noinline) +#elif defined(Q_CC_GNU) +__attribute__((noinline)) +#endif +static QByteArray toCase_template(T &input, const uchar * table) { - QByteArray s(*this); - uchar *p = reinterpret_cast<uchar *>(s.data()); - uchar *e = reinterpret_cast<uchar *>(s.end()); - if (p) { - while (p != e) { - *p = QChar::toLower((ushort)*p); - p++; - } + // find the first bad character in input + const char *orig_begin = input.constBegin(); + const char *firstBad = orig_begin; + const char *e = input.constEnd(); + for ( ; firstBad != e ; ++firstBad) { + uchar ch = uchar(*firstBad); + uchar converted = table[ch]; + if (ch != converted) + break; + } + + if (firstBad == e) + return qMove(input); + + // transform the rest + QByteArray s = qMove(input); // will copy if T is const QByteArray + char *b = s.begin(); // will detach if necessary + char *p = b + (firstBad - orig_begin); + e = b + s.size(); + for ( ; p != e; ++p) { + *p = char(uchar(table[uchar(*p)])); } return s; } +QByteArray QByteArray::toLower_helper(const QByteArray &a) +{ + return toCase_template(a, latin1_lowercased); +} + +QByteArray QByteArray::toLower_helper(QByteArray &a) +{ + return toCase_template(a, latin1_lowercased); +} + /*! + \fn QByteArray QByteArray::toUpper() const + Returns an uppercase copy of the byte array. The bytearray is interpreted as a Latin-1 encoded string. @@ -2709,18 +2806,14 @@ QByteArray QByteArray::toLower() const \sa toLower(), {8-bit Character Comparisons} */ -QByteArray QByteArray::toUpper() const +QByteArray QByteArray::toUpper_helper(const QByteArray &a) { - QByteArray s(*this); - uchar *p = reinterpret_cast<uchar *>(s.data()); - uchar *e = reinterpret_cast<uchar *>(s.end()); - if (p) { - while (p != e) { - *p = QChar::toUpper((ushort)*p); - p++; - } - } - return s; + return toCase_template(a, latin1_uppercased); +} + +QByteArray QByteArray::toUpper_helper(QByteArray &a) +{ + return toCase_template(a, latin1_uppercased); } /*! \fn void QByteArray::clear() @@ -3115,27 +3208,7 @@ QDataStream &operator>>(QDataStream &in, QByteArray &ba) */ QByteArray QByteArray::simplified() const { - if (d->size == 0) - return *this; - QByteArray result(d->size, Qt::Uninitialized); - const char *from = d->data(); - const char *fromend = from + d->size; - int outc=0; - char *to = result.d->data(); - for (;;) { - while (from!=fromend && ascii_isspace(uchar(*from))) - from++; - while (from!=fromend && !ascii_isspace(uchar(*from))) - to[outc++] = *from++; - if (from!=fromend) - to[outc++] = ' '; - else - break; - } - if (outc > 0 && to[outc-1] == ' ') - outc--; - result.resize(outc); - return result; + return QStringAlgorithms<const QByteArray>::simplified_helper(*this); } /*! @@ -3155,25 +3228,7 @@ QByteArray QByteArray::simplified() const */ QByteArray QByteArray::trimmed() const { - if (d->size == 0) - return *this; - const char *s = d->data(); - if (!ascii_isspace(uchar(*s)) && !ascii_isspace(uchar(s[d->size-1]))) - return *this; - int start = 0; - int end = d->size - 1; - while (start<=end && ascii_isspace(uchar(s[start]))) // skip white space from start - start++; - if (start <= end) { // only white space - while (end && ascii_isspace(uchar(s[end]))) // skip white space from end - end--; - } - int l = end - start + 1; - if (l <= 0) { - QByteArrayDataPtr empty = { Data::allocate(0) }; - return QByteArray(empty); - } - return QByteArray(s+start, l); + return QStringAlgorithms<const QByteArray>::trimmed_helper(*this); } /*! diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index f13b1c16cd..46aaeba1b5 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -256,8 +256,29 @@ public: void truncate(int pos); void chop(int n); +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) +# if defined(Q_CC_GNU) + // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 +# pragma push_macro("Q_REQUIRED_RESULT") +# undef Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT_pushed +# endif + QByteArray toLower() const & Q_REQUIRED_RESULT + { return toLower_helper(*this); } + QByteArray toLower() && Q_REQUIRED_RESULT + { return toLower_helper(*this); } + QByteArray toUpper() const & Q_REQUIRED_RESULT + { return toUpper_helper(*this); } + QByteArray toUpper() && Q_REQUIRED_RESULT + { return toUpper_helper(*this); } +# ifdef Q_REQUIRED_RESULT_pushed +# pragma pop_macro("Q_REQUIRED_RESULT") +# endif +#else QByteArray toLower() const Q_REQUIRED_RESULT; QByteArray toUpper() const Q_REQUIRED_RESULT; +#endif QByteArray trimmed() const Q_REQUIRED_RESULT; QByteArray simplified() const Q_REQUIRED_RESULT; @@ -414,6 +435,10 @@ private: void expand(int i); QByteArray nulTerminated() const; + static QByteArray toLower_helper(const QByteArray &a); + static QByteArray toLower_helper(QByteArray &a); + static QByteArray toUpper_helper(const QByteArray &a); + static QByteArray toUpper_helper(QByteArray &a); friend class QByteRef; friend class QString; friend Q_CORE_EXPORT QByteArray qUncompress(const uchar *data, int nbytes); diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index 4db09e0f82..dcbe3fb0c2 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -83,8 +83,10 @@ public: #ifndef QT_NO_CAST_FROM_ASCII QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR explicit QChar(char c) : ucs(uchar(c)) { } +#ifndef QT_RESTRICTED_CAST_FROM_ASCII QT_ASCII_CAST_WARN Q_DECL_CONSTEXPR explicit QChar(uchar c) : ucs(c) { } #endif +#endif // Unicode information enum Category diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 75f2a93e45..4fa07b17d4 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -249,7 +249,7 @@ static QString toOffsetString(Qt::DateFormat format, int offset) } // Parse offset in [+-]HH[:]MM format -static int fromOffsetString(const QString &offsetString, bool *valid) +static int fromOffsetString(const QStringRef &offsetString, bool *valid) { *valid = false; @@ -270,15 +270,15 @@ static int fromOffsetString(const QString &offsetString, bool *valid) return 0; // Split the hour and minute parts - QStringList parts = offsetString.mid(1).split(QLatin1Char(':')); + QVector<QStringRef> parts = offsetString.mid(1).split(QLatin1Char(':')); if (parts.count() == 1) { // [+-]HHMM format - parts.append(parts.at(0).mid(2)); - parts[0] = parts.at(0).left(2); + parts.append(parts.first().mid(2)); + parts[0] = parts.first().left(2); } bool ok = false; - const int hour = parts.at(0).toInt(&ok); + const int hour = parts.first().toInt(&ok); if (!ok) return 0; @@ -898,18 +898,18 @@ QString QDate::toString(Qt::DateFormat format) const #ifndef QT_NO_TEXTDATE case Qt::TextDate: getDateFromJulianDay(jd, &y, &m, &d); - return QString::fromUtf8("%1 %2 %3 %4").arg(shortDayName(dayOfWeek())) - .arg(shortMonthName(m)) - .arg(d) - .arg(y); + return QString::fromLatin1("%1 %2 %3 %4").arg(shortDayName(dayOfWeek())) + .arg(shortMonthName(m)) + .arg(d) + .arg(y); #endif case Qt::ISODate: getDateFromJulianDay(jd, &y, &m, &d); if (y < 0 || y > 9999) return QString(); - return QString::fromUtf8("%1-%2-%3").arg(y, 4, 10, QLatin1Char('0')) - .arg(m, 2, 10, QLatin1Char('0')) - .arg(d, 2, 10, QLatin1Char('0')); + return QString::fromLatin1("%1-%2-%3").arg(y, 4, 10, QLatin1Char('0')) + .arg(m, 2, 10, QLatin1Char('0')) + .arg(d, 2, 10, QLatin1Char('0')); } } @@ -1247,12 +1247,12 @@ QDate QDate::fromString(const QString& string, Qt::DateFormat format) default: #ifndef QT_NO_TEXTDATE case Qt::TextDate: { - QStringList parts = string.split(QLatin1Char(' '), QString::SkipEmptyParts); + QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts); if (parts.count() != 4) return QDate(); - QString monthName = parts.at(1); + QStringRef monthName = parts.at(1); int month = -1; // Assume that English monthnames are the default for (int i = 0; i < 12; ++i) { @@ -1288,10 +1288,10 @@ QDate QDate::fromString(const QString& string, Qt::DateFormat format) || (string.size() > 10 && string.at(10).isDigit())) { return QDate(); } - const int year = string.mid(0, 4).toInt(); + const int year = string.midRef(0, 4).toInt(); if (year <= 0 || year > 9999) return QDate(); - return QDate(year, string.mid(5, 2).toInt(), string.mid(8, 2).toInt()); + return QDate(year, string.midRef(5, 2).toInt(), string.midRef(8, 2).toInt()); } } return QDate(); @@ -1649,9 +1649,9 @@ QString QTime::toString(Qt::DateFormat format) const case Qt::ISODate: case Qt::TextDate: default: - return QString::fromUtf8("%1:%2:%3").arg(hour(), 2, 10, QLatin1Char('0')) - .arg(minute(), 2, 10, QLatin1Char('0')) - .arg(second(), 2, 10, QLatin1Char('0')); + return QString::fromLatin1("%1:%2:%3").arg(hour(), 2, 10, QLatin1Char('0')) + .arg(minute(), 2, 10, QLatin1Char('0')) + .arg(second(), 2, 10, QLatin1Char('0')); } } @@ -3596,11 +3596,11 @@ QString QDateTime::toString(Qt::DateFormat format) const QTime tm; d->getDateTime(&dt, &tm); //We cant use date.toString(Qt::TextDate) as we need to insert the time before the year - buf = QString::fromUtf8("%1 %2 %3 %4 %5").arg(dt.shortDayName(dt.dayOfWeek())) - .arg(dt.shortMonthName(dt.month())) - .arg(dt.day()) - .arg(tm.toString(Qt::TextDate)) - .arg(dt.year()); + buf = QString::fromLatin1("%1 %2 %3 %4 %5").arg(dt.shortDayName(dt.dayOfWeek())) + .arg(dt.shortMonthName(dt.month())) + .arg(dt.day()) + .arg(tm.toString(Qt::TextDate)) + .arg(dt.year()); if (timeSpec() != Qt::LocalTime) { buf += QStringLiteral(" GMT"); if (d->m_spec == Qt::OffsetFromUTC) @@ -4197,6 +4197,39 @@ qint64 QDateTime::currentMSecsSinceEpoch() Q_DECL_NOTHROW #error "What system is this?" #endif +/*! \fn QDateTime QDateTime::fromCFDate(CFDateRef date) + \since 5.5 + + Constructs a new QDateTime containing a copy of the CFDate \a date. + + \sa toCFDate() +*/ + +/*! \fn CFDateRef QDateTime::toCFDate() const + \since 5.5 + + Creates a CFDate from a QDateTime. The caller owns the CFDate object + and is responsible for releasing it. + + \sa fromCFDate() +*/ + +/*! \fn QDateTime QDateTime::fromNSDate(const NSDate *date) + \since 5.5 + + Constructs a new QDateTime containing a copy of the NSDate \a date. + + \sa toNSDate() +*/ + +/*! \fn NSDate QDateTime::toNSDate() const + \since 5.5 + + Creates an NSDate from a QDateTime. The NSDate object is autoreleased. + + \sa fromNSDate() +*/ + /*! \since 4.2 @@ -4351,7 +4384,7 @@ int QDateTime::utcOffset() const #ifndef QT_NO_DATESTRING -static int fromShortMonthName(const QString &monthName) +static int fromShortMonthName(const QStringRef &monthName) { // Assume that English monthnames are the default for (int i = 0; i < 12; ++i) { @@ -4443,7 +4476,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (found) { bool ok; - offset = fromOffsetString(isoString.mid(signIndex).toString(), &ok); + offset = fromOffsetString(isoString.mid(signIndex), &ok); if (!ok) return QDateTime(); isoString = isoString.left(signIndex); @@ -4463,7 +4496,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) } #if !defined(QT_NO_TEXTDATE) case Qt::TextDate: { - QStringList parts = string.split(QLatin1Char(' '), QString::SkipEmptyParts); + QVector<QStringRef> parts = string.splitRef(QLatin1Char(' '), QString::SkipEmptyParts); if ((parts.count() < 5) || (parts.count() > 6)) return QDateTime(); @@ -4482,9 +4515,9 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (!month || !day) { month = fromShortMonthName(parts.at(2)); if (month) { - QString dayStr = parts.at(1); + QStringRef dayStr = parts.at(1); if (dayStr.endsWith(QLatin1Char('.'))) { - dayStr.chop(1); + dayStr = dayStr.left(dayStr.size() - 1); day = dayStr.toInt(); } } @@ -4517,7 +4550,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (!date.isValid()) return QDateTime(); - QStringList timeParts = parts.at(timePart).split(QLatin1Char(':')); + QVector<QStringRef> timeParts = parts.at(timePart).split(QLatin1Char(':')); if (timeParts.count() < 2 || timeParts.count() > 3) return QDateTime(); @@ -4532,7 +4565,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) int second = 0; int millisecond = 0; if (timeParts.count() > 2) { - QStringList secondParts = timeParts.at(2).split(QLatin1Char('.')); + QVector<QStringRef> secondParts = timeParts.at(2).split(QLatin1Char('.')); if (secondParts.size() > 2) { return QDateTime(); } @@ -4557,10 +4590,10 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (parts.count() == 5) return QDateTime(date, time, Qt::LocalTime); - QString tz = parts.at(5); + QStringRef tz = parts.at(5); if (!tz.startsWith(QLatin1String("GMT"), Qt::CaseInsensitive)) return QDateTime(); - tz.remove(0, 3); + tz = tz.mid(3); if (!tz.isEmpty()) { int offset = fromOffsetString(tz, &ok); if (!ok) @@ -4987,7 +5020,7 @@ QDebug operator<<(QDebug dbg, const QDateTime &date) spec = QStringLiteral(" Qt::UTC"); break; case Qt::OffsetFromUTC: - spec = QString::fromUtf8(" Qt::OffsetFromUTC %1s").arg(date.offsetFromUtc()); + spec = QString::fromLatin1(" Qt::OffsetFromUTC %1s").arg(date.offsetFromUtc()); break; case Qt::TimeZone: #ifndef QT_BOOTSTRAPPED diff --git a/src/corelib/tools/qdatetime.h b/src/corelib/tools/qdatetime.h index 597655f557..4ef94f72d7 100644 --- a/src/corelib/tools/qdatetime.h +++ b/src/corelib/tools/qdatetime.h @@ -40,6 +40,13 @@ #include <limits> +#ifdef Q_OS_MAC +Q_FORWARD_DECLARE_CF_TYPE(CFDate); +# ifdef __OBJC__ +Q_FORWARD_DECLARE_OBJC_CLASS(NSDate); +# endif +#endif + QT_BEGIN_NAMESPACE class QTimeZone; @@ -295,6 +302,15 @@ public: #endif static qint64 currentMSecsSinceEpoch() Q_DECL_NOTHROW; +#if defined(Q_OS_MAC) || defined(Q_QDOC) + static QDateTime fromCFDate(CFDateRef date); + CFDateRef toCFDate() const Q_DECL_CF_RETURNS_RETAINED; +# if defined(__OBJC__) || defined(Q_QDOC) + static QDateTime fromNSDate(const NSDate *date); + NSDate *toNSDate() const Q_DECL_NS_RETURNS_AUTORELEASED; +# endif +#endif + private: friend class QDateTimePrivate; void detach(); diff --git a/src/corelib/tools/qdatetime_mac.mm b/src/corelib/tools/qdatetime_mac.mm new file mode 100644 index 0000000000..c8a1d22928 --- /dev/null +++ b/src/corelib/tools/qdatetime_mac.mm @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2014 Petroules Corporation. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qdatetime.h" + +#import <Foundation/Foundation.h> + +QT_BEGIN_NAMESPACE + +QDateTime QDateTime::fromCFDate(CFDateRef date) +{ + if (!date) + return QDateTime(); + return QDateTime::fromMSecsSinceEpoch(static_cast<qint64>((CFDateGetAbsoluteTime(date) + + kCFAbsoluteTimeIntervalSince1970) * 1000)); +} + +CFDateRef QDateTime::toCFDate() const +{ + return CFDateCreate(kCFAllocatorDefault, (static_cast<CFAbsoluteTime>(toMSecsSinceEpoch()) + / 1000) - kCFAbsoluteTimeIntervalSince1970); +} + +QDateTime QDateTime::fromNSDate(const NSDate *date) +{ + if (!date) + return QDateTime(); + return QDateTime::fromMSecsSinceEpoch(static_cast<qint64>([date timeIntervalSince1970] * 1000)); +} + +NSDate *QDateTime::toNSDate() const +{ + return [NSDate + dateWithTimeIntervalSince1970:static_cast<NSTimeInterval>(toMSecsSinceEpoch()) / 1000]; +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qdatetime_p.h b/src/corelib/tools/qdatetime_p.h index 78484f30ed..7c7f7f2a6a 100644 --- a/src/corelib/tools/qdatetime_p.h +++ b/src/corelib/tools/qdatetime_p.h @@ -111,6 +111,9 @@ public: m_status(other.m_status) {} + // ### XXX: when the tooling situation improves, look at fixing the padding. + // 4 bytes padding + qint64 m_msecs; Qt::TimeSpec m_spec; int m_offsetFromUtc; diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp index 0e3375cf21..b4ecc65f29 100644 --- a/src/corelib/tools/qeasingcurve.cpp +++ b/src/corelib/tools/qeasingcurve.cpp @@ -347,9 +347,7 @@ typedef QVector<TCBPoint> TCBPoints; class QEasingCurveFunction { public: - enum Type { In, Out, InOut, OutIn }; - - QEasingCurveFunction(QEasingCurveFunction::Type type = In, qreal period = 0.3, qreal amplitude = 1.0, + QEasingCurveFunction(QEasingCurve::Type type, qreal period = 0.3, qreal amplitude = 1.0, qreal overshoot = 1.70158) : _t(type), _p(period), _a(amplitude), _o(overshoot) { } @@ -358,7 +356,7 @@ public: virtual QEasingCurveFunction *copy() const; bool operator==(const QEasingCurveFunction &other) const; - Type _t; + QEasingCurve::Type _t; qreal _p; qreal _a; qreal _o; @@ -367,9 +365,12 @@ public: }; +static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve); + qreal QEasingCurveFunction::value(qreal t) { - return t; + QEasingCurve::EasingFunction func = curveToFunc(_t); + return func(t); } QEasingCurveFunction *QEasingCurveFunction::copy() const @@ -430,8 +431,8 @@ struct BezierEase : public QEasingCurveFunction bool _init; bool _valid; - BezierEase() - : QEasingCurveFunction(InOut), _curves(10), _intervals(10), _init(false), _valid(false) + BezierEase(QEasingCurve::Type type = QEasingCurve::BezierSpline) + : QEasingCurveFunction(type), _curves(10), _intervals(10), _init(false), _valid(false) { } void init() @@ -814,6 +815,10 @@ struct BezierEase : public QEasingCurveFunction struct TCBEase : public BezierEase { + TCBEase() + : BezierEase(QEasingCurve::TCBSpline) + { } + qreal value(qreal x) { Q_ASSERT(_bezierCurves.count() % 3 == 0); @@ -830,7 +835,7 @@ struct TCBEase : public BezierEase struct ElasticEase : public QEasingCurveFunction { - ElasticEase(Type type) + ElasticEase(QEasingCurve::Type type) : QEasingCurveFunction(type, qreal(0.3), qreal(1.0)) { } @@ -849,13 +854,13 @@ struct ElasticEase : public QEasingCurveFunction qreal p = (_p < 0) ? qreal(0.3) : _p; qreal a = (_a < 0) ? qreal(1.0) : _a; switch(_t) { - case In: + case QEasingCurve::InElastic: return easeInElastic(t, a, p); - case Out: + case QEasingCurve::OutElastic: return easeOutElastic(t, a, p); - case InOut: + case QEasingCurve::InOutElastic: return easeInOutElastic(t, a, p); - case OutIn: + case QEasingCurve::OutInElastic: return easeOutInElastic(t, a, p); default: return t; @@ -865,7 +870,7 @@ struct ElasticEase : public QEasingCurveFunction struct BounceEase : public QEasingCurveFunction { - BounceEase(Type type) + BounceEase(QEasingCurve::Type type) : QEasingCurveFunction(type, qreal(0.3), qreal(1.0)) { } @@ -882,13 +887,13 @@ struct BounceEase : public QEasingCurveFunction { qreal a = (_a < 0) ? qreal(1.0) : _a; switch(_t) { - case In: + case QEasingCurve::InBounce: return easeInBounce(t, a); - case Out: + case QEasingCurve::OutBounce: return easeOutBounce(t, a); - case InOut: + case QEasingCurve::InOutBounce: return easeInOutBounce(t, a); - case OutIn: + case QEasingCurve::OutInBounce: return easeOutInBounce(t, a); default: return t; @@ -898,7 +903,7 @@ struct BounceEase : public QEasingCurveFunction struct BackEase : public QEasingCurveFunction { - BackEase(Type type) + BackEase(QEasingCurve::Type type) : QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158)) { } @@ -915,13 +920,13 @@ struct BackEase : public QEasingCurveFunction { qreal o = (_o < 0) ? qreal(1.70158) : _o; switch(_t) { - case In: + case QEasingCurve::InBack: return easeInBack(t, o); - case Out: + case QEasingCurve::OutBack: return easeOutBack(t, o); - case InOut: + case QEasingCurve::InOutBack: return easeInOutBack(t, o); - case OutIn: + case QEasingCurve::OutInBack: return easeOutInBack(t, o); default: return t; @@ -1006,55 +1011,31 @@ static QEasingCurve::EasingFunction curveToFunc(QEasingCurve::Type curve) static QEasingCurveFunction *curveToFunctionObject(QEasingCurve::Type type) { - QEasingCurveFunction *curveFunc = 0; switch(type) { case QEasingCurve::InElastic: - curveFunc = new ElasticEase(ElasticEase::In); - break; case QEasingCurve::OutElastic: - curveFunc = new ElasticEase(ElasticEase::Out); - break; case QEasingCurve::InOutElastic: - curveFunc = new ElasticEase(ElasticEase::InOut); - break; case QEasingCurve::OutInElastic: - curveFunc = new ElasticEase(ElasticEase::OutIn); - break; + return new ElasticEase(type); case QEasingCurve::OutBounce: - curveFunc = new BounceEase(BounceEase::Out); - break; case QEasingCurve::InBounce: - curveFunc = new BounceEase(BounceEase::In); - break; case QEasingCurve::OutInBounce: - curveFunc = new BounceEase(BounceEase::OutIn); - break; case QEasingCurve::InOutBounce: - curveFunc = new BounceEase(BounceEase::InOut); - break; + return new BounceEase(type); case QEasingCurve::InBack: - curveFunc = new BackEase(BackEase::In); - break; case QEasingCurve::OutBack: - curveFunc = new BackEase(BackEase::Out); - break; case QEasingCurve::InOutBack: - curveFunc = new BackEase(BackEase::InOut); - break; case QEasingCurve::OutInBack: - curveFunc = new BackEase(BackEase::OutIn); - break; + return new BackEase(type); case QEasingCurve::BezierSpline: - curveFunc = new BezierEase(); - break; + return new BezierEase; case QEasingCurve::TCBSpline: - curveFunc = new TCBEase(); - break; + return new TCBEase; default: - curveFunc = new QEasingCurveFunction(QEasingCurveFunction::In, qreal(0.3), qreal(1.0), qreal(1.70158)); + return new QEasingCurveFunction(type, qreal(0.3), qreal(1.0), qreal(1.70158)); } - return curveFunc; + return 0; } /*! diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index fe8c52d103..0f741a2f7e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -259,9 +259,7 @@ static uint qt_create_qhash_seed() quintptr seedPtr = reinterpret_cast<quintptr>(&seed); seed ^= seedPtr; -#if QT_POINTER_SIZE == 8 - seed ^= (seedPtr >> 32); -#endif + seed ^= (qulonglong(seedPtr) >> 32); // no-op on 32-bit platforms #endif // QT_BOOTSTRAPPED return seed; diff --git a/src/corelib/tools/qlist.h b/src/corelib/tools/qlist.h index 326a276f40..9704c7b953 100644 --- a/src/corelib/tools/qlist.h +++ b/src/corelib/tools/qlist.h @@ -770,11 +770,10 @@ Q_OUTOFLINE_TEMPLATE bool QList<T>::operator==(const QList<T> &l) const return true; if (p.size() != l.p.size()) return false; - Node *i = reinterpret_cast<Node *>(p.end()); - Node *b = reinterpret_cast<Node *>(p.begin()); - Node *li = reinterpret_cast<Node *>(l.p.end()); - while (i != b) { - --i; --li; + Node *i = reinterpret_cast<Node *>(p.begin()); + Node *e = reinterpret_cast<Node *>(p.end()); + Node *li = reinterpret_cast<Node *>(l.p.begin()); + for (; i != e; ++i, ++li) { if (!(i->t() == li->t())) return false; } @@ -922,9 +921,9 @@ Q_OUTOFLINE_TEMPLATE int QList<T>::lastIndexOf(const T &t, int from) const template <typename T> Q_OUTOFLINE_TEMPLATE bool QList<T>::contains(const T &t) const { - Node *b = reinterpret_cast<Node *>(p.begin()); - Node *i = reinterpret_cast<Node *>(p.end()); - while (i-- != b) + Node *e = reinterpret_cast<Node *>(p.end()); + Node *i = reinterpret_cast<Node *>(p.begin()); + for (; i != e; ++i) if (i->t() == t) return true; return false; @@ -934,9 +933,9 @@ template <typename T> Q_OUTOFLINE_TEMPLATE int QList<T>::count(const T &t) const { int c = 0; - Node *b = reinterpret_cast<Node *>(p.begin()); - Node *i = reinterpret_cast<Node *>(p.end()); - while (i-- != b) + Node *e = reinterpret_cast<Node *>(p.end()); + Node *i = reinterpret_cast<Node *>(p.begin()); + for (; i != e; ++i) if (i->t() == t) ++c; return c; diff --git a/src/corelib/tools/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index 33894927fe..228ee5b842 100644 --- a/src/corelib/tools/qregularexpression.cpp +++ b/src/corelib/tools/qregularexpression.cpp @@ -835,6 +835,8 @@ struct QRegularExpressionPrivate : QSharedData }; QRegularExpressionMatchPrivate *doMatch(const QString &subject, + int subjectStartPos, + int subjectLength, int offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, @@ -872,6 +874,8 @@ struct QRegularExpressionMatchPrivate : QSharedData { QRegularExpressionMatchPrivate(const QRegularExpression &re, const QString &subject, + int subjectStart, + int subjectLength, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, int capturingCount = 0); @@ -884,6 +888,9 @@ struct QRegularExpressionMatchPrivate : QSharedData // for each captured substring QVector<int> capturedOffsets; + const int subjectStart; + const int subjectLength; + const QRegularExpression::MatchType matchType; const QRegularExpression::MatchOptions matchOptions; @@ -1219,14 +1226,21 @@ static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra, /*! \internal - Performs a match of type \a matchType on the given \a subject string with - options \a matchOptions and returns the QRegularExpressionMatchPrivate of - the result. It also advances a match if a previous result is given as \a + Performs a match on the substring of the given \a subject string, + substring which starts from \a subjectStart and up to + (but not including) \a subjectStart + \a subjectLength. The match + will be of type \a matchType and using the options \a matchOptions; + the matching \a offset is relative the substring, + and if negative, it's taken as an offset from the end of the substring. + + It also advances a match if a previous result is given as \a previous. The \a subject string goes a Unicode validity check if \a checkSubjectString is CheckSubjectString and the match options don't include DontCheckSubjectStringMatchOption (PCRE doesn't like illegal UTF-16 sequences). + Returns the QRegularExpressionMatchPrivate of the result. + Advancing a match is a tricky algorithm. If the previous match matched a non-empty string, we just do an ordinary match at the offset position. @@ -1239,6 +1253,8 @@ static int pcre16SafeExec(const pcre16 *code, const pcre16_extra *extra, must advance over it. */ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString &subject, + int subjectStart, + int subjectLength, int offset, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, @@ -1246,21 +1262,22 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString const QRegularExpressionMatchPrivate *previous) const { if (offset < 0) - offset += subject.length(); + offset += subjectLength; QRegularExpression re(*const_cast<QRegularExpressionPrivate *>(this)); - if (offset < 0 || offset > subject.length()) - return new QRegularExpressionMatchPrivate(re, subject, matchType, matchOptions); + if (offset < 0 || offset > subjectLength) + return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions); if (!compiledPattern) { qWarning("QRegularExpressionPrivate::doMatch(): called on an invalid QRegularExpression object"); - return new QRegularExpressionMatchPrivate(re, subject, matchType, matchOptions); + return new QRegularExpressionMatchPrivate(re, subject, subjectStart, subjectLength, matchType, matchOptions); } // skip optimizing and doing the actual matching if NoMatch type was requested if (matchType == QRegularExpression::NoMatch) { QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject, + subjectStart, subjectLength, matchType, matchOptions); priv->isValid = true; return priv; @@ -1268,6 +1285,7 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString // capturingCount doesn't include the implicit "0" capturing group QRegularExpressionMatchPrivate *priv = new QRegularExpressionMatchPrivate(re, subject, + subjectStart, subjectLength, matchType, matchOptions, capturingCount + 1); @@ -1307,45 +1325,49 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString int * const captureOffsets = priv->capturedOffsets.data(); const int captureOffsetsCount = priv->capturedOffsets.size(); + int realOffset = offset + subjectStart; + const int realSubjectLength = subjectLength + subjectStart; + const unsigned short * const subjectUtf16 = subject.utf16(); - const int subjectLength = subject.length(); int result; if (!previousMatchWasEmpty) { result = pcre16SafeExec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions, + subjectUtf16, realSubjectLength, + realOffset, pcreOptions, captureOffsets, captureOffsetsCount); } else { result = pcre16SafeExec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED, + subjectUtf16, realSubjectLength, + realOffset, pcreOptions | PCRE_NOTEMPTY_ATSTART | PCRE_ANCHORED, captureOffsets, captureOffsetsCount); if (result == PCRE_ERROR_NOMATCH) { - ++offset; + ++realOffset; if (usingCrLfNewlines - && offset < subjectLength - && subjectUtf16[offset - 1] == QLatin1Char('\r') - && subjectUtf16[offset] == QLatin1Char('\n')) { - ++offset; - } else if (offset < subjectLength - && QChar::isLowSurrogate(subjectUtf16[offset])) { - ++offset; + && realOffset < realSubjectLength + && subjectUtf16[realOffset - 1] == QLatin1Char('\r') + && subjectUtf16[realOffset] == QLatin1Char('\n')) { + ++realOffset; + } else if (realOffset < realSubjectLength + && QChar::isLowSurrogate(subjectUtf16[realOffset])) { + ++realOffset; } result = pcre16SafeExec(compiledPattern, currentStudyData, - subjectUtf16, subjectLength, - offset, pcreOptions, + subjectUtf16, realSubjectLength, + realOffset, pcreOptions, captureOffsets, captureOffsetsCount); } } #ifdef QREGULAREXPRESSION_DEBUG qDebug() << "Matching" << pattern << "against" << subject - << offset << matchType << matchOptions << previousMatchWasEmpty + << "starting at" << subjectStart << "len" << subjectLength << "real len" << realSubjectLength + << "offset" << offset << "real offset" << realOffset + << matchType << matchOptions << previousMatchWasEmpty << "result" << result; #endif @@ -1383,10 +1405,13 @@ QRegularExpressionMatchPrivate *QRegularExpressionPrivate::doMatch(const QString */ QRegularExpressionMatchPrivate::QRegularExpressionMatchPrivate(const QRegularExpression &re, const QString &subject, + int subjectStart, + int subjectLength, QRegularExpression::MatchType matchType, QRegularExpression::MatchOptions matchOptions, int capturingCount) : regularExpression(re), subject(subject), + subjectStart(subjectStart), subjectLength(subjectLength), matchType(matchType), matchOptions(matchOptions), capturedCount(0), hasMatch(false), hasPartialMatch(false), isValid(false) @@ -1412,6 +1437,8 @@ QRegularExpressionMatch QRegularExpressionMatchPrivate::nextMatch() const // then that subject was already checked at least once (when this object // was created, or when the object that created this one was created, etc.) QRegularExpressionMatchPrivate *nextPrivate = regularExpression.d->doMatch(subject, + subjectStart, + subjectLength, capturedOffsets.at(1), matchType, matchOptions, @@ -1684,7 +1711,33 @@ QRegularExpressionMatch QRegularExpression::match(const QString &subject, { d.data()->compilePattern(); - QRegularExpressionMatchPrivate *priv = d->doMatch(subject, offset, matchType, matchOptions); + QRegularExpressionMatchPrivate *priv = d->doMatch(subject, 0, subject.length(), offset, matchType, matchOptions); + return QRegularExpressionMatch(*priv); +} + +/*! + \since 5.5 + \overload + + Attempts to match the regular expression against the given \a subjectRef + string reference, starting at the position \a offset inside the subject, using a + match of type \a matchType and honoring the given \a matchOptions. + + The returned QRegularExpressionMatch object contains the results of the + match. + + \sa QRegularExpressionMatch, {normal matching} +*/ +QRegularExpressionMatch QRegularExpression::match(const QStringRef &subjectRef, + int offset, + MatchType matchType, + MatchOptions matchOptions) const +{ + d.data()->compilePattern(); + + const QString subject = subjectRef.string() ? *subjectRef.string() : QString(); + + QRegularExpressionMatchPrivate *priv = d->doMatch(subject, subjectRef.position(), subjectRef.length(), offset, matchType, matchOptions); return QRegularExpressionMatch(*priv); } @@ -1714,6 +1767,34 @@ QRegularExpressionMatchIterator QRegularExpression::globalMatch(const QString &s } /*! + \since 5.5 + \overload + + Attempts to perform a global match of the regular expression against the + given \a subjectRef string reference, starting at the position \a offset inside the + subject, using a match of type \a matchType and honoring the given \a + matchOptions. + + The returned QRegularExpressionMatchIterator is positioned before the + first match result (if any). + + \sa QRegularExpressionMatchIterator, {global matching} +*/ +QRegularExpressionMatchIterator QRegularExpression::globalMatch(const QStringRef &subjectRef, + int offset, + MatchType matchType, + MatchOptions matchOptions) const +{ + QRegularExpressionMatchIteratorPrivate *priv = + new QRegularExpressionMatchIteratorPrivate(*this, + matchType, + matchOptions, + match(subjectRef, offset, matchType, matchOptions)); + + return QRegularExpressionMatchIterator(*priv); +} + +/*! \since 5.4 Forces an immediate optimization of the pattern, including @@ -1823,6 +1904,8 @@ QString QRegularExpression::escape(const QString &str) QRegularExpressionMatch::QRegularExpressionMatch() : d(new QRegularExpressionMatchPrivate(QRegularExpression(), QString(), + 0, + 0, QRegularExpression::NoMatch, QRegularExpression::NoMatchOption)) { diff --git a/src/corelib/tools/qregularexpression.h b/src/corelib/tools/qregularexpression.h index 66538f22b3..f332227094 100644 --- a/src/corelib/tools/qregularexpression.h +++ b/src/corelib/tools/qregularexpression.h @@ -112,11 +112,21 @@ public: MatchType matchType = NormalMatch, MatchOptions matchOptions = NoMatchOption) const; + QRegularExpressionMatch match(const QStringRef &subjectRef, + int offset = 0, + MatchType matchType = NormalMatch, + MatchOptions matchOptions = NoMatchOption) const; + QRegularExpressionMatchIterator globalMatch(const QString &subject, int offset = 0, MatchType matchType = NormalMatch, MatchOptions matchOptions = NoMatchOption) const; + QRegularExpressionMatchIterator globalMatch(const QStringRef &subjectRef, + int offset = 0, + MatchType matchType = NormalMatch, + MatchOptions matchOptions = NoMatchOption) const; + void optimize() const; static QString escape(const QString &str); diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b805ec792e..95e45c8d93 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -70,6 +70,7 @@ #include "qchar.cpp" #include "qstringmatcher.cpp" #include "qstringiterator_p.h" +#include "qstringalgorithms_p.h" #include "qthreadstorage.h" #ifdef Q_OS_WIN @@ -731,12 +732,30 @@ inline char qToLower(char ch) const QString::Null QString::null = { }; /*! + \macro QT_RESTRICTED_CAST_FROM_ASCII + \relates QString + + Defining this macro disables most automatic conversions from source + literals and 8-bit data to unicode QStrings, but allows the use of + the \c{QChar(char)} and \c{QString(const char (&ch)[N]} constructors, + and the \c{QString::operator=(const char (&ch)[N])} assignment operator + giving most of the type-safety benefits of QT_NO_CAST_FROM_ASCII + but does not require user code to wrap character and string literals + with QLatin1Char, QLatin1String or similar. + + Using this macro together with source strings outside the 7-bit range, + non-literals, or literals with embedded NUL characters is undefined. + + \sa QT_NO_CAST_FROM_ASCII, QT_NO_CAST_TO_ASCII +*/ + +/*! \macro QT_NO_CAST_FROM_ASCII \relates QString Disables automatic conversions from 8-bit strings (char *) to unicode QStrings - \sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_BYTEARRAY + \sa QT_NO_CAST_TO_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY */ /*! @@ -745,7 +764,7 @@ const QString::Null QString::null = { }; disables automatic conversion from QString to 8-bit strings (char *) - \sa QT_NO_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY + \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII, QT_NO_CAST_FROM_BYTEARRAY */ /*! @@ -759,7 +778,7 @@ const QString::Null QString::null = { }; Note: This only works for compilers that support warnings for deprecated API. - \sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_ASCII + \sa QT_NO_CAST_TO_ASCII, QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII */ /*! @@ -993,6 +1012,9 @@ const QString::Null QString::null = { }; \list \li \c QT_NO_CAST_FROM_ASCII disables automatic conversions from C string literals and pointers to Unicode. + \li \c QT_RESTRICTED_CAST_FROM_ASCII allows automatic conversions + from C characters and character arrays, but disables automatic + conversions from character pointers to Unicode. \li \c QT_NO_CAST_TO_ASCII disables automatic conversion from QString to C strings. \endlist @@ -1310,6 +1332,12 @@ const QString::Null QString::null = { }; can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + \note Defining QT_RESTRICTED_CAST_FROM_ASCII also disables + this constructor, but enables a \c{QString(const char (&ch)[N])} + constructor instead. Using non-literal input, or input with + embedded NUL characters, or non-7-bit characters is undefined + in this case. + \sa fromLatin1(), fromLocal8Bit(), fromUtf8() */ @@ -1748,10 +1776,11 @@ QString &QString::operator=(const QString &other) Assigns \a str to this string. The const char pointer is converted to Unicode using the fromUtf8() function. - You can disable this operator by defining \c - QT_NO_CAST_FROM_ASCII when you compile your applications. This - can be useful if you want to ensure that all user-visible strings + You can disable this operator by defining \c QT_NO_CAST_FROM_ASCII + or \c QT_RESTRICTED_CAST_FROM_ASCII when you compile your applications. + This can be useful if you want to ensure that all user-visible strings go through QObject::tr(), for example. + */ /*! \fn QString &QString::operator=(char ch) @@ -3664,14 +3693,39 @@ int QString::count(const QRegExp& rx) const */ int QString::indexOf(const QRegularExpression& re, int from) const { + return indexOf(re, from, Q_NULLPTR); +} + +/*! + \overload + \since 5.5 + + Returns the index position of the first match of the regular + expression \a re in the string, searching forward from index + position \a from. Returns -1 if \a re didn't match anywhere. + + If the match is successful and \a rmatch is not a null pointer, it also + writes the results of the match into the QRegularExpressionMatch object + pointed to by \a rmatch. + + Example: + + \snippet qstring/main.cpp 97 +*/ +int QString::indexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const +{ if (!re.isValid()) { qWarning("QString::indexOf: invalid QRegularExpression object"); return -1; } QRegularExpressionMatch match = re.match(*this, from); - if (match.hasMatch()) - return match.capturedStart(); + if (match.hasMatch()) { + const int ret = match.capturedStart(); + if (rmatch) + *rmatch = qMove(match); + return ret; + } return -1; } @@ -3690,22 +3744,45 @@ int QString::indexOf(const QRegularExpression& re, int from) const */ int QString::lastIndexOf(const QRegularExpression &re, int from) const { + return lastIndexOf(re, from, Q_NULLPTR); +} + +/*! + \overload + \since 5.5 + + Returns the index position of the last match of the regular + expression \a re in the string, which starts before the index + position \a from. Returns -1 if \a re didn't match anywhere. + + If the match is successful and \a rmatch is not a null pointer, it also + writes the results of the match into the QRegularExpressionMatch object + pointed to by \a rmatch. + + Example: + + \snippet qstring/main.cpp 98 +*/ +int QString::lastIndexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const +{ if (!re.isValid()) { qWarning("QString::lastIndexOf: invalid QRegularExpression object"); return -1; } int endpos = (from < 0) ? (size() + from + 1) : (from + 1); - QRegularExpressionMatchIterator iterator = re.globalMatch(*this); int lastIndex = -1; while (iterator.hasNext()) { QRegularExpressionMatch match = iterator.next(); int start = match.capturedStart(); - if (start < endpos) + if (start < endpos) { lastIndex = start; - else + if (rmatch) + *rmatch = qMove(match); + } else { break; + } } return lastIndex; @@ -3719,12 +3796,7 @@ int QString::lastIndexOf(const QRegularExpression &re, int from) const */ bool QString::contains(const QRegularExpression &re) const { - if (!re.isValid()) { - qWarning("QString::contains: invalid QRegularExpression object"); - return false; - } - QRegularExpressionMatch match = re.match(*this); - return match.hasMatch(); + return contains(re, Q_NULLPTR); } /*! @@ -3744,13 +3816,13 @@ bool QString::contains(const QRegularExpression &re) const bool QString::contains(const QRegularExpression &re, QRegularExpressionMatch *match) const { if (!re.isValid()) { - qWarning("QString::contains: invalid QRegularExpresssion object"); + qWarning("QString::contains: invalid QRegularExpression object"); return false; } QRegularExpressionMatch m = re.match(*this); bool hasMatch = m.hasMatch(); if (hasMatch && match) - *match = m; + *match = qMove(m); return hasMatch; } @@ -3909,12 +3981,14 @@ QString QString::section(const QString &sep, int start, int end, SectionFlags fl #if !(defined(QT_NO_REGEXP) && defined(QT_NO_REGULAREXPRESSION)) class qt_section_chunk { public: - qt_section_chunk(int l, QString s) { length = l; string = s; } + qt_section_chunk() {} + qt_section_chunk(int l, QString s) : length(l), string(qMove(s)) {} int length; QString string; }; +Q_DECLARE_TYPEINFO(qt_section_chunk, Q_MOVABLE_TYPE); -static QString extractSections(const QList<qt_section_chunk> §ions, +static QString extractSections(const QVector<qt_section_chunk> §ions, int start, int end, QString::SectionFlags flags) @@ -3982,7 +4056,7 @@ QString QString::section(const QRegExp ®, int start, int end, SectionFlags fl sep.setCaseSensitivity((flags & SectionCaseInsensitiveSeps) ? Qt::CaseInsensitive : Qt::CaseSensitive); - QList<qt_section_chunk> sections; + QVector<qt_section_chunk> sections; int n = length(), m = 0, last_m = 0, last_len = 0; while ((m = sep.indexIn(*this, m)) != -1) { sections.append(qt_section_chunk(last_len, QString(uc + last_m, m - last_m))); @@ -4027,7 +4101,7 @@ QString QString::section(const QRegularExpression &re, int start, int end, Secti if (flags & SectionCaseInsensitiveSeps) sep.setPatternOptions(sep.patternOptions() | QRegularExpression::CaseInsensitiveOption); - QList<qt_section_chunk> sections; + QVector<qt_section_chunk> sections; int n = length(), m = 0, last_m = 0, last_len = 0; QRegularExpressionMatchIterator iterator = sep.globalMatch(*this); while (iterator.hasNext()) { @@ -4621,78 +4695,7 @@ QString& QString::setUnicode(const QChar *unicode, int size) */ QString QString::simplified() const { - if (d->size == 0) - return *this; - - const QChar * const start = reinterpret_cast<QChar *>(d->data()); - const QChar *from = start; - const QChar *fromEnd = start + d->size; - forever { - QChar ch = *from; - if (!ch.isSpace()) - break; - if (++from == fromEnd) { - // All-whitespace string - QStringDataPtr empty = { Data::allocate(0) }; - return QString(empty); - } - } - // This loop needs no underflow check, as we already determined that - // the string contains non-whitespace. If the string has exactly one - // non-whitespace, it will be checked twice - we can live with that. - while (fromEnd[-1].isSpace()) - fromEnd--; - // The rest of the function depends on the fact that we already know - // that the last character in the source is no whitespace. - const QChar *copyFrom = from; - int copyCount; - forever { - if (++from == fromEnd) { - // Only leading and/or trailing whitespace, if any at all - return mid(copyFrom - start, from - copyFrom); - } - QChar ch = *from; - if (!ch.isSpace()) - continue; - if (ch != QLatin1Char(' ')) { - copyCount = from - copyFrom; - break; - } - ch = *++from; - if (ch.isSpace()) { - copyCount = from - copyFrom - 1; - break; - } - } - // 'from' now points at the non-trailing whitespace which made the - // string not simplified in the first place. 'copyCount' is the number - // of already simplified characters - at least one, obviously - - // without a trailing space. - QString result((fromEnd - from) + copyCount, Qt::Uninitialized); - QChar *to = reinterpret_cast<QChar *>(result.d->data()); - ::memcpy(to, copyFrom, copyCount * 2); - to += copyCount; - fromEnd--; - QChar ch; - forever { - *to++ = QLatin1Char(' '); - do { - ch = *++from; - } while (ch.isSpace()); - if (from == fromEnd) - break; - do { - *to++ = ch; - ch = *++from; - if (from == fromEnd) - goto done; - } while (!ch.isSpace()); - - } - done: - *to++ = ch; - result.truncate(to - reinterpret_cast<QChar *>(result.d->data())); - return result; + return QStringAlgorithms<const QString>::simplified_helper(*this); } /*! @@ -4713,25 +4716,7 @@ QString QString::simplified() const */ QString QString::trimmed() const { - if (d->size == 0) - return *this; - const QChar *s = (const QChar*)d->data(); - if (!s->isSpace() && !s[d->size-1].isSpace()) - return *this; - int start = 0; - int end = d->size - 1; - while (start<=end && s[start].isSpace()) // skip white space from start - start++; - if (start <= end) { // only white space - while (end && s[end].isSpace()) // skip white space from end - end--; - } - int l = end - start + 1; - if (l <= 0) { - QStringDataPtr empty = { Data::allocate(0) }; - return QString(empty); - } - return QString(s + start, l); + return QStringAlgorithms<const QString>::trimmed_helper(*this); } /*! \fn const QChar QString::at(int position) const @@ -5498,6 +5483,8 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const } /*! + \fn QString QString::toLower() const + Returns a lowercase copy of the string. \snippet qstring/main.cpp 75 @@ -5508,132 +5495,118 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const \sa toUpper(), QLocale::toLower() */ -QString QString::toLower() const +namespace QUnicodeTables { +struct LowercaseTraits { - const ushort *p = d->data(); - if (!p) - return *this; + static signed short caseDiff(const Properties *prop) + { return prop->lowerCaseDiff; } + static bool caseSpecial(const Properties *prop) + { return prop->lowerCaseSpecial; } +}; - const ushort *e = p + d->size; - // this avoids out of bounds check in the loop - while (e != p && QChar::isHighSurrogate(*(e - 1))) - --e; +struct UppercaseTraits +{ + static signed short caseDiff(const Properties *prop) + { return prop->upperCaseDiff; } + static bool caseSpecial(const Properties *prop) + { return prop->upperCaseSpecial; } +}; - const QUnicodeTables::Properties *prop; - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - ushort high = *p++; - prop = qGetProp(QChar::surrogateToUcs4(high, *p)); +struct CasefoldTraits +{ + static signed short caseDiff(const Properties *prop) + { return prop->caseFoldDiff; } + static bool caseSpecial(const Properties *prop) + { return prop->caseFoldSpecial; } +}; + +template <typename Traits, typename T> +#ifdef Q_CC_MSVC +__declspec(noinline) +#elif defined(Q_CC_GNU) +__attribute__((noinline)) +#endif +static QString detachAndConvertCase(T &str, QStringIterator it) +{ + QString s = qMove(str); // will copy if T is const QString + QChar *pp = s.begin() + it.index(); // will detach if necessary + uint uc = it.nextUnchecked(); + forever { + const QUnicodeTables::Properties *prop = qGetProp(uc); + signed short caseDiff = Traits::caseDiff(prop); + + if (Q_UNLIKELY(Traits::caseSpecial(prop))) { + // slow path + const ushort *specialCase = specialCaseMap + caseDiff; + ushort length = *specialCase++; + int pos = pp - s.constBegin(); + s.replace(pos, 1, reinterpret_cast<const QChar *>(specialCase), length); + pp = const_cast<QChar *>(s.constBegin()) + pos + length; + } else if (QChar::requiresSurrogates(uc)) { + *pp++ = QChar::highSurrogate(uc + caseDiff); + *pp++ = QChar::lowSurrogate(uc + caseDiff); } else { - prop = qGetProp(*p); + *pp++ = QChar(uc + caseDiff); } - if (prop->lowerCaseDiff) { - if (QChar::isLowSurrogate(*p)) - --p; // safe; diff is 0 for surrogates - QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); - ushort *pp = s.d->data() + (p - d->data()); - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - *pp = *p++; - prop = qGetProp(QChar::surrogateToUcs4(*pp++, *p)); - } else { - prop = qGetProp(*p); - } - if (prop->lowerCaseSpecial) { - const ushort *specialCase = specialCaseMap + prop->lowerCaseDiff; - ushort length = *specialCase++; - int pos = pp - s.d->data(); - s.resize(s.d->size + length - 1); - pp = s.d->data() + pos; - while (length--) - *pp++ = *specialCase++; - } else { - *pp++ = *p + prop->lowerCaseDiff; - } - ++p; - } - - // this restores high surrogate parts eaten above, if any - while (e != d->data() + d->size) - *pp++ = *e++; + if (!it.hasNext()) return s; - } - ++p; + + uc = it.nextUnchecked(); } - return *this; } -/*! - Returns the case folded equivalent of the string. For most Unicode - characters this is the same as toLower(). -*/ -QString QString::toCaseFolded() const +template <typename Traits, typename T> +static QString convertCase(T &str) { - const ushort *p = d->data(); - if (!p) - return *this; + const QChar *p = str.constBegin(); + const QChar *e = p + str.size(); - const ushort *e = p + d->size; // this avoids out of bounds check in the loop - while (e != p && QChar::isHighSurrogate(*(e - 1))) + while (e != p && e[-1].isHighSurrogate()) --e; const QUnicodeTables::Properties *prop; - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - ushort high = *p++; - prop = qGetProp(QChar::surrogateToUcs4(high, *p)); - } else { - prop = qGetProp(*p); - } - if (prop->caseFoldDiff) { - if (QChar::isLowSurrogate(*p)) - --p; // safe; diff is 0 for surrogates - QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); - ushort *pp = s.d->data() + (p - d->data()); - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - *pp = *p++; - prop = qGetProp(QChar::surrogateToUcs4(*pp++, *p)); - } else { - prop = qGetProp(*p); - } - if (prop->caseFoldSpecial) { - const ushort *specialCase = specialCaseMap + prop->caseFoldDiff; - ushort length = *specialCase++; -#if 0 - int pos = pp - s.d->data; - s.resize(s.d->size + length - 1); - pp = s.d->data + pos; - while (length--) - *pp++ = *specialCase++; -#else - //### we currently don't support full case foldings - Q_ASSERT(length == 1); - Q_UNUSED(length) - *pp++ = *specialCase; -#endif - } else { - *pp++ = *p + prop->caseFoldDiff; - } - ++p; - } + QStringIterator it(p, e); + for ( ; it.hasNext(); it.advanceUnchecked()) { + prop = qGetProp(it.peekNextUnchecked()); + if (Traits::caseDiff(prop)) + return detachAndConvertCase<Traits>(str, it); + } + return qMove(str); +} +} // namespace QUnicodeTables - // this restores high surrogate parts eaten above, if any - while (e != d->data() + d->size) - *pp++ = *e++; +QString QString::toLower_helper(const QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::LowercaseTraits>(str); +} - return s; - } - ++p; - } - return *this; +QString QString::toLower_helper(QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::LowercaseTraits>(str); +} + +/*! + \fn QString QString::toCaseFolded() const + + Returns the case folded equivalent of the string. For most Unicode + characters this is the same as toLower(). +*/ + +QString QString::toCaseFolded_helper(const QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::CasefoldTraits>(str); +} + +QString QString::toCaseFolded_helper(QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::CasefoldTraits>(str); } /*! + \fn QString QString::toUpper() const + Returns an uppercase copy of the string. \snippet qstring/main.cpp 81 @@ -5643,63 +5616,18 @@ QString QString::toCaseFolded() const \sa toLower(), QLocale::toLower() */ -QString QString::toUpper() const -{ - const ushort *p = d->data(); - if (!p) - return *this; - - const ushort *e = p + d->size; - // this avoids out of bounds check in the loop - while (e != p && QChar::isHighSurrogate(*(e - 1))) - --e; - const QUnicodeTables::Properties *prop; - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - ushort high = *p++; - prop = qGetProp(QChar::surrogateToUcs4(high, *p)); - } else { - prop = qGetProp(*p); - } - if (prop->upperCaseDiff) { - if (QChar::isLowSurrogate(*p)) - --p; // safe; diff is 0 for surrogates - QString s(d->size, Qt::Uninitialized); - memcpy(s.d->data(), d->data(), (p - d->data())*sizeof(ushort)); - ushort *pp = s.d->data() + (p - d->data()); - while (p != e) { - if (QChar::isHighSurrogate(*p) && QChar::isLowSurrogate(p[1])) { - *pp = *p++; - prop = qGetProp(QChar::surrogateToUcs4(*pp++, *p)); - } else { - prop = qGetProp(*p); - } - if (prop->upperCaseSpecial) { - const ushort *specialCase = specialCaseMap + prop->upperCaseDiff; - ushort length = *specialCase++; - int pos = pp - s.d->data(); - s.resize(s.d->size + length - 1); - pp = s.d->data() + pos; - while (length--) - *pp++ = *specialCase++; - } else { - *pp++ = *p + prop->upperCaseDiff; - } - ++p; - } - - // this restores high surrogate parts eaten above, if any - while (e != d->data() + d->size) - *pp++ = *e++; +QString QString::toUpper_helper(const QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::UppercaseTraits>(str); +} - return s; - } - ++p; - } - return *this; +QString QString::toUpper_helper(QString &str) +{ + return QUnicodeTables::convertCase<QUnicodeTables::UppercaseTraits>(str); } + // ### Qt 6: Consider whether this function shouldn't be removed See task 202871. /*! Safely builds a formatted string from the format string \a cformat @@ -9826,20 +9754,15 @@ QVector<uint> QStringRef::toUcs4() const */ QStringRef QStringRef::trimmed() const { - if (m_size == 0 || m_string == 0) + const QChar *begin = cbegin(); + const QChar *end = cend(); + QStringAlgorithms<const QStringRef>::trimmed_helper_positions(begin, end); + if (begin == cbegin() && end == cend()) return *this; - const QChar *s = m_string->constData() + m_position; - int start = 0; - int end = m_size - 1; - while (start <= end && s[start].isSpace()) // skip white space from start - start++; - if (start <= end) { // only white space - while (end && s[end].isSpace()) // skip white space from end - end--; - } - int l = end - start + 1; - Q_ASSERT(l >= 0); - return QStringRef(m_string, m_position + start, l); + if (begin == end) + return QStringRef(); + int position = m_position + (begin - cbegin()); + return QStringRef(m_string, position, end - begin); } /*! diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index a12946e23c..a84179e1e6 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -34,6 +34,10 @@ #ifndef QSTRING_H #define QSTRING_H +#if defined(QT_NO_CAST_FROM_ASCII) && defined(QT_RESTRICTED_CAST_FROM_ASCII) +#error QT_NO_CAST_FROM_ASCII and QT_RESTRICTED_CAST_FROM_ASCII must not be defined at the same time +#endif + #include <QtCore/qchar.h> #include <QtCore/qbytearray.h> #include <QtCore/qrefcount.h> @@ -93,7 +97,7 @@ public: inline bool operator>=(const QString &s) const; inline bool operator<=(const QString &s) const; -#ifndef QT_NO_CAST_FROM_ASCII +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN bool operator==(const char *s) const; inline QT_ASCII_CAST_WARN bool operator!=(const char *s) const; inline QT_ASCII_CAST_WARN bool operator<(const char *s) const; @@ -107,7 +111,7 @@ public: inline QT_ASCII_CAST_WARN bool operator>(const QByteArray &s) const; inline QT_ASCII_CAST_WARN bool operator<=(const QByteArray &s) const; inline QT_ASCII_CAST_WARN bool operator>=(const QByteArray &s) const; -#endif // QT_NO_CAST_FROM_ASCII +#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) private: int m_size; @@ -327,7 +331,9 @@ public: #ifndef QT_NO_REGULAREXPRESSION int indexOf(const QRegularExpression &re, int from = 0) const; + int indexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const; // ### Qt 6: merge overloads int lastIndexOf(const QRegularExpression &re, int from = -1) const; + int lastIndexOf(const QRegularExpression &re, int from, QRegularExpressionMatch *rmatch) const; // ### Qt 6: merge overloads bool contains(const QRegularExpression &re) const; bool contains(const QRegularExpression &re, QRegularExpressionMatch *match) const; // ### Qt 6: merge overloads int count(const QRegularExpression &re) const; @@ -369,9 +375,34 @@ public: QString leftJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT; QString rightJustified(int width, QChar fill = QLatin1Char(' '), bool trunc = false) const Q_REQUIRED_RESULT; +#if defined(Q_COMPILER_REF_QUALIFIERS) && !defined(QT_COMPILING_QSTRING_COMPAT_CPP) +# if defined(Q_CC_GNU) + // required due to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61941 +# pragma push_macro("Q_REQUIRED_RESULT") +# undef Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT +# define Q_REQUIRED_RESULT_pushed +# endif + QString toLower() const & Q_REQUIRED_RESULT + { return toLower_helper(*this); } + QString toLower() && Q_REQUIRED_RESULT + { return toLower_helper(*this); } + QString toUpper() const & Q_REQUIRED_RESULT + { return toUpper_helper(*this); } + QString toUpper() && Q_REQUIRED_RESULT + { return toUpper_helper(*this); } + QString toCaseFolded() const & Q_REQUIRED_RESULT + { return toCaseFolded_helper(*this); } + QString toCaseFolded() && Q_REQUIRED_RESULT + { return toCaseFolded_helper(*this); } +# ifdef Q_REQUIRED_RESULT_pushed +# pragma pop_macro("Q_REQUIRED_RESULT") +# endif +#else QString toLower() const Q_REQUIRED_RESULT; QString toUpper() const Q_REQUIRED_RESULT; QString toCaseFolded() const Q_REQUIRED_RESULT; +#endif QString trimmed() const Q_REQUIRED_RESULT; QString simplified() const Q_REQUIRED_RESULT; @@ -596,7 +627,16 @@ public: inline bool operator>=(QLatin1String s) const { return !operator<(s); } // ASCII compatibility -#ifndef QT_NO_CAST_FROM_ASCII +#if defined(QT_RESTRICTED_CAST_FROM_ASCII) + template <int N> + inline QString(const char (&ch)[N]) + : d(fromAscii_helper(ch, N - 1)) + {} + template <int N> + inline QString &operator=(const char (&ch)[N]) + { return (*this = fromLatin1(ch, N - 1)); } +#endif +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN QString(const char *ch) : d(fromAscii_helper(ch, ch ? int(strlen(ch)) : -1)) {} @@ -734,6 +774,12 @@ private: Qt::CaseSensitivity cs = Qt::CaseSensitive); static int localeAwareCompare_helper(const QChar *data1, int length1, const QChar *data2, int length2); + static QString toLower_helper(const QString &str); + static QString toLower_helper(QString &str); + static QString toUpper_helper(const QString &str); + static QString toUpper_helper(QString &str); + static QString toCaseFolded_helper(const QString &str); + static QString toCaseFolded_helper(QString &str); static Data *fromLatin1_helper(const char *str, int size = -1); static Data *fromAscii_helper(const char *str, int size = -1); static QString fromUtf8_helper(const char *str, int size); @@ -1083,7 +1129,7 @@ inline bool QLatin1String::operator>=(const QString &s) const inline bool QLatin1String::operator<=(const QString &s) const { return s >= *this; } -#ifndef QT_NO_CAST_FROM_ASCII +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline bool QString::operator==(const char *s) const { return QString::compare_helper(constData(), size(), s, -1) == 0; } inline bool QString::operator!=(const char *s) const @@ -1174,7 +1220,7 @@ inline bool QByteArray::operator<=(const QString &s) const { 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(), qstrnlen(constData(), size())) >= 0; } -#endif // QT_NO_CAST_FROM_ASCII +#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) #ifndef QT_NO_CAST_TO_ASCII inline QByteArray &QByteArray::append(const QString &s) @@ -1202,7 +1248,7 @@ inline const QString operator+(const QString &s1, QChar s2) { QString t(s1); t += s2; return t; } inline const QString operator+(QChar s1, const QString &s2) { QString t(s1); t += s2; return t; } -# ifndef QT_NO_CAST_FROM_ASCII +# if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN const QString operator+(const QString &s1, const char *s2) { QString t(s1); t += QString::fromUtf8(s2); return t; } inline QT_ASCII_CAST_WARN const QString operator+(const char *s1, const QString &s2) @@ -1355,7 +1401,7 @@ public: inline const QChar at(int i) const { Q_ASSERT(uint(i) < uint(size())); return m_string->at(i + m_position); } -#ifndef QT_NO_CAST_FROM_ASCII +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) // ASCII compatibility inline QT_ASCII_CAST_WARN bool operator==(const char *s) const; inline QT_ASCII_CAST_WARN bool operator!=(const char *s) const; @@ -1429,7 +1475,7 @@ inline bool operator<=(const QStringRef &s1, const QStringRef &s2) inline bool operator>=(const QStringRef &s1, const QStringRef &s2) { return !(s1 < s2); } -#ifndef QT_NO_CAST_FROM_ASCII +#if !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline QT_ASCII_CAST_WARN bool QStringRef::operator==(const char *s) const { return QString::compare_helper(constData(), size(), s, -1) == 0; } inline QT_ASCII_CAST_WARN bool QStringRef::operator!=(const char *s) const @@ -1455,7 +1501,7 @@ inline QT_ASCII_CAST_WARN bool operator>(const char *s1, const QStringRef &s2) { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) <= 0; } inline QT_ASCII_CAST_WARN bool operator>=(const char *s1, const QStringRef &s2) { return QString::compare_helper(s2.constData(), s2.size(), s1, -1) >= 0; } -#endif // QT_NO_CAST_FROM_ASCII +#endif // !defined(QT_NO_CAST_FROM_ASCII) && !defined(QT_RESTRICTED_CAST_FROM_ASCII) inline int QString::compare(const QStringRef &s, Qt::CaseSensitivity cs) const { return QString::compare_helper(constData(), length(), s.constData(), s.length(), cs); } diff --git a/src/corelib/tools/qstring_compat.cpp b/src/corelib/tools/qstring_compat.cpp index c776092569..bc48e3e5cf 100644 --- a/src/corelib/tools/qstring_compat.cpp +++ b/src/corelib/tools/qstring_compat.cpp @@ -31,16 +31,32 @@ ** ****************************************************************************/ -#if defined(QSTRING_H) +#if defined(QSTRING_H) || defined(QBYTEARRAY_H) # error "This file cannot be compiled with pre-compiled headers" #endif #define QT_COMPILING_QSTRING_COMPAT_CPP +#include "qbytearray.h" #include "qstring.h" QT_BEGIN_NAMESPACE // all these implementations must be the same as the inline versions in qstring.h +QString QString::toLower() const +{ + return toLower_helper(*this); +} + +QString QString::toCaseFolded() const +{ + return toCaseFolded_helper(*this); +} + +QString QString::toUpper() const +{ + return toUpper_helper(*this); +} + QByteArray QString::toLatin1() const { return toLatin1_helper(*this); @@ -56,4 +72,15 @@ QByteArray QString::toUtf8() const return toUtf8_helper(*this); } +// ditto, for qbytearray.h (because we're lazy) +QByteArray QByteArray::toLower() const +{ + return toLower_helper(*this); +} + +QByteArray QByteArray::toUpper() const +{ + return toUpper_helper(*this); +} + QT_END_NAMESPACE diff --git a/src/corelib/tools/qstringalgorithms_p.h b/src/corelib/tools/qstringalgorithms_p.h new file mode 100644 index 0000000000..5a68260c59 --- /dev/null +++ b/src/corelib/tools/qstringalgorithms_p.h @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Intel Corporation. +** Contact: http://www.qt-project.org/legal +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSTRINGALGORITHMS_P_H +#define QSTRINGALGORITHMS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include "qstring.h" +#include "qlocale_p.h" // for ascii_isspace + +QT_BEGIN_NAMESPACE + +template <typename StringType> struct QStringAlgorithms +{ + typedef typename StringType::value_type Char; + typedef typename StringType::size_type size_type; + typedef typename QtPrivate::remove_cv<StringType>::type NakedStringType; + static const bool isConst = QtPrivate::is_const<StringType>::value; + + static inline bool isSpace(char ch) { return ascii_isspace(ch); } + static inline bool isSpace(QChar ch) { return ch.isSpace(); } + + // Surrogate pairs are not handled in either of the functions below. That is + // not a problem because there are no space characters (Zs, Zl, Zp) outside the + // Basic Multilingual Plane. + + static inline void trimmed_helper_positions(const Char *&begin, const Char *&end) + { + // skip white space from start + while (begin < end && isSpace(*begin)) + begin++; + // skip white space from end + if (begin < end) { + while (begin < end && isSpace(end[-1])) + end--; + } + } + + static inline StringType trimmed_helper(StringType &str) + { + const Char *begin = str.cbegin(); + const Char *end = str.cend(); + trimmed_helper_positions(begin, end); + + if (begin == str.cbegin() && end == str.cend()) + return str; + if (begin == end) + return StringType(); + return StringType(begin, end - begin); + } + + static inline StringType simplified_helper(StringType &str) + { + if (str.isEmpty()) + return str; + const Char *src = str.cbegin(); + const Char *end = str.cend(); + NakedStringType result(str.size(), Qt::Uninitialized); + + Char *dst = const_cast<Char *>(result.cbegin()); + Char *ptr = dst; + forever { + while (src != end && isSpace(*src)) + ++src; + while (src != end && !isSpace(*src)) + *ptr++ = *src++; + if (src != end) + *ptr++ = QChar::Space; + else + break; + } + if (ptr != dst && ptr[-1] == QChar::Space) + --ptr; + + int newlen = ptr - dst; + if (newlen == str.size()) { + // nothing happened, return the original + return str; + } + result.resize(ptr - dst); + return qMove(result); + } +}; + +QT_END_NAMESPACE + +#endif // QSTRINGALGORITHMS_P_H diff --git a/src/corelib/tools/qstringiterator_p.h b/src/corelib/tools/qstringiterator_p.h index b80193b790..3f431daf6f 100644 --- a/src/corelib/tools/qstringiterator_p.h +++ b/src/corelib/tools/qstringiterator_p.h @@ -74,6 +74,11 @@ public: return pos; } + inline int index() const + { + return pos - i; + } + inline void setPosition(QString::const_iterator position) { Q_ASSERT_X(i <= position && position <= e, Q_FUNC_INFO, "position out of bounds"); diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 07c66bc393..bfc7f2380f 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -707,13 +707,10 @@ bool QVector<T>::operator==(const QVector<T> &v) const return true; if (d->size != v.d->size) return false; - T* b = d->begin(); - T* i = b + d->size; - T* j = v.d->end(); - while (i != b) - if (!(*--i == *--j)) - return false; - return true; + const T *vb = v.d->begin(); + const T *b = d->begin(); + const T *e = d->end(); + return std::equal(b, e, vb); } template <typename T> @@ -791,12 +788,9 @@ int QVector<T>::lastIndexOf(const T &t, int from) const template <typename T> bool QVector<T>::contains(const T &t) const { - T* b = d->begin(); - T* i = d->end(); - while (i != b) - if (*--i == t) - return true; - return false; + const T *b = d->begin(); + const T *e = d->end(); + return std::find(b, e, t) != e; } template <typename T> diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index af0ed228bd..2e77f683a4 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -57,6 +57,7 @@ HEADERS += \ tools/qsize.h \ tools/qstack.h \ tools/qstring.h \ + tools/qstringalgorithms_p.h \ tools/qstringbuilder.h \ tools/qstringiterator_p.h \ tools/qstringlist.h \ @@ -128,7 +129,8 @@ false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator OBJECTIVE_SOURCES += tools/qlocale_mac.mm \ tools/qtimezoneprivate_mac.mm \ tools/qstring_mac.mm \ - tools/qbytearray_mac.mm + tools/qbytearray_mac.mm \ + tools/qdatetime_mac.mm } else:blackberry { SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_blackberry.cpp tools/qtimezoneprivate_tz.cpp |