From 7fd483f3de5bfb98a816e4d63724476b839effc8 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 25 Feb 2017 11:40:04 -0800 Subject: QDateTimeParser: Merge the code to parse names of months and weekdays Simplifies everything and avoids bugfixes in one not propagating to the other. Change-Id: I95c9e502ccc74af3bcf0fffd14a69f0cde60cc8c Reviewed-by: Edward Welbourne --- src/corelib/tools/qdatetimeparser.cpp | 136 +++++++++++++--------------------- 1 file changed, 51 insertions(+), 85 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index c8aa4fbc89..b90d7d1aea 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -1243,6 +1243,34 @@ end: #endif // QT_NO_DATESTRING #ifndef QT_NO_TEXTDATE + +static int findTextEntry(const QString &text, int start, const QVector &entries, QString *usedText, int *used) +{ + if (text.isEmpty()) + return -1; + + int bestMatch = -1; + int bestCount = 0; + for (int n = start; n <= entries.size(); ++n) { + const QString name = entries.at(n - 1).toLower(); + + const int limit = qMin(text.size(), name.size()); + int i = 0; + while (i < limit && text.at(i) == name.at(i)) + ++i; + if (i > bestCount) { + bestCount = i; + bestMatch = n; + } + } + if (usedText && bestMatch != -1) + *usedText = entries.at(bestMatch - 1); + if (used) + *used = bestCount; + + return bestMatch; +} + /*! \internal finds the first possible monthname that \a str1 can @@ -1252,99 +1280,37 @@ end: int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionIndex, QString *usedMonth, int *used) const { - int bestMatch = -1; - int bestCount = 0; - if (!str1.isEmpty()) { - const SectionNode &sn = sectionNode(sectionIndex); - if (sn.type != MonthSection) { - qWarning("QDateTimeParser::findMonth Internal error"); - return -1; - } - - QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; - QLocale l = locale(); - - for (int month=startMonth; month<=12; ++month) { - const QString monthName = l.monthName(month, type); - QString str2 = monthName.toLower(); + const SectionNode &sn = sectionNode(sectionIndex); + if (sn.type != MonthSection) { + qWarning("QDateTimeParser::findMonth Internal error"); + return -1; + } - if (str1.startsWith(str2)) { - if (used) { - QDTPDEBUG << "used is set to" << str2.size(); - *used = str2.size(); - } - if (usedMonth) - *usedMonth = monthName; + QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; + QLocale l = locale(); + QVector monthNames; + monthNames.reserve(12); + for (int month = 1; month <= 12; ++month) + monthNames.append(month >= startMonth ? l.monthName(month, type) : QString()); - return month; - } - if (context == FromString) - continue; - - const int limit = qMin(str1.size(), str2.size()); - - QDTPDEBUG << "limit is" << limit << str1 << str2; - bool equal = true; - for (int i=0; i bestCount) { - bestCount = i; - bestMatch = month; - } - break; - } - } - if (equal) { - if (used) - *used = limit; - if (usedMonth) - *usedMonth = monthName; - return month; - } - } - if (usedMonth && bestMatch != -1) - *usedMonth = l.monthName(bestMatch, type); - } - if (used) { - QDTPDEBUG << "used is set to" << bestCount; - *used = bestCount; - } - return bestMatch; + return findTextEntry(str1, startMonth, monthNames, usedMonth, used); } int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const { - int bestMatch = -1; - int bestCount = 0; - if (!str1.isEmpty()) { - const SectionNode &sn = sectionNode(sectionIndex); - if (!(sn.type & DaySectionMask)) { - qWarning("QDateTimeParser::findDay Internal error"); - return -1; - } - const QLocale l = locale(); - for (int day=startDay; day<=7; ++day) { - const QString dayName = l.dayName(day, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); - const QString str2 = dayName.toLower(); - - const int limit = qMin(str1.size(), str2.size()); - int i = 0; - while (i < limit && str1.at(i) == str2.at(i)) - ++i; - if (i > bestCount) { - bestCount = i; - bestMatch = day; - } - } - if (usedDay && bestMatch != -1) { - *usedDay = l.dayName(bestMatch, sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat); - } + const SectionNode &sn = sectionNode(sectionIndex); + if (!(sn.type & DaySectionMask)) { + qWarning("QDateTimeParser::findDay Internal error"); + return -1; } - if (used) - *used = bestCount; - return bestMatch; + QLocale::FormatType type = sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat; + QLocale l = locale(); + QVector daysOfWeek; + daysOfWeek.reserve(7); + for (int day = 1; day <= 7; ++day) + daysOfWeek.append(day >= startDay ? l.dayName(day, type) : QString()); + return findTextEntry(str1, startDay, daysOfWeek, usedDay, used); } #endif // QT_NO_TEXTDATE -- cgit v1.2.3 From 326f1fdb7d6550a529217b226cbef78425d32969 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 28 Feb 2017 12:03:46 +0100 Subject: Simplify QDateTimeParser's shiny new findTextEntry() Decouple from the callers' offset into a larger list; just search for an entry in a list, let the caller deal with the offset. Also, defer a .tolower() to save the need to allocate a copy of each list entry. Change-Id: I748d5214c2cc6dc592fe2bd41e3f8150f71c335b Reviewed-by: Thiago Macieira --- src/corelib/tools/qdatetimeparser.cpp | 38 +++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 13 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index b90d7d1aea..5871587f8c 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -1244,19 +1244,28 @@ end: #ifndef QT_NO_TEXTDATE -static int findTextEntry(const QString &text, int start, const QVector &entries, QString *usedText, int *used) +/* + \internal + \brief Returns the index in \a entries with the best prefix match to \a text + + Scans \a entries looking for an entry overlapping \a text as much as possible. + Records the length of overlap in *used (if \a used is non-NULL) and the first + entry that overlapped this much in *usedText (if \a usedText is non-NULL). + */ +static int findTextEntry(const QString &text, const QVector &entries, QString *usedText, int *used) { if (text.isEmpty()) return -1; int bestMatch = -1; int bestCount = 0; - for (int n = start; n <= entries.size(); ++n) { - const QString name = entries.at(n - 1).toLower(); + for (int n = 0; n < entries.size(); ++n) + { + const QString &name = entries.at(n); const int limit = qMin(text.size(), name.size()); int i = 0; - while (i < limit && text.at(i) == name.at(i)) + while (i < limit && text.at(i) == name.at(i).toLower()) ++i; if (i > bestCount) { bestCount = i; @@ -1264,7 +1273,7 @@ static int findTextEntry(const QString &text, int start, const QVector } } if (usedText && bestMatch != -1) - *usedText = entries.at(bestMatch - 1); + *usedText = entries.at(bestMatch); if (used) *used = bestCount; @@ -1289,11 +1298,12 @@ int QDateTimeParser::findMonth(const QString &str1, int startMonth, int sectionI QLocale::FormatType type = sn.count == 3 ? QLocale::ShortFormat : QLocale::LongFormat; QLocale l = locale(); QVector monthNames; - monthNames.reserve(12); - for (int month = 1; month <= 12; ++month) - monthNames.append(month >= startMonth ? l.monthName(month, type) : QString()); + monthNames.reserve(13 - startMonth); + for (int month = startMonth; month <= 12; ++month) + monthNames.append(l.monthName(month, type)); - return findTextEntry(str1, startMonth, monthNames, usedMonth, used); + const int index = findTextEntry(str1, monthNames, usedMonth, used); + return index < 0 ? index : index + startMonth; } int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex, QString *usedDay, int *used) const @@ -1307,10 +1317,12 @@ int QDateTimeParser::findDay(const QString &str1, int startDay, int sectionIndex QLocale::FormatType type = sn.count == 4 ? QLocale::LongFormat : QLocale::ShortFormat; QLocale l = locale(); QVector daysOfWeek; - daysOfWeek.reserve(7); - for (int day = 1; day <= 7; ++day) - daysOfWeek.append(day >= startDay ? l.dayName(day, type) : QString()); - return findTextEntry(str1, startDay, daysOfWeek, usedDay, used); + daysOfWeek.reserve(8 - startDay); + for (int day = startDay; day <= 7; ++day) + daysOfWeek.append(l.dayName(day, type)); + + const int index = findTextEntry(str1, daysOfWeek, usedDay, used); + return index < 0 ? index : index + startDay; } #endif // QT_NO_TEXTDATE -- cgit v1.2.3 From 9ed389bf15787266c207435d712b9e225db07ad9 Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 28 Feb 2017 12:03:46 +0100 Subject: Bugfix in QDateTimeParser's findTextEntry() If a later month-or-day were to have a name that's a prefix of an earlier one's name, the code would have selected the longer name as best match when the text matched is the shorter name, simply because it found that one first. (Found, on Turkish Cuma(rtesi)? in Thiago's recent new test, by reversing the loop that iterated the list.) Make an exact match win and a match of a full name beat any prefix match of the same length. Change-Id: I8d954b83ccc25e4f47af2e558036d714685cef5e Reviewed-by: Thiago Macieira --- src/corelib/tools/qdatetimeparser.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qdatetimeparser.cpp b/src/corelib/tools/qdatetimeparser.cpp index 5871587f8c..62dd25e072 100644 --- a/src/corelib/tools/qdatetimeparser.cpp +++ b/src/corelib/tools/qdatetimeparser.cpp @@ -1248,9 +1248,12 @@ end: \internal \brief Returns the index in \a entries with the best prefix match to \a text - Scans \a entries looking for an entry overlapping \a text as much as possible. - Records the length of overlap in *used (if \a used is non-NULL) and the first - entry that overlapped this much in *usedText (if \a usedText is non-NULL). + Scans \a entries looking for an entry overlapping \a text as much as possible + (an exact match beats any prefix match; a match of the full entry as prefix of + text beats any entry but one matching a longer prefix; otherwise, the match of + longest prefix wins, earlier entries beating later on a draw). Records the + length of overlap in *used (if \a used is non-NULL) and the first entry that + overlapped this much in *usedText (if \a usedText is non-NULL). */ static int findTextEntry(const QString &text, const QVector &entries, QString *usedText, int *used) { @@ -1267,9 +1270,12 @@ static int findTextEntry(const QString &text, const QVector &entries, Q int i = 0; while (i < limit && text.at(i) == name.at(i).toLower()) ++i; - if (i > bestCount) { + // Full match beats an equal prefix match: + if (i > bestCount || (i == bestCount && i == name.size())) { bestCount = i; bestMatch = n; + if (i == name.size() && i == text.size()) + break; // Exact match, name == text, wins. } } if (usedText && bestMatch != -1) -- cgit v1.2.3 From e364384d9f91e57ad6116d549f3748d165b77ea2 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 14 Mar 2017 11:01:37 +0100 Subject: QChar: fix docs of (uchar) ctor The constructor is not only disabled under QT_NO_CAST_FROM_ASCII, but also under QT_RESTRICTED_CAST_FROM_ASCII. Change-Id: I7bbaf2891913d5256dff7f80c49075ea3326155a Reviewed-by: Edward Welbourne Reviewed-by: Thiago Macieira --- src/corelib/tools/qchar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 287861eee8..5f918aab0f 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -624,9 +624,9 @@ QT_BEGIN_NAMESPACE Constructs a QChar corresponding to ASCII/Latin-1 character \a ch. \note This constructor is not available when \c QT_NO_CAST_FROM_ASCII - is defined. + or QT_RESTRICTED_CAST_FROM_ASCII is defined. - \sa QT_NO_CAST_FROM_ASCII + \sa QT_NO_CAST_FROM_ASCII, QT_RESTRICTED_CAST_FROM_ASCII */ /*! -- cgit v1.2.3 From 5c724a6087b0a647e8241d35f0d44bce08e35281 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Fri, 17 Mar 2017 11:07:30 +0100 Subject: QChar: fix ambiguous comparisons with 0, '\0', ... for good Commit e0ea0f6178c9dbee2a8c888fde84ad1cd9670c6b optimized QChar <-> QString(Ref) comparisons by adding more overloads to avoid creating QStrings from QChars just to compare them. But these new overloads made existing comparisons to QChar ambiguous. This was known at the time for QChar/int comparisons. It has since turned out that also comparing to '\0' is ambiguous, ie. not comparing to int or char per se is ambiguous, but comparing to nullptr constants is, because QString(const char*) is just as good a candidate as QChar(char)/QChar(int). Since we allow QString/QChar comparisons, it seems logical to solve the problem by adding QChar<->nullptr overloads. [ChangeLog][QtCore][QChar] Disambiguated comparisons with nullptr constants such as '\0', which 5.8.0 broke. As a consequence, QChar<->int comparisons are no longer deprecated, as this was a failed attempt at fixing the ambiguity. Change-Id: I680dd509c2286e96894e13078899dbe3b2dd83bc Reviewed-by: Thiago Macieira --- src/corelib/tools/qchar.h | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qchar.h b/src/corelib/tools/qchar.h index a83e5e6f98..81ef67d116 100644 --- a/src/corelib/tools/qchar.h +++ b/src/corelib/tools/qchar.h @@ -578,17 +578,21 @@ Q_DECL_CONSTEXPR inline bool operator>=(QChar c1, QChar c2) Q_DECL_NOTHROW { ret Q_DECL_CONSTEXPR inline bool operator> (QChar c1, QChar c2) Q_DECL_NOTHROW { return operator< (c2, c1); } Q_DECL_CONSTEXPR inline bool operator<=(QChar c1, QChar c2) Q_DECL_NOTHROW { return !operator< (c2, c1); } -// disambiguate QChar == int (but only that, so constrain template to exactly 'int'): -template -Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead") -Q_DECL_CONSTEXPR inline -typename std::enable_if::type, int>::value, bool>::type -operator==(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs == QChar(rhs); } -template -Q_DECL_DEPRECATED_X("don't compare ints to QChars, compare them to QChar::unicode() instead") -Q_DECL_CONSTEXPR inline -typename std::enable_if::type, int>::value, bool>::type -operator!=(QChar lhs, T rhs) Q_DECL_NOEXCEPT { return lhs != QChar(rhs); } + +Q_DECL_CONSTEXPR inline bool operator==(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return lhs.isNull(); } +Q_DECL_CONSTEXPR inline bool operator< (QChar, std::nullptr_t) Q_DECL_NOTHROW { return false; } +Q_DECL_CONSTEXPR inline bool operator==(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return rhs.isNull(); } +Q_DECL_CONSTEXPR inline bool operator< (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !rhs.isNull(); } + +Q_DECL_CONSTEXPR inline bool operator!=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator==(lhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator>=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (lhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator> (QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return operator< (nullptr, lhs); } +Q_DECL_CONSTEXPR inline bool operator<=(QChar lhs, std::nullptr_t) Q_DECL_NOTHROW { return !operator< (nullptr, lhs); } + +Q_DECL_CONSTEXPR inline bool operator!=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator==(nullptr, rhs); } +Q_DECL_CONSTEXPR inline bool operator>=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (nullptr, rhs); } +Q_DECL_CONSTEXPR inline bool operator> (std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return operator< (rhs, nullptr); } +Q_DECL_CONSTEXPR inline bool operator<=(std::nullptr_t, QChar rhs) Q_DECL_NOTHROW { return !operator< (rhs, nullptr); } #ifndef QT_NO_DATASTREAM Q_CORE_EXPORT QDataStream &operator<<(QDataStream &, QChar); -- cgit v1.2.3 From 4a97e3b98a40e6d35a4e63e171319ed02961a0cc Mon Sep 17 00:00:00 2001 From: Anton Kudryavtsev Date: Fri, 17 Mar 2017 00:07:57 +0300 Subject: QMap, QHash: make key_iterator satisfy the DefaultConstructible concept Change-Id: Ifc3f481ddb902b26c217516412c93a4a39a32b1c Reviewed-by: Marc Mutz --- src/corelib/tools/qhash.h | 1 + src/corelib/tools/qmap.h | 1 + 2 files changed, 2 insertions(+) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qhash.h b/src/corelib/tools/qhash.h index 66b5e75a1a..c59f789cb2 100644 --- a/src/corelib/tools/qhash.h +++ b/src/corelib/tools/qhash.h @@ -432,6 +432,7 @@ public: typedef const Key *pointer; typedef const Key &reference; + key_iterator() = default; explicit key_iterator(const_iterator o) : i(o) { } const Key &operator*() const { return i.key(); } diff --git a/src/corelib/tools/qmap.h b/src/corelib/tools/qmap.h index e6da2820f8..3ee6ab8c58 100644 --- a/src/corelib/tools/qmap.h +++ b/src/corelib/tools/qmap.h @@ -531,6 +531,7 @@ public: typedef const Key *pointer; typedef const Key &reference; + key_iterator() = default; explicit key_iterator(const_iterator o) : i(o) { } const Key &operator*() const { return i.key(); } -- cgit v1.2.3 From 202d6ad73059d4dd1199fd1e8785d29018749f32 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 14 Mar 2017 11:31:52 -0700 Subject: QHash: unexport the hash seed variable The only allowed way to access the variable is now via the public qGlobalQHashSeed and qSetGlobalQHashSeed functions. The variable was private API, so we're allowed to remove it. Task-number: QTBUG-47566 Change-Id: I4a7dc1fe14154695b968fffd14abd331e5810482 Reviewed-by: Jake Petroules Reviewed-by: David Faure --- src/corelib/tools/qhash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index 9270539f4f..334bd52f1e 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -325,7 +325,7 @@ static uint qt_create_qhash_seed() /* The QHash seed itself. */ -Q_CORE_EXPORT QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1); +static QBasicAtomicInt qt_qhash_seed = Q_BASIC_ATOMIC_INITIALIZER(-1); /*! \internal -- cgit v1.2.3 From 5ca7d56aca5d7cae3f6eefad181839f9b3a2ece6 Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Sat, 25 Mar 2017 08:09:03 +0100 Subject: QVarLengthArray: fix compilation with GCC 7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes a warning-turned-Werror in qdistancefield.cpp: In member function ‘void QVarLengthArray::realloc(int, int) [with T = bool; int Prealloc = 256]’, inlined from ‘void makeDistanceField(QDistanceFieldData*, const QPainterPath&, int, int)’ at ../../include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:275:10: ../../include/QtCore/../../../../qt5/qtbase/src/corelib/tools/qvarlengtharray.h:390:19: error: ‘void* memcpy(void*, const void*, size_t)’: specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Werror=stringop-overflow=] memcpy(ptr, oldPtr, copySize * sizeof(T)); ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Apparently GCC cannot rule out that copySize may be negative in the call to memcpy. Put GCC on the right track by adding a Q_ASSUME. Change-Id: I63e3801e52ebe2a7f77e3a97ef03ec3869319c8c Reviewed-by: Thiago Macieira Reviewed-by: Konstantin Ritt Reviewed-by: Olivier Goffart (Woboq GmbH) --- src/corelib/tools/qvarlengtharray.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/corelib/tools') diff --git a/src/corelib/tools/qvarlengtharray.h b/src/corelib/tools/qvarlengtharray.h index 2d3c25a5dd..8b9df7c12b 100644 --- a/src/corelib/tools/qvarlengtharray.h +++ b/src/corelib/tools/qvarlengtharray.h @@ -350,6 +350,7 @@ Q_OUTOFLINE_TEMPLATE void QVarLengthArray::realloc(int asize, int a int osize = s; const int copySize = qMin(asize, osize); + Q_ASSUME(copySize >= 0); if (aalloc != a) { if (aalloc > Prealloc) { T* newPtr = reinterpret_cast(malloc(aalloc * sizeof(T))); -- cgit v1.2.3