summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools')
-rw-r--r--src/corelib/tools/qbytearray.cpp179
-rw-r--r--src/corelib/tools/qbytearray.h25
-rw-r--r--src/corelib/tools/qdatetime.cpp68
-rw-r--r--src/corelib/tools/qdatetime_p.h3
-rw-r--r--src/corelib/tools/qeasingcurve.cpp87
-rw-r--r--src/corelib/tools/qhash.cpp4
-rw-r--r--src/corelib/tools/qregularexpression.cpp131
-rw-r--r--src/corelib/tools/qregularexpression.h10
-rw-r--r--src/corelib/tools/qstring.cpp453
-rw-r--r--src/corelib/tools/qstring.h33
-rw-r--r--src/corelib/tools/qstring_compat.cpp29
-rw-r--r--src/corelib/tools/qstringalgorithms_p.h135
-rw-r--r--src/corelib/tools/qstringiterator_p.h5
-rw-r--r--src/corelib/tools/tools.pri1
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> &sections,
+static QString extractSections(const QVector<qt_section_chunk> &sections,
int start,
int end,
QString::SectionFlags flags)
@@ -3982,7 +4028,7 @@ QString QString::section(const QRegExp &reg, 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 \