QCollator: add public, static functions to do comparisons

Collation with the default QCollator object (no numeric, punctuation or
case sensitivity changes) is a common-place occurrence, so add two
functions to do this work.

It's also what QString::localeAwareCompare() calls.

The test ends up testing that default, static collator updates after the
default QLocale changes too.

Task-number: QTBUG-95050
Change-Id: I7e0b82c2d2fe464082d8fffd1696ac77f32840b2
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Thiago Macieira 2021-07-30 13:45:46 -07:00 committed by Edward Welbourne
parent 25d807f629
commit a9d8794cf0
4 changed files with 70 additions and 25 deletions

View File

@ -43,9 +43,33 @@
#include "qstring.h"
#include "qdebug.h"
#include "qlocale_p.h"
#include "qthreadstorage.h"
QT_BEGIN_NAMESPACE
namespace {
struct GenerationalCollator
{
QCollator theCollator;
int generation = QLocalePrivate::s_generation.loadRelaxed();
public:
GenerationalCollator() = default;
GenerationalCollator(const QCollator &copy) : theCollator(copy) {}
QCollator &collator()
{
int currentGeneration = QLocalePrivate::s_generation.loadRelaxed();
if (Q_UNLIKELY(generation != currentGeneration)) {
// reinitialize the collator
generation = currentGeneration;
theCollator = QCollator();
}
return theCollator;
}
};
}
Q_GLOBAL_STATIC(QThreadStorage<GenerationalCollator>, defaultCollator)
/*!
\class QCollator
\inmodule QtCore
@ -344,6 +368,33 @@ bool QCollator::ignorePunctuation() const
*/
#endif // QT_STRINGVIEW_LEVEL < 2
/*!
\since 6.3
Compares the strings \a s1 and \a s2, returning their sorting order. This
function performs the same operation as compare() on a default-constructed
QCollator object.
\sa compare(), defaultSortKey()
*/
int QCollator::defaultCompare(QStringView s1, QStringView s2)
{
return defaultCollator->localData().collator().compare(s1, s2);
}
/*!
\since 6.3
Returns the sort key for the string \a key. This function performs the same
operation as sortKey() on a default-constructed QCollator object.
\sa sortKey(), defaultCompare()
*/
QCollatorSortKey QCollator::defaultSortKey(QStringView key)
{
return defaultCollator->localData().collator().sortKey(key.toString());
}
/*!
\fn QCollatorSortKey QCollator::sortKey(const QString &string) const

View File

@ -117,6 +117,9 @@ public:
QCollatorSortKey sortKey(const QString &string) const;
static int defaultCompare(QStringView s1, QStringView s2);
static QCollatorSortKey defaultSortKey(QStringView key);
private:
QCollatorPrivate *d;

View File

@ -6214,28 +6214,6 @@ int QString::localeAwareCompare(const QString &other) const
return localeAwareCompare_helper(constData(), length(), other.constData(), other.length());
}
#if QT_CONFIG(icu)
namespace {
class GenerationalCollator
{
QCollator theCollator;
int generation = QLocalePrivate::s_generation.loadRelaxed();
public:
QCollator &collator()
{
int currentGeneration = QLocalePrivate::s_generation.loadRelaxed();
if (Q_UNLIKELY(generation != currentGeneration)) {
// reinitialize the collator
generation = currentGeneration;
theCollator = QCollator();
}
return theCollator;
}
};
}
Q_GLOBAL_STATIC(QThreadStorage<GenerationalCollator>, defaultCollator)
#endif
/*!
\internal
\since 4.5
@ -6254,9 +6232,7 @@ int QString::localeAwareCompare_helper(const QChar *data1, qsizetype length1,
Qt::CaseSensitive);
#if QT_CONFIG(icu)
if (!defaultCollator()->hasLocalData())
defaultCollator()->setLocalData(GenerationalCollator());
return defaultCollator()->localData().collator().compare(data1, length1, data2, length2);
return QCollator::defaultCompare(QStringView(data1, length1), QStringView(data2, length2));
#else
const QString lhs = QString::fromRawData(data1, length1).normalized(QString::NormalizationForm_C);
const QString rhs = QString::fromRawData(data2, length2).normalized(QString::NormalizationForm_C);

View File

@ -31,6 +31,7 @@
#include <qlocale.h>
#include <qcollator.h>
#include <private/qglobal_p.h>
#include <QScopeGuard>
#include <cstring>
@ -276,6 +277,13 @@ void tst_QCollator::compare()
QFETCH(int, punctuationResult);
QCollator collator((QLocale(locale)));
// AFTER the QCollator initialization
auto localechanger = qScopeGuard([original = QLocale()] {
QLocale::setDefault(original); // reset back to what it was
});
QLocale::setDefault(QLocale(locale));
// Need to canonicalize sign to -1, 0 or 1, as .compare() can produce any -ve for <, any +ve for >.
auto asSign = [](int compared) {
return compared < 0 ? -1 : compared > 0 ? 1 : 0;
@ -310,10 +318,17 @@ void tst_QCollator::compare()
// NOTE: currently QCollatorSortKey::compare is not working
// properly without icu: see QTBUG-88704 for details
QCOMPARE(asSign(collator.compare(s1, s2)), result);
if (!numericMode)
QCOMPARE(asSign(QCollator::defaultCompare(s1, s2)), result);
#if QT_CONFIG(icu)
auto key1 = collator.sortKey(s1);
auto key2 = collator.sortKey(s2);
QCOMPARE(asSign(key1.compare(key2)), keyCompareResult);
key1 = QCollator::defaultSortKey(s1);
key2 = QCollator::defaultSortKey(s2);
if (!numericMode)
QCOMPARE(asSign(key1.compare(key2)), keyCompareResult);
#endif
collator.setCaseSensitivity(Qt::CaseInsensitive);
QCOMPARE(asSign(collator.compare(s1, s2)), caseInsensitiveResult);