Optimize QDateTime string parsing

The patch reduces amount of allocations during
string parsing by using QStringRef. The operation
is safe as neither QDate nor QTime uses QString as
a storage type

Change-Id: Ib9f40d86e8e420653ac4fe8ba883d554331ffc32
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
bb10
Jędrzej Nowacki 2013-09-12 12:18:45 +00:00 committed by The Qt Project
parent 7c8131763d
commit 39262323d3
1 changed files with 31 additions and 11 deletions

View File

@ -1902,7 +1902,7 @@ int QTime::msecsTo(const QTime &t) const
#ifndef QT_NO_DATESTRING
static QTime fromIsoTimeString(const QString &string, Qt::DateFormat format, bool *isMidnight24)
static QTime fromIsoTimeString(const QStringRef &string, Qt::DateFormat format, bool *isMidnight24)
{
if (isMidnight24)
*isMidnight24 = false;
@ -1935,9 +1935,13 @@ static QTime fromIsoTimeString(const QString &string, Qt::DateFormat format, boo
// the maximum amount of millisecond digits it will expand to once converted to
// seconds is 4. E.g. 12:34,99999 will expand to 12:34:59.9994. The milliseconds
// will then be rounded up AND clamped to 999.
const float minuteFraction = QString::fromUtf8("0.%1").arg(string.mid(6, 5)).toFloat(&ok);
const QStringRef minuteFractionStr = string.mid(6, 5);
const long minuteFractionInt = minuteFractionStr.toLong(&ok);
if (!ok)
return QTime();
const float minuteFraction = double(minuteFractionInt) / (pow(double(10), minuteFractionStr.count()));
const float secondWithMs = minuteFraction * 60;
const float secondNoMs = std::floor(secondWithMs);
const float secondFraction = secondWithMs - secondNoMs;
@ -1949,9 +1953,11 @@ static QTime fromIsoTimeString(const QString &string, Qt::DateFormat format, boo
if (!ok)
return QTime();
if (size > 8 && (string.at(8) == QLatin1Char(',') || string.at(8) == QLatin1Char('.'))) {
const double secondFraction = QString::fromUtf8("0.%1").arg(string.mid(9, 4)).toDouble(&ok);
const QStringRef msecStr(string.mid(9, 4));
int msecInt = msecStr.isEmpty() ? 0 : msecStr.toInt(&ok);
if (!ok)
return QTime();
const double secondFraction(msecInt / (pow(double(10), msecStr.count())));
msec = qMin(qRound(secondFraction * 1000.0), 999);
}
}
@ -2001,7 +2007,7 @@ QTime QTime::fromString(const QString& string, Qt::DateFormat format)
case Qt::ISODate:
case Qt::TextDate:
default:
return fromIsoTimeString(string, format, 0);
return fromIsoTimeString(&string, format, 0);
}
}
@ -4383,26 +4389,40 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format)
if (size < 10)
return QDateTime();
QString isoString = string;
QStringRef isoString(&string);
Qt::TimeSpec spec = Qt::LocalTime;
QDate date = QDate::fromString(isoString.left(10), Qt::ISODate);
QDate date = QDate::fromString(string.left(10), Qt::ISODate);
if (!date.isValid())
return QDateTime();
if (size == 10)
return QDateTime(date);
isoString.remove(0, 11);
isoString = isoString.right(11);
int offset = 0;
// Check end of string for Time Zone definition, either Z for UTC or [+-]HH:MM for Offset
if (isoString.endsWith(QLatin1Char('Z'))) {
spec = Qt::UTC;
isoString.chop(1);
isoString = isoString.left(isoString.size() - 1);
} else {
const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
if (signIndex >= 0) {
// the loop below is faster but functionally equal to:
// const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]")));
const int sizeOfTimeZoneString = 4;
int signIndex = isoString.size() - sizeOfTimeZoneString - 1;
bool found = false;
{
const QChar plus = QLatin1Char('+');
const QChar minus = QLatin1Char('-');
do {
QChar character(isoString.at(signIndex));
found = character == plus || character == minus;
} while (--signIndex >= 0 && !found);
++signIndex;
}
if (found) {
bool ok;
offset = fromOffsetString(isoString.mid(signIndex), &ok);
offset = fromOffsetString(isoString.mid(signIndex).toString(), &ok);
if (!ok)
return QDateTime();
isoString = isoString.left(signIndex);