diff options
Diffstat (limited to 'src/corelib/text/qcollator.cpp')
-rw-r--r-- | src/corelib/text/qcollator.cpp | 319 |
1 files changed, 183 insertions, 136 deletions
diff --git a/src/corelib/text/qcollator.cpp b/src/corelib/text/qcollator.cpp index 4bef356044..1f7e7459e7 100644 --- a/src/corelib/text/qcollator.cpp +++ b/src/corelib/text/qcollator.cpp @@ -1,50 +1,39 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qcollator_p.h" #include "qstringlist.h" #include "qstring.h" #include "qdebug.h" +#include "qlocale_p.h" +#include "qthreadstorage.h" QT_BEGIN_NAMESPACE +QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCollatorSortKeyPrivate) + +namespace { +struct GenerationalCollator +{ + QCollator theCollator; + int generation = QLocalePrivate::s_generation.loadRelaxed(); +public: + GenerationalCollator() = default; + GenerationalCollator(const QCollator ©) : 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 @@ -58,35 +47,60 @@ QT_BEGIN_NAMESPACE \ingroup string-processing \ingroup shared - QCollator is initialized with a QLocale and an optional collation strategy. - It tries to initialize the collator with the specified values. The collator - can then be used to compare and sort strings in a locale dependent fashion. + QCollator is initialized with a QLocale. It can then be used to compare and + sort strings by using the ordering appropriate for that locale. + + A QCollator object can be used together with template-based sorting + algorithms, such as std::sort(), to sort a list with QString entries. + + \snippet code/src_corelib_text_qcollator.cpp 0 + + In addition to the locale, several optional flags can be set that influence + the result of the collation. + + \section1 POSIX fallback implementation + + On Unix systems, Qt is normally compiled to use ICU (except for \macos, + where Qt defaults to using an equivalent Apple API). However, if ICU was + not available at compile time or explicitly disabled, Qt will use a + fallback backend that uses the POSIX API only. This backend has several + limitations: - A QCollator object can be used together with template based sorting - algorithms such as std::sort to sort a list of QStrings. + \list + \li Only the QLocale::c() and QLocale::system() locales are supported. + Consult the POSIX and C Standard Library manuals for the + \c{<locale.h>} header for more information on the system locale. + \li caseSensitivity() is not supported: only case-sensitive collation + can be performed. + \li numericMode() and ignorePunctuation() are not supported. + \endlist - In addition to the locale and collation strategy, several optional flags can - be set that influence the result of the collation. + The use of any of the unsupported options will cause a warning to be + printed to the application's output. */ /*! \since 5.13 - Constructs a QCollator using the system's default collation locale. + Constructs a QCollator using the default locale's collation locale. - \sa setLocale(), QLocale::collation() + The system locale, when used as default locale, may have a collation locale + other than itself (e.g. on Unix, if LC_COLLATE is set differently to LANG in + the environment). All other locales are their own collation locales. + + \sa setLocale(), QLocale::collation(), QLocale::setDefault() */ QCollator::QCollator() - : d(new QCollatorPrivate(QLocale::system().collation())) + : d(new QCollatorPrivate(QLocale().collation())) { d->init(); } /*! - Constructs a QCollator from \a locale. + Constructs a QCollator using the given \a locale. \sa setLocale() - */ +*/ QCollator::QCollator(const QLocale &locale) : d(new QCollatorPrivate(locale)) { @@ -94,21 +108,20 @@ QCollator::QCollator(const QLocale &locale) /*! Creates a copy of \a other. - */ +*/ QCollator::QCollator(const QCollator &other) : d(other.d) { if (d) { // Ensure clean, lest both copies try to init() at the same time: - if (d->dirty) - d->init(); + d->ensureInitialized(); d->ref.ref(); } } /*! - Destroys the collator. - */ + Destroys this collator. +*/ QCollator::~QCollator() { if (d && !d->ref.deref()) @@ -117,7 +130,7 @@ QCollator::~QCollator() /*! Assigns \a other to this collator. - */ +*/ QCollator &QCollator::operator=(const QCollator &other) { if (this != &other) { @@ -126,8 +139,7 @@ QCollator &QCollator::operator=(const QCollator &other) d = other.d; if (d) { // Ensure clean, lest both copies try to init() at the same time: - if (d->dirty) - d->init(); + d->ensureInitialized(); d->ref.ref(); } } @@ -139,19 +151,19 @@ QCollator &QCollator::operator=(const QCollator &other) Move constructor. Moves from \a other into this collator. - Note that a moved-from QCollator can only be destroyed or assigned to. - The effect of calling other functions than the destructor or one of the - assignment operators is undefined. +//! [partially-formed] + \note The moved-from object \a other is placed in a partially-formed state, + in which the only valid operations are destruction and assignment of a new + value. +//! [partially-formed] */ /*! \fn QCollator & QCollator::operator=(QCollator && other) - Move-assigns from \a other to this collator. + Move-assigns \a other to this QCollator instance. - Note that a moved-from QCollator can only be destroyed or assigned to. - The effect of calling other functions than the destructor or one of the - assignment operators is undefined. + \include qcollator.cpp partially-formed */ /*! @@ -163,7 +175,7 @@ QCollator &QCollator::operator=(const QCollator &other) /*! \internal - */ +*/ void QCollator::detach() { if (d->ref.loadRelaxed() != 1) { @@ -178,7 +190,9 @@ void QCollator::detach() /*! Sets the locale of the collator to \a locale. - */ + + \sa locale() +*/ void QCollator::setLocale(const QLocale &locale) { if (locale == d->locale) @@ -190,19 +204,22 @@ void QCollator::setLocale(const QLocale &locale) /*! Returns the locale of the collator. - */ + + Unless supplied to the constructor or by calling setLocale(), the system's + default collation locale is used. + + \sa setLocale(), QLocale::collation() +*/ QLocale QCollator::locale() const { return d->locale; } /*! - \fn void QCollator::setCaseSensitivity(Qt::CaseSensitivity sensitivity) - - Sets the case \a sensitivity of the collator. + Sets the case-sensitivity of the collator to \a cs. \sa caseSensitivity() - */ +*/ void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs) { if (d->caseSensitivity == cs) @@ -213,29 +230,27 @@ void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs) } /*! - \fn Qt::CaseSensitivity QCollator::caseSensitivity() const - Returns case sensitivity of the collator. + This defaults to case-sensitive until set. + + \note In the C locale, when case-sensitive, all lower-case letters sort + after all upper-case letters, where most locales sort each lower-case letter + either immediately before or immediately after its upper-case partner. Thus + "Zap" sorts before "ape" in the C locale but after in most others. + \sa setCaseSensitivity() - */ +*/ Qt::CaseSensitivity QCollator::caseSensitivity() const { return d->caseSensitivity; } /*! - \fn void QCollator::setNumericMode(bool on) - - Enables numeric sorting mode when \a on is set to true. - - This will enable proper sorting of numeric digits, so that e.g. 100 sorts - after 99. - - By default this mode is off. + Enables numeric sorting mode when \a on is \c true. \sa numericMode() - */ +*/ void QCollator::setNumericMode(bool on) { if (d->numericMode == on) @@ -246,30 +261,25 @@ void QCollator::setNumericMode(bool on) } /*! - \fn bool QCollator::numericMode() const + Returns \c true if numeric sorting is enabled, \c false otherwise. - Returns \c true if numeric sorting is enabled, false otherwise. + When \c true, numerals are recognized as numbers and sorted in arithmetic + order; for example, 100 sortes after 99. When \c false, numbers are sorted + in lexical order, so that 100 sorts before 99 (because 1 is before 9). By + default, this option is disabled. \sa setNumericMode() - */ +*/ bool QCollator::numericMode() const { return d->numericMode; } /*! - \fn void QCollator::setIgnorePunctuation(bool on) - - If \a on is set to true, punctuation characters and symbols are ignored when - determining sort order. - - The default is locale dependent. - - \note This method is not currently supported if Qt is configured to not use - ICU on Linux. + Ignores punctuation and symbols if \a on is \c true, attends to them if \c false. \sa ignorePunctuation() - */ +*/ void QCollator::setIgnorePunctuation(bool on) { if (d->ignorePunctuation == on) @@ -280,13 +290,13 @@ void QCollator::setIgnorePunctuation(bool on) } /*! - \fn bool QCollator::ignorePunctuation() const + Returns whether punctuation and symbols are ignored when collating. - Returns \c true if punctuation characters and symbols are ignored when - determining sort order. + When \c true, strings are compared as if all punctuation and symbols were + removed from each string. \sa setIgnorePunctuation() - */ +*/ bool QCollator::ignorePunctuation() const { return d->ignorePunctuation; @@ -295,7 +305,11 @@ bool QCollator::ignorePunctuation() const /*! \since 5.13 \fn bool QCollator::operator()(QStringView s1, QStringView s2) const - \internal + + A QCollator can be used as the comparison function of a sorting algorithm. + It returns \c true if \a s1 sorts before \a s2, otherwise \c false. + + \sa compare() */ /*! @@ -304,42 +318,64 @@ bool QCollator::ignorePunctuation() const Compares \a s1 with \a s2. - Returns an integer less than, equal to, or greater than zero depending on - whether \a s1 sorts before, with or after \a s2. + Returns a negative integer if \a s1 is less than \a s2, a positive integer + if it is greater than \a s2, and zero if they are equal. */ -#if QT_STRINGVIEW_LEVEL < 2 + /*! \fn bool QCollator::operator()(const QString &s1, const QString &s2) const - \internal + \overload + \since 5.2 */ /*! + \fn int QCollator::compare(const QString &s1, const QString &s2) const \overload + \since 5.2 +*/ - Compares \a s1 with \a s2. +/*! + \fn int QCollator::compare(const QChar *s1, qsizetype len1, const QChar *s2, qsizetype len2) const + \overload + \since 5.2 - Returns an integer less than, equal to, or greater than zero depending on - whether \a s1 sorts before, with or after \a s2. + Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the + QChar arrays pointed to by \a s1 and \a s2. + + Returns a negative integer if \a s1 is less than \a s2, a positive integer + if it is greater than \a s2, and zero if they are equal. + + + \note In Qt versions prior to 6.4, the length arguments were of type + \c{int}, not \c{qsizetype}. */ -int QCollator::compare(const QString &s1, const QString &s2) const + +/*! + \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 compare(QStringView(s1), QStringView(s2)); + return defaultCollator->localData().collator().compare(s1, s2); } /*! - \overload + \since 6.3 - Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the - QChar arrays pointed to by \a s1 and \a s2. + Returns the sort key for the string \a key. This function performs the same + operation as sortKey() on a default-constructed QCollator object. - Returns an integer less than, equal to, or greater than zero depending on - whether \a s1 sorts before, with or after \a s2. + \sa sortKey(), defaultCompare() */ -int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const +QCollatorSortKey QCollator::defaultSortKey(QStringView key) { - return compare(QStringView(s1, len1), QStringView(s2, len2)); + return defaultCollator->localData().collator().sortKey(key.toString()); } -#endif // QT_STRINGVIEW_LEVEL < 2 /*! \fn QCollatorSortKey QCollator::sortKey(const QString &string) const @@ -352,7 +388,7 @@ int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) con keys for each string and then sort using the keys. \note Not supported with the C (a.k.a. POSIX) locale on Darwin. - */ +*/ /*! \class QCollatorSortKey @@ -369,12 +405,12 @@ int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) con \ingroup string-processing \ingroup shared - \sa QCollator, QCollator::sortKey() + \sa QCollator, QCollator::sortKey(), compare() */ /*! \internal - */ +*/ QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d) : d(d) { @@ -389,15 +425,23 @@ QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey &other) } /*! + \since 6.8 + \fn QCollatorSortKey::QCollatorSortKey(QCollatorSortKey &&other) + Move-constructs a new QCollatorSortKey from \a other. + + \include qcollator.cpp partially-formed +*/ + +/*! Destroys the collator key. - */ +*/ QCollatorSortKey::~QCollatorSortKey() { } /*! Assigns \a other to this collator key. - */ +*/ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) { if (this != &other) { @@ -409,18 +453,20 @@ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) /*! \fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other) - Move-assigns \a other to this collator key. + Move-assigns \a other to this QCollatorSortKey instance. + + \include qcollator.cpp partially-formed */ /*! - \fn bool operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs) - \relates QCollatorSortKey + \fn bool QCollatorSortKey::operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs) - According to the QCollator that created the keys, returns \c true if \a lhs - should be sorted before \a rhs; otherwise returns \c false. + Both keys must have been created by the same QCollator's sortKey(). Returns + \c true if \a lhs should be sorted before \a rhs, according to the QCollator + that created them; otherwise returns \c false. \sa QCollatorSortKey::compare() - */ +*/ /*! \fn void QCollatorSortKey::swap(QCollatorSortKey & other) @@ -431,13 +477,14 @@ QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) /*! \fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const - Compares this key to \a otherKey. + Compares this key to \a otherKey, which must have been created by the same + QCollator's sortKey() as this key. The comparison is performed in accordance + with that QCollator's sort order. - Returns a negative value if the key is less than \a otherKey, 0 if the key - is equal to \a otherKey or a positive value if the key is greater than \a - otherKey. + Returns a negative value if this key sorts before \a otherKey, 0 if the two + keys are equal or a positive value if this key sorts after \a otherKey. \sa operator<() - */ +*/ QT_END_NAMESPACE |