diff options
Diffstat (limited to 'src/corelib/tools')
-rw-r--r-- | src/corelib/tools/qbytearray.cpp | 179 | ||||
-rw-r--r-- | src/corelib/tools/qbytearray.h | 25 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime.cpp | 68 | ||||
-rw-r--r-- | src/corelib/tools/qdatetime_p.h | 3 | ||||
-rw-r--r-- | src/corelib/tools/qeasingcurve.cpp | 87 | ||||
-rw-r--r-- | src/corelib/tools/qhash.cpp | 4 | ||||
-rw-r--r-- | src/corelib/tools/qregularexpression.cpp | 131 | ||||
-rw-r--r-- | src/corelib/tools/qregularexpression.h | 10 | ||||
-rw-r--r-- | src/corelib/tools/qstring.cpp | 453 | ||||
-rw-r--r-- | src/corelib/tools/qstring.h | 33 | ||||
-rw-r--r-- | src/corelib/tools/qstring_compat.cpp | 29 | ||||
-rw-r--r-- | src/corelib/tools/qstringalgorithms_p.h | 135 | ||||
-rw-r--r-- | src/corelib/tools/qstringiterator_p.h | 5 | ||||
-rw-r--r-- | src/corelib/tools/tools.pri | 1 |
14 files changed, 707 insertions, 456 deletions
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/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 66d2ad9111..3acde53208 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) @@ -4351,7 +4351,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 +4443,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 +4463,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 +4482,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 +4517,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 +4532,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 +4557,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 +4987,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_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/qregularexpression.cpp b/src/corelib/tools/qregularexpression.cpp index cf80d05153..cd7b375c8f 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..2067605646 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 @@ -3664,14 +3665,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 +3716,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 +3768,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 +3788,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 +3953,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 +4028,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 +4073,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 +4667,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 +4688,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 +5455,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 +5467,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 +5588,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 +9726,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 f54ac0f277..ddee6e9fc0 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -327,7 +327,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 +371,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; @@ -734,6 +761,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); 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/tools.pri b/src/corelib/tools/tools.pri index af0ed228bd..adda91b739 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 \ |