QDateTimePrivate: merge the time spec, DST status and validity flags

Storing them in a single byte is the first step towards the Short
QDateTime Optimization.

The bump in the "private version" by 10 is to accommodate possible
changes in the Qt 5.7 branch.

Change-Id: Id5480807d25e49e78b79ffff144a59420457bcf0
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
Thiago Macieira 2016-04-30 22:06:09 -07:00
parent 9466d0e633
commit 1a161c8ede
4 changed files with 66 additions and 71 deletions

View File

@ -67,7 +67,7 @@ quintptr Q_CORE_EXPORT qtHookData[] = {
// The required sizes and offsets are tested in tests/auto/other/toolsupport. // The required sizes and offsets are tested in tests/auto/other/toolsupport.
// When this fails and the change was intentional, adjust the test and // When this fails and the change was intentional, adjust the test and
// adjust this value here. // adjust this value here.
4 14
}; };
Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0])); Q_STATIC_ASSERT(QHooks::LastHookIndex == sizeof(qtHookData) / sizeof(qtHookData[0]));

View File

@ -2487,9 +2487,8 @@ static qint64 localMSecsToEpochMSecs(qint64 localMsecs,
QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
int offsetSeconds) int offsetSeconds)
: m_msecs(0), : m_msecs(0),
m_spec(Qt::LocalTime), m_status(0),
m_offsetFromUtc(0), m_offsetFromUtc(0)
m_status(0)
{ {
setTimeSpec(toSpec, offsetSeconds); setTimeSpec(toSpec, offsetSeconds);
setDateTime(toDate, toTime); setDateTime(toDate, toTime);
@ -2498,11 +2497,11 @@ QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt:
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime, QDateTimePrivate::QDateTimePrivate(const QDate &toDate, const QTime &toTime,
const QTimeZone &toTimeZone) const QTimeZone &toTimeZone)
: m_spec(Qt::TimeZone), : m_status(0),
m_offsetFromUtc(0), m_offsetFromUtc(0),
m_timeZone(toTimeZone), m_timeZone(toTimeZone)
m_status(0)
{ {
setSpec(Qt::TimeZone);
setDateTime(toDate, toTime); setDateTime(toDate, toTime);
} }
#endif // QT_BOOTSTRAPPED #endif // QT_BOOTSTRAPPED
@ -2519,21 +2518,21 @@ void QDateTimePrivate::setTimeSpec(Qt::TimeSpec spec, int offsetSeconds)
switch (spec) { switch (spec) {
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
if (offsetSeconds == 0) { if (offsetSeconds == 0) {
m_spec = Qt::UTC; setSpec(Qt::UTC);
m_offsetFromUtc = 0; m_offsetFromUtc = 0;
} else { } else {
m_spec = Qt::OffsetFromUTC; setSpec(Qt::OffsetFromUTC);
m_offsetFromUtc = offsetSeconds; m_offsetFromUtc = offsetSeconds;
} }
break; break;
case Qt::TimeZone: case Qt::TimeZone:
// Use system time zone instead // Use system time zone instead
m_spec = Qt::LocalTime; setSpec(Qt::LocalTime);
m_offsetFromUtc = 0; m_offsetFromUtc = 0;
break; break;
case Qt::UTC: case Qt::UTC:
case Qt::LocalTime: case Qt::LocalTime:
m_spec = spec; setSpec(spec);
m_offsetFromUtc = 0; m_offsetFromUtc = 0;
break; break;
} }
@ -2564,7 +2563,8 @@ void QDateTimePrivate::setDateTime(const QDate &date, const QTime &time)
// Set msecs serial value // Set msecs serial value
m_msecs = (days * MSECS_PER_DAY) + ds; m_msecs = (days * MSECS_PER_DAY) + ds;
m_status = newStatus; m_status &= ~(ValidityMask | DaylightMask);
m_status |= newStatus;
// Set if date and time are valid // Set if date and time are valid
checkValidDateTime(); checkValidDateTime();
@ -2587,14 +2587,11 @@ QPair<QDate, QTime> QDateTimePrivate::getDateTime() const
// Set the Daylight Status if LocalTime set via msecs // Set the Daylight Status if LocalTime set via msecs
void QDateTimePrivate::setDaylightStatus(QDateTimePrivate::DaylightStatus status) void QDateTimePrivate::setDaylightStatus(QDateTimePrivate::DaylightStatus status)
{ {
clearSetToDaylightStatus();
if (status == DaylightTime) { if (status == DaylightTime) {
m_status = m_status & ~SetToStandardTime;
m_status = m_status | SetToDaylightTime; m_status = m_status | SetToDaylightTime;
} else if (status == StandardTime) { } else if (status == StandardTime) {
m_status = m_status & ~SetToDaylightTime;
m_status = m_status | SetToStandardTime; m_status = m_status | SetToStandardTime;
} else {
clearSetToDaylightStatus();
} }
} }
@ -2610,7 +2607,7 @@ QDateTimePrivate::DaylightStatus QDateTimePrivate::daylightStatus() const
qint64 QDateTimePrivate::toMSecsSinceEpoch() const qint64 QDateTimePrivate::toMSecsSinceEpoch() const
{ {
switch (m_spec) { switch (spec()) {
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
case Qt::UTC: case Qt::UTC:
return (m_msecs - (m_offsetFromUtc * 1000)); return (m_msecs - (m_offsetFromUtc * 1000));
@ -2635,7 +2632,7 @@ qint64 QDateTimePrivate::toMSecsSinceEpoch() const
// Check the UTC / offsetFromUTC validity // Check the UTC / offsetFromUTC validity
void QDateTimePrivate::checkValidDateTime() void QDateTimePrivate::checkValidDateTime()
{ {
switch (m_spec) { switch (spec()) {
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
case Qt::UTC: case Qt::UTC:
// for these, a valid date and a valid time imply a valid QDateTime // for these, a valid date and a valid time imply a valid QDateTime
@ -2656,7 +2653,7 @@ void QDateTimePrivate::checkValidDateTime()
// Refresh the LocalTime validity and offset // Refresh the LocalTime validity and offset
void QDateTimePrivate::refreshDateTime() void QDateTimePrivate::refreshDateTime()
{ {
switch (m_spec) { switch (spec()) {
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
case Qt::UTC: case Qt::UTC:
// Always set by setDateTime so just return // Always set by setDateTime so just return
@ -2675,7 +2672,7 @@ void QDateTimePrivate::refreshDateTime()
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
// If not valid time zone then is invalid // If not valid time zone then is invalid
if (m_spec == Qt::TimeZone && !m_timeZone.isValid()) { if (spec() == Qt::TimeZone && !m_timeZone.isValid()) {
clearValidDateTime(); clearValidDateTime();
m_offsetFromUtc = 0; m_offsetFromUtc = 0;
return; return;
@ -2688,7 +2685,7 @@ void QDateTimePrivate::refreshDateTime()
QDate testDate; QDate testDate;
QTime testTime; QTime testTime;
qint64 epochMSecs = 0; qint64 epochMSecs = 0;
if (m_spec == Qt::LocalTime) { if (spec() == Qt::LocalTime) {
DaylightStatus status = daylightStatus(); DaylightStatus status = daylightStatus();
epochMSecs = localMSecsToEpochMSecs(m_msecs, &status, &testDate, &testTime); epochMSecs = localMSecsToEpochMSecs(m_msecs, &status, &testDate, &testTime);
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
@ -3038,7 +3035,7 @@ QTime QDateTime::time() const
Qt::TimeSpec QDateTime::timeSpec() const Qt::TimeSpec QDateTime::timeSpec() const
{ {
return d->m_spec; return d->spec();
} }
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
@ -3056,7 +3053,7 @@ Qt::TimeSpec QDateTime::timeSpec() const
QTimeZone QDateTime::timeZone() const QTimeZone QDateTime::timeZone() const
{ {
switch (d->m_spec) { switch (d->spec()) {
case Qt::UTC: case Qt::UTC:
return QTimeZone::utc(); return QTimeZone::utc();
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
@ -3117,7 +3114,7 @@ int QDateTime::offsetFromUtc() const
QString QDateTime::timeZoneAbbreviation() const QString QDateTime::timeZoneAbbreviation() const
{ {
switch (d->m_spec) { switch (d->spec()) {
case Qt::UTC: case Qt::UTC:
return QTimeZonePrivate::utcQString(); return QTimeZonePrivate::utcQString();
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
@ -3151,7 +3148,7 @@ QString QDateTime::timeZoneAbbreviation() const
bool QDateTime::isDaylightTime() const bool QDateTime::isDaylightTime() const
{ {
switch (d->m_spec) { switch (d->spec()) {
case Qt::UTC: case Qt::UTC:
case Qt::OffsetFromUTC: case Qt::OffsetFromUTC:
return false; return false;
@ -3261,7 +3258,7 @@ void QDateTime::setOffsetFromUtc(int offsetSeconds)
void QDateTime::setTimeZone(const QTimeZone &toZone) void QDateTime::setTimeZone(const QTimeZone &toZone)
{ {
QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->m_spec = Qt::TimeZone; d->setSpec(Qt::TimeZone);
d->m_offsetFromUtc = 0; d->m_offsetFromUtc = 0;
d->m_timeZone = toZone; d->m_timeZone = toZone;
d->refreshDateTime(); d->refreshDateTime();
@ -3338,8 +3335,8 @@ void QDateTime::setMSecsSinceEpoch(qint64 msecs)
{ {
QDateTimePrivate *d = this->d.data(); // detaches (and shadows d) QDateTimePrivate *d = this->d.data(); // detaches (and shadows d)
d->m_status = 0; d->m_status &= ~QDateTimePrivate::ValidityMask;
switch (d->m_spec) { switch (d->spec()) {
case Qt::UTC: case Qt::UTC:
d->m_msecs = msecs; d->m_msecs = msecs;
d->m_status = d->m_status d->m_status = d->m_status
@ -3484,7 +3481,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
.arg(dt.year()); .arg(dt.year());
if (timeSpec() != Qt::LocalTime) { if (timeSpec() != Qt::LocalTime) {
buf += QStringLiteral(" GMT"); buf += QStringLiteral(" GMT");
if (d->m_spec == Qt::OffsetFromUTC) if (d->spec() == Qt::OffsetFromUTC)
buf += toOffsetString(Qt::TextDate, d->m_offsetFromUtc); buf += toOffsetString(Qt::TextDate, d->m_offsetFromUtc);
} }
return buf; return buf;
@ -3499,7 +3496,7 @@ QString QDateTime::toString(Qt::DateFormat format) const
return QString(); // failed to convert return QString(); // failed to convert
buf += QLatin1Char('T'); buf += QLatin1Char('T');
buf += tm.toString(Qt::ISODate); buf += tm.toString(Qt::ISODate);
switch (d->m_spec) { switch (d->spec()) {
case Qt::UTC: case Qt::UTC:
buf += QLatin1Char('Z'); buf += QLatin1Char('Z');
break; break;
@ -3648,7 +3645,7 @@ QDateTime QDateTime::addDays(qint64 ndays) const
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
date = date.addDays(ndays); date = date.addDays(ndays);
MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); MASSAGEADJUSTEDDATETIME(d->spec(), d->m_timeZone, &date, &time);
dt.d->setDateTime(date, time); dt.d->setDateTime(date, time);
return dt; return dt;
} }
@ -3674,7 +3671,7 @@ QDateTime QDateTime::addMonths(int nmonths) const
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
date = date.addMonths(nmonths); date = date.addMonths(nmonths);
MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); MASSAGEADJUSTEDDATETIME(d->spec(), d->m_timeZone, &date, &time);
dt.d->setDateTime(date, time); dt.d->setDateTime(date, time);
return dt; return dt;
} }
@ -3700,7 +3697,7 @@ QDateTime QDateTime::addYears(int nyears) const
QDate &date = p.first; QDate &date = p.first;
QTime &time = p.second; QTime &time = p.second;
date = date.addYears(nyears); date = date.addYears(nyears);
MASSAGEADJUSTEDDATETIME(d->m_spec, d->m_timeZone, &date, &time); MASSAGEADJUSTEDDATETIME(d->spec(), d->m_timeZone, &date, &time);
dt.d->setDateTime(date, time); dt.d->setDateTime(date, time);
return dt; return dt;
} }
@ -3736,12 +3733,12 @@ QDateTime QDateTime::addMSecs(qint64 msecs) const
return QDateTime(); return QDateTime();
QDateTime dt(*this); QDateTime dt(*this);
if (d->m_spec == Qt::LocalTime || d->m_spec == Qt::TimeZone) if (d->spec() == Qt::LocalTime || d->spec() == Qt::TimeZone)
// Convert to real UTC first in case crosses DST transition // Convert to real UTC first in case crosses DST transition
dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs); dt.setMSecsSinceEpoch(d->toMSecsSinceEpoch() + msecs);
else else
// No need to convert, just add on // No need to convert, just add on
dt.d->m_msecs = dt.d->m_msecs + msecs; dt.d->m_msecs += msecs;
return dt; return dt;
} }
@ -3830,7 +3827,7 @@ qint64 QDateTime::msecsTo(const QDateTime &other) const
QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
{ {
if (d->m_spec == spec && (spec == Qt::UTC || spec == Qt::LocalTime)) if (d->spec() == spec && (spec == Qt::UTC || spec == Qt::LocalTime))
return *this; return *this;
if (!isValid()) { if (!isValid()) {
@ -3857,7 +3854,7 @@ QDateTime QDateTime::toTimeSpec(Qt::TimeSpec spec) const
QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
{ {
if (d->m_spec == Qt::OffsetFromUTC && d->m_offsetFromUtc == offsetSeconds) if (d->spec() == Qt::OffsetFromUTC && d->m_offsetFromUtc == offsetSeconds)
return *this; return *this;
if (!isValid()) { if (!isValid()) {
@ -3880,7 +3877,7 @@ QDateTime QDateTime::toOffsetFromUtc(int offsetSeconds) const
QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
{ {
if (d->m_spec == Qt::TimeZone && d->m_timeZone == timeZone) if (d->spec() == Qt::TimeZone && d->m_timeZone == timeZone)
return *this; return *this;
if (!isValid()) { if (!isValid()) {
@ -3902,8 +3899,8 @@ QDateTime QDateTime::toTimeZone(const QTimeZone &timeZone) const
bool QDateTime::operator==(const QDateTime &other) const bool QDateTime::operator==(const QDateTime &other) const
{ {
if (d->m_spec == Qt::LocalTime if (d->spec() == Qt::LocalTime
&& other.d->m_spec == Qt::LocalTime && other.d->spec() == Qt::LocalTime
&& d->m_status == other.d->m_status) { && d->m_status == other.d->m_status) {
return (d->m_msecs == other.d->m_msecs); return (d->m_msecs == other.d->m_msecs);
} }
@ -3930,8 +3927,8 @@ bool QDateTime::operator==(const QDateTime &other) const
bool QDateTime::operator<(const QDateTime &other) const bool QDateTime::operator<(const QDateTime &other) const
{ {
if (d->m_spec == Qt::LocalTime if (d->spec() == Qt::LocalTime
&& other.d->m_spec == Qt::LocalTime && other.d->spec() == Qt::LocalTime
&& d->m_status == other.d->m_status) { && d->m_status == other.d->m_status) {
return (d->m_msecs < other.d->m_msecs); return (d->m_msecs < other.d->m_msecs);
} }

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2016 The Qt Company Ltd. ** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/ ** Contact: https://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -83,21 +84,30 @@ public:
// Status of date/time // Status of date/time
enum StatusFlag { enum StatusFlag {
NullDate = 0x01, ShortData = 0x01,
NullTime = 0x02,
ValidDate = 0x04, // just the date field ValidDate = 0x02,
ValidTime = 0x08, // just the time field ValidTime = 0x04,
ValidDateTime = 0x10, // the whole object (including timezone) ValidDateTime = 0x08,
TimeSpecMask = 0x30,
SetToStandardTime = 0x40, SetToStandardTime = 0x40,
SetToDaylightTime = 0x80 SetToDaylightTime = 0x80
}; };
Q_DECLARE_FLAGS(StatusFlags, StatusFlag) Q_DECLARE_FLAGS(StatusFlags, StatusFlag)
enum {
TimeSpecShift = 4,
ValidityMask = ValidDate | ValidTime | ValidDateTime,
DaylightMask = SetToStandardTime | SetToDaylightTime
};
QDateTimePrivate() : m_msecs(0), QDateTimePrivate() : m_msecs(0),
m_spec(Qt::LocalTime), m_status(StatusFlag(Qt::LocalTime << TimeSpecShift)),
m_offsetFromUtc(0), m_offsetFromUtc(0)
m_status(NullDate | NullTime) {
{} }
QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec, QDateTimePrivate(const QDate &toDate, const QTime &toTime, Qt::TimeSpec toSpec,
int offsetSeconds); int offsetSeconds);
@ -110,12 +120,11 @@ public:
// 4 bytes padding // 4 bytes padding
qint64 m_msecs; qint64 m_msecs;
Qt::TimeSpec m_spec; StatusFlags m_status;
int m_offsetFromUtc; int m_offsetFromUtc;
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
QTimeZone m_timeZone; QTimeZone m_timeZone;
#endif // QT_BOOTSTRAPPED #endif // QT_BOOTSTRAPPED
StatusFlags m_status;
void setTimeSpec(Qt::TimeSpec spec, int offsetSeconds); void setTimeSpec(Qt::TimeSpec spec, int offsetSeconds);
void setDateTime(const QDate &date, const QTime &time); void setDateTime(const QDate &date, const QTime &time);
@ -140,6 +149,10 @@ public:
inline void clearValidDateTime() { m_status &= ~ValidDateTime; } inline void clearValidDateTime() { m_status &= ~ValidDateTime; }
inline void clearSetToDaylightStatus() { m_status &= ~(SetToStandardTime | SetToDaylightTime); } inline void clearSetToDaylightStatus() { m_status &= ~(SetToStandardTime | SetToDaylightTime); }
inline Qt::TimeSpec spec() const { return Qt::TimeSpec((m_status & TimeSpecMask) >> TimeSpecShift); }
inline void setSpec(Qt::TimeSpec spec)
{ m_status &= ~TimeSpecMask; m_status |= StatusFlag(uint(spec) << TimeSpecShift); }
#ifndef QT_BOOTSTRAPPED #ifndef QT_BOOTSTRAPPED
static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone, static qint64 zoneMSecsToEpochMSecs(qint64 msecs, const QTimeZone &zone,
QDate *localDate = 0, QTime *localTime = 0); QDate *localDate = 0, QTime *localTime = 0);

View File

@ -129,29 +129,14 @@ void tst_toolsupport::offsets_data()
#endif #endif
{ {
#ifdef Q_OS_WIN
QTest::newRow("QDateTimePrivate::m_msecs") QTest::newRow("QDateTimePrivate::m_msecs")
<< pmm_to_offsetof(&QDateTimePrivate::m_msecs) << 8 << 8; << pmm_to_offsetof(&QDateTimePrivate::m_msecs) << 0 << 0;
QTest::newRow("QDateTimePrivate::m_spec")
<< pmm_to_offsetof(&QDateTimePrivate::m_spec) << 16 << 16;
QTest::newRow("QDateTimePrivate::m_offsetFromUtc")
<< pmm_to_offsetof(&QDateTimePrivate::m_offsetFromUtc) << 20 << 20;
QTest::newRow("QDateTimePrivate::m_timeZone")
<< pmm_to_offsetof(&QDateTimePrivate::m_timeZone) << 24 << 24;
QTest::newRow("QDateTimePrivate::m_status") QTest::newRow("QDateTimePrivate::m_status")
<< pmm_to_offsetof(&QDateTimePrivate::m_status) << 28 << 32; << pmm_to_offsetof(&QDateTimePrivate::m_status) << 8 << 8;
#else
QTest::newRow("QDateTimePrivate::m_msecs")
<< pmm_to_offsetof(&QDateTimePrivate::m_msecs) << 4 << 8;
QTest::newRow("QDateTimePrivate::m_spec")
<< pmm_to_offsetof(&QDateTimePrivate::m_spec) << 12 << 16;
QTest::newRow("QDateTimePrivate::m_offsetFromUtc") QTest::newRow("QDateTimePrivate::m_offsetFromUtc")
<< pmm_to_offsetof(&QDateTimePrivate::m_offsetFromUtc) << 16 << 20; << pmm_to_offsetof(&QDateTimePrivate::m_offsetFromUtc) << 12 << 12;
QTest::newRow("QDateTimePrivate::m_timeZone") QTest::newRow("QDateTimePrivate::m_timeZone")
<< pmm_to_offsetof(&QDateTimePrivate::m_timeZone) << 20 << 24; << pmm_to_offsetof(&QDateTimePrivate::m_timeZone) << 20 << 24;
QTest::newRow("QDateTimePrivate::m_status")
<< pmm_to_offsetof(&QDateTimePrivate::m_status) << 24 << 32;
#endif
} }
#endif // RUN_MEMBER_OFFSET_TEST #endif // RUN_MEMBER_OFFSET_TEST
} }