From f9b8ea4b0eaea94a6d724a0955b13fd8a97d96e3 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 6 Dec 2016 13:44:00 +0100 Subject: Fix QMacTimeZonePrivate::previousTransition() for early after epoch The native APIs don't support previous transition, only next after a stipulated date. The prior code started its search at the epoch; if used for a time before the first transition after the epoch, this found no transitions so returned invalid data, when the last transition before the epoch would have been suitable. It also wound through all transitions since the epoch, on its way to the selected time, which was potentially laborious. Instead, start a year before the stipulated time; this should get a transition if the zone uses DST. If it doesn't, start with the first known transition and binary-chop our way to one within a year of the last before the stipulated time; then wind forward one transition at a time, as before. The chopping is actually faster than binary: each time we find a transition after the interval mid-point but early enough, we move the early end of our interval to the transition, which is later than the old interval's middle. Using halving, starting with a vast interval, should thus only incur modest cost, while ensuring we give up early when no transition data is available at all or the zone's first transition ever was after the stipulated time. Task-number: QTBUG-65443 Change-Id: I96c14540fc2600837e6a22e480fb8dc36cb37220 (cherry picked from commit 7c0b706488b0edcc2fd6db7870db700ff0548f21) (cherry picked from commit a090076e93487f8e461d9b866b9da1c0c21cb59b) Reviewed-by: Andy Shaw Reviewed-by: Jason Dolan --- src/corelib/tools/qtimezoneprivate_mac.mm | 88 ++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 18 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qtimezoneprivate_mac.mm b/src/corelib/tools/qtimezoneprivate_mac.mm index 4e9a432fbf..fa0dd87cfc 100644 --- a/src/corelib/tools/qtimezoneprivate_mac.mm +++ b/src/corelib/tools/qtimezoneprivate_mac.mm @@ -226,27 +226,79 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSecsSinceEpoch) const { - // No direct Mac API, so get all transitions since epoch and return the last one - QList secsList; - if (beforeMSecsSinceEpoch > 0) { - const int endSecs = beforeMSecsSinceEpoch / 1000.0; - NSTimeInterval prevSecs = 0; - NSTimeInterval nextSecs = 0; - NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs]; - // If invalid may return a nil date or an Epoch date + // The native API only lets us search forward, so we need to find an early-enough start: + const NSTimeInterval lowerBound = std::numeric_limits::min(); + const qint64 endSecs = beforeMSecsSinceEpoch / 1000; + const int year = 366 * 24 * 3600; // a (long) year, in seconds + NSTimeInterval prevSecs = endSecs; // sentinel for later check + NSTimeInterval nextSecs = prevSecs - year; + NSTimeInterval tranSecs = lowerBound; // time at a transition; may be > endSecs + + NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs]; + nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; + if (nextDate != nil + && (tranSecs = [nextDate timeIntervalSince1970]) < endSecs) { + // There's a transition within the last year before endSecs: + nextSecs = tranSecs; + } else { + // Need to start our search earlier: + nextDate = [NSDate dateWithTimeIntervalSince1970:lowerBound]; nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; - nextSecs = [nextDate timeIntervalSince1970]; - while (nextDate != nil && nextSecs > prevSecs && nextSecs < endSecs) { - secsList.append(nextSecs); - prevSecs = nextSecs; - nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; + if (nextDate != nil) { + NSTimeInterval lateSecs = nextSecs; nextSecs = [nextDate timeIntervalSince1970]; - } + Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs); + /* + We're looking at the first ever transition for our zone, at + nextSecs (and our zone *does* have at least one transition). If + it's later than endSecs - year, then we must have found it on the + initial check and therefore set tranSecs to the same transition + time (which, we can infer here, is >= endSecs). In this case, we + won't enter the binary-chop loop, below. + + In the loop, nextSecs < lateSecs < endSecs: we have a transition + at nextSecs and there is no transition between lateSecs and + endSecs. The loop narrows the interval between nextSecs and + lateSecs by looking for a transition after their mid-point; if it + finds one < endSecs, nextSecs moves to this transition; otherwise, + lateSecs moves to the mid-point. This soon enough narrows the gap + to within a year, after which walking forward one transition at a + time (the "Wind through" loop, below) is good enough. + */ + + // Binary chop to within a year of last transition before endSecs: + while (nextSecs + year < lateSecs) { + // Careful about overflow, not fussy about rounding errors: + NSTimeInterval middle = nextSecs / 2 + lateSecs / 2; + NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle]; + split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split]; + if (split != nil + && (tranSecs = [split timeIntervalSince1970]) < endSecs) { + nextDate = split; + nextSecs = tranSecs; + } else { + lateSecs = middle; + } + } + Q_ASSERT(nextDate != nil); + // ... and nextSecs < endSecs unless first transition ever was >= endSecs. + } // else: we have no data - prevSecs is still endSecs, nextDate is still nil } - if (secsList.size() >= 1) - return data(qint64(secsList.constLast()) * 1000); - else - return invalidData(); + // Either nextDate is nil or nextSecs is at its transition. + + // Wind through remaining transitions (spanning at most a year), one at a time: + while (nextDate != nil && nextSecs < endSecs) { + prevSecs = nextSecs; + nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; + nextSecs = [nextDate timeIntervalSince1970]; + if (nextSecs <= prevSecs) // presumably no later data available + break; + } + if (prevSecs < endSecs) // i.e. we did make it into that while loop + return data(qint64(prevSecs * 1e3)); + + // No transition data; or first transition later than requested time. + return invalidData(); } QByteArray QMacTimeZonePrivate::systemTimeZoneId() const -- cgit v1.2.3 From 6d50f746fe05a7008b63818e77784dd0c99270a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Otto=20Ryyn=C3=A4nen?= Date: Fri, 2 Jun 2017 12:53:23 +0300 Subject: Support for Q_OS_ANDROID_EMBEDDED and android-embedded build flags The Embedded Android build (Boot to Qt Android injection) is defined by having both Q_OS_ANDROID and Q_OS_ANDROID_EMBEDDED flags defined, as well as having Qt config android-embedded. This commit enables the possibility to build embedded Android builds. (i.e. Qt build for Android baselayer only, without JNI) Change-Id: I8406e959fdf1c8d9efebbbe53f1a391fa25f336a Reviewed-by: Oswald Buddenhagen Reviewed-by: Paul Olav Tvete --- src/corelib/tools/qsimd_p.h | 2 +- src/corelib/tools/qtimezone.cpp | 8 ++++---- src/corelib/tools/qtimezoneprivate_p.h | 6 +++--- src/corelib/tools/tools.pri | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 05f118a9eb..36c0a9097b 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -198,7 +198,7 @@ // SSE intrinsics #if defined(__SSE2__) || (defined(QT_COMPILER_SUPPORTS_SSE2) && defined(QT_COMPILER_SUPPORTS_SIMD_ALWAYS)) -#if defined(QT_LINUXBASE) +#if defined(QT_LINUXBASE) || defined(Q_OS_ANDROID_EMBEDDED) /// this is an evil hack - the posix_memalign declaration in LSB /// is wrong - see http://bugs.linuxbase.org/show_bug.cgi?id=2431 # define posix_memalign _lsb_hack_posix_memalign diff --git a/src/corelib/tools/qtimezone.cpp b/src/corelib/tools/qtimezone.cpp index c4cd76c59c..567c819813 100644 --- a/src/corelib/tools/qtimezone.cpp +++ b/src/corelib/tools/qtimezone.cpp @@ -62,9 +62,9 @@ static QTimeZonePrivate *newBackendTimeZone() #else #if defined Q_OS_MAC return new QMacTimeZonePrivate(); -#elif defined Q_OS_ANDROID +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) return new QAndroidTimeZonePrivate(); -#elif defined Q_OS_UNIX +#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED) return new QTzTimeZonePrivate(); // Registry based timezone backend not available on WinRT #elif defined Q_OS_WIN @@ -89,9 +89,9 @@ static QTimeZonePrivate *newBackendTimeZone(const QByteArray &ianaId) #else #if defined Q_OS_MAC return new QMacTimeZonePrivate(ianaId); -#elif defined Q_OS_ANDROID +#elif defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) return new QAndroidTimeZonePrivate(ianaId); -#elif defined Q_OS_UNIX +#elif defined(Q_OS_UNIX) || defined(Q_OS_ANDROID_EMBEDDED) return new QTzTimeZonePrivate(ianaId); // Registry based timezone backend not available on WinRT #elif defined Q_OS_WIN diff --git a/src/corelib/tools/qtimezoneprivate_p.h b/src/corelib/tools/qtimezoneprivate_p.h index 74b79dce16..83e06ffcb0 100644 --- a/src/corelib/tools/qtimezoneprivate_p.h +++ b/src/corelib/tools/qtimezoneprivate_p.h @@ -68,7 +68,7 @@ Q_FORWARD_DECLARE_OBJC_CLASS(NSTimeZone); #include #endif // Q_OS_WIN -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) #include #endif @@ -266,7 +266,7 @@ private: }; #endif -#if defined Q_OS_UNIX && !defined Q_OS_MAC && !defined Q_OS_ANDROID +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && (!defined(Q_OS_ANDROID) || defined(Q_OS_ANDROID_EMBEDDED)) struct QTzTransitionTime { qint64 atMSecsSinceEpoch; @@ -443,7 +443,7 @@ private: }; #endif // Q_OS_WIN -#ifdef Q_OS_ANDROID +#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED) class QAndroidTimeZonePrivate Q_DECL_FINAL : public QTimeZonePrivate { public: diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 7ba3ff4a8b..bea8e97435 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -158,7 +158,7 @@ qtConfig(timezone) { tools/qtimezoneprivate.cpp !nacl:darwin: \ SOURCES += tools/qtimezoneprivate_mac.mm - else: android: \ + else: android:!android-embedded: \ SOURCES += tools/qtimezoneprivate_android.cpp else: unix: \ SOURCES += tools/qtimezoneprivate_tz.cpp -- cgit v1.2.3 From d80b0eb12c477592b590b768e21dc26c137beadc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 9 Jan 2018 10:24:18 -0800 Subject: Doc: make a note about use of QStringLiteral with non-ASCII chars Both ICC and MSVC have bugs concatenating strings and that's despite the standard giving an example ([lex.string] table 9) that says that u"a" "b" is the same as u"ab" We can't change to preprocessor concatenation (u ## STR) because that fails when QStringLiteral is used with a macro instead of an actual string literal. Task-number: QTBUG-65479 Change-Id: I39332e0a867442d58082fffd1504a0a868c291ef Reviewed-by: Friedemann Kleint Reviewed-by: Thiago Macieira --- src/corelib/tools/qstring.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index c0a03e0011..aff384a257 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -10802,7 +10802,7 @@ QString QString::toHtmlEscaped() const This cost can be avoided by using QStringLiteral instead: \code - if (node.hasAttribute(QStringLiteral("http-contents-length"))) //... + if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //... \endcode In this case, QString's internal data will be generated at compile time; no @@ -10822,6 +10822,10 @@ QString QString::toHtmlEscaped() const if (attribute.name() == QLatin1String("http-contents-length")) //... \endcode + \note Some compilers have bugs encoding strings containing characters outside + the US-ASCII character set. Make sure you prefix your string with \c{u} in + those cases. It is optional otherwise. + \sa QByteArrayLiteral */ -- cgit v1.2.3 From b44df9937e4b15596b994f8e20822b83ac4bed29 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 30 Jan 2018 21:02:10 +0100 Subject: Clean-up in QDateTime's parsing of ISODate{,WithMs} Actually check that there's a T where ISO 8601 wants it (instead of just skipping over whatever's there), with something after it; move some declarations later; add some comments; and use the QStringRef API more cleanly (so that it's easier to see what's going on). Simplify a loop condition to avoid the need for a post-loop fix-up. This incidentally prevents an assertion failure (which brought the mess to my attention) parsing a short string as an ISO date-time; if there's a T with nothing after it, we won't try to read at index -1 in the following text. (The actual fail seen had a Z where the T should have been, with nothing after it.) Add tests for invalid ISOdate cases that triggered the assertion. Task-number: QTBUG-66076 Change-Id: Ided9adf62a56d98f144bdf91b40f918e22bd82cd Reviewed-by: Israel Lins Albuquerque Reviewed-by: Thiago Macieira (cherry picked from commit a9c111ed8c30a5a8fec3f02244f0d5a4bd08e931) --- src/corelib/tools/qdatetime.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qdatetime.cpp b/src/corelib/tools/qdatetime.cpp index 9d26207a0f..045ad10755 100644 --- a/src/corelib/tools/qdatetime.cpp +++ b/src/corelib/tools/qdatetime.cpp @@ -4720,25 +4720,35 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) if (size < 10) return QDateTime(); - QStringRef isoString(&string); - Qt::TimeSpec spec = Qt::LocalTime; - QDate date = QDate::fromString(string.left(10), Qt::ISODate); if (!date.isValid()) return QDateTime(); if (size == 10) return QDateTime(date); - isoString = isoString.right(isoString.length() - 11); + Qt::TimeSpec spec = Qt::LocalTime; + QStringRef isoString(&string); + isoString = isoString.mid(10); // trim "yyyy-MM-dd" + + // Must be left with T and at least one digit for the hour: + if (isoString.size() < 2 + || !(isoString.startsWith(QLatin1Char('T')) + // FIXME: QSql relies on QVariant::toDateTime() accepting a space here: + || isoString.startsWith(QLatin1Char(' ')))) { + return QDateTime(); + } + isoString = isoString.mid(1); // trim 'T' (or space) + 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 = isoString.left(isoString.size() - 1); + isoString.chop(1); // trim 'Z' } else { // the loop below is faster but functionally equal to: // const int signIndex = isoString.indexOf(QRegExp(QStringLiteral("[+-]"))); int signIndex = isoString.size() - 1; + Q_ASSERT(signIndex >= 0); bool found = false; { const QChar plus = QLatin1Char('+'); @@ -4746,8 +4756,7 @@ QDateTime QDateTime::fromString(const QString& string, Qt::DateFormat format) do { QChar character(isoString.at(signIndex)); found = character == plus || character == minus; - } while (--signIndex >= 0 && !found); - ++signIndex; + } while (!found && --signIndex >= 0); } if (found) { -- cgit v1.2.3 From c26c5b7d0dc4607b7cdd5569c5180b94b4563b73 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 29 Jan 2018 21:46:40 -0800 Subject: Silence GCC 8 warning on memcpy of movable types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is similar to commit 342bb5b03a76d1428fafb8e1532d66e172bd1c0b. From GCC 8: qarraydataops.h:84:17: error: ‘void* memcpy(void*, const void*, size_t)’ writing to an object of type ‘class QStringRef’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess] [etc.] Change-Id: I41d006aac5bc48529845fffd150e817e64973bec Reviewed-by: Ville Voutilainen Reviewed-by: Thiago Macieira --- src/corelib/tools/qarraydataops.h | 3 ++- src/corelib/tools/qvarlengtharray.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qarraydataops.h b/src/corelib/tools/qarraydataops.h index b7c3bc1287..d0f83d2b6a 100644 --- a/src/corelib/tools/qarraydataops.h +++ b/src/corelib/tools/qarraydataops.h @@ -76,7 +76,8 @@ struct QPodArrayOps Q_ASSERT(b < e); Q_ASSERT(size_t(e - b) <= this->alloc - uint(this->size)); - ::memcpy(this->end(), b, (e - b) * sizeof(T)); + ::memcpy(static_cast(this->end()), static_cast(b), + (e - b) * sizeof(T)); this->size += e - b; } diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index d99eebd4b9..58bb5e75c4 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -344,7 +344,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::append(const T *abuf, in while (s < asize) new (ptr+(s++)) T(*abuf++); } else { - memcpy(&ptr[s], abuf, increment * sizeof(T)); + memcpy(static_cast(&ptr[s]), static_cast(abuf), increment * sizeof(T)); s = asize; } } @@ -392,7 +392,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::realloc(int asize, int a QT_RETHROW; } } else { - memcpy(ptr, oldPtr, copySize * sizeof(T)); + memcpy(static_cast(ptr), static_cast(oldPtr), copySize * sizeof(T)); } } s = copySize; -- cgit v1.2.3 From b34942710cf4e40bd9a3091032cb14baed741862 Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 16:31:40 +0200 Subject: Silence a GCC 8 warning in QIODevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/io/qiodevice.cpp:688:60: required from here ../../../include/QtCore/../../../../qtbase/src/corelib/tools/qvector.h:727:20: error: ‘void* memmove(void*, const void*, size_t)’ writing to an object of type ‘class QRingBuffer’ with no trivial copy-assignment; use copy-assignment or copy-initialization instead [-Werror=class-memaccess] memmove(i, b, (d->size - offset) * sizeof(T)); ~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change-Id: I9dc9a17c281b71bf2eb3e89116600ec3ba345d74 Reviewed-by: Simon Hausmann --- src/corelib/tools/qvector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qvector.h b/src/corelib/tools/qvector.h index 74c37faad0..e225ce1ecb 100644 --- a/src/corelib/tools/qvector.h +++ b/src/corelib/tools/qvector.h @@ -724,7 +724,7 @@ typename QVector::iterator QVector::insert(iterator before, size_type n, c } else { T *b = d->begin() + offset; T *i = b + n; - memmove(i, b, (d->size - offset) * sizeof(T)); + memmove(static_cast(i), static_cast(b), (d->size - offset) * sizeof(T)); while (i != b) new (--i) T(copy); } -- cgit v1.2.3 From 77582f1f103b4f86423aa29fc7233678a399938c Mon Sep 17 00:00:00 2001 From: Ville Voutilainen Date: Wed, 7 Feb 2018 17:58:38 +0200 Subject: Silence GCC 8 warnings in QString MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit qtbase/src/corelib/tools/qstring.cpp:3539:67: error: ‘void* memcpy(void*, const void*, size_t)’ copying an object of non-trivial type ‘class QChar’ from an array of ‘short unsigned int’ [-Werror=class-memaccess] memcpy(uc, d->data() + copystart, size * sizeof(QChar)); Change-Id: Ic601bed1a1f9e1b6f0ac1f9e58f1dcadb50ad724 Reviewed-by: Simon Hausmann --- src/corelib/tools/qstring.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index aff384a257..2c96a8d33c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -3536,14 +3536,14 @@ QString& QString::replace(const QRegExp &rx, const QString &after) while (i < pos) { int copyend = replacements[i].pos; int size = copyend - copystart; - memcpy(uc, d->data() + copystart, size * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(d->data() + copystart), size * sizeof(QChar)); uc += size; - memcpy(uc, after.d->data(), al * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(after.d->data()), al * sizeof(QChar)); uc += al; copystart = copyend + replacements[i].length; i++; } - memcpy(uc, d->data() + copystart, (d->size - copystart) * sizeof(QChar)); + memcpy(static_cast(uc), static_cast(d->data() + copystart), (d->size - copystart) * sizeof(QChar)); newstring.resize(newlen); *this = newstring; caretMode = QRegExp::CaretWontMatch; @@ -5766,7 +5766,7 @@ QString QString::rightJustified(int width, QChar fill, bool truncate) const while (padlen--) * uc++ = fill; if (len) - memcpy(uc, d->data(), sizeof(QChar)*len); + memcpy(static_cast(uc), static_cast(d->data()), sizeof(QChar)*len); } else { if (truncate) result = left(width); -- cgit v1.2.3