diff options
-rw-r--r-- | src/corelib/tools/qcollator.cpp | 330 | ||||
-rw-r--r-- | src/corelib/tools/qcollator.h | 70 |
2 files changed, 144 insertions, 256 deletions
diff --git a/src/corelib/tools/qcollator.cpp b/src/corelib/tools/qcollator.cpp index f41e9d61bf..28d42f4dca 100644 --- a/src/corelib/tools/qcollator.cpp +++ b/src/corelib/tools/qcollator.cpp @@ -50,8 +50,6 @@ #include <unicode/ures.h> #endif -#include "qdebug.h" - QT_BEGIN_NAMESPACE @@ -60,7 +58,6 @@ class QCollatorPrivate public: QAtomicInt ref; QLocale locale; - QCollator::Collation collation; #ifdef QT_USE_ICU UCollator *collator; @@ -68,50 +65,48 @@ public: void *collator; #endif - QStringList indexCharacters; - void clear() { #ifdef QT_USE_ICU if (collator) ucol_close(collator); #endif collator = 0; - indexCharacters.clear(); } QCollatorPrivate() - : collation(QCollator::Default), + : ref(1), collator(0) - { ref.store(1); } + { + } ~QCollatorPrivate(); + void init(); + private: Q_DISABLE_COPY(QCollatorPrivate) }; +class QCollatorSortKeyPrivate : public QSharedData +{ + friend class QCollator; +public: + QCollatorSortKeyPrivate(const QByteArray &key) : + QSharedData(), + m_key(key) + { + } + + QByteArray m_key; + +private: + Q_DISABLE_COPY(QCollatorSortKeyPrivate) +}; QCollatorPrivate::~QCollatorPrivate() { clear(); } -static const int collationStringsCount = 13; -static const char * const collationStrings[collationStringsCount] = { - "default", - "big5han", - "dictionary", - "direct", - "gb2312han", - "phonebook", - "pinyin", - "phonetic", - "reformed", - "standard", - "stroke", - "traditional", - "unihan" -}; - /*! \class QCollator \inmodule QtCore @@ -138,20 +133,16 @@ static const char * const collationStrings[collationStringsCount] = { */ /*! - Constructs a QCollator from \a locale and \a collation. If \a collation is not - specified the default collation algorithm for the locale is being used. If - \a locale is not specified QLocale::default() is being used. + Constructs a QCollator from \a locale. If \a locale is not specified QLocale::default() + is being used. - \sa setLocale(), setCollation() + \sa setLocale() */ -QCollator::QCollator(const QLocale &locale, QCollator::Collation collation) +QCollator::QCollator(const QLocale &locale) : d(new QCollatorPrivate) { d->locale = locale; - if ((int)collation >= 0 && (int)collation < collationStringsCount) - d->collation = collation; - - init(); + d->init(); } /*! @@ -190,19 +181,17 @@ QCollator &QCollator::operator=(const QCollator &other) /*! \internal */ -void QCollator::init() +void QCollatorPrivate::init() { - Q_ASSERT((int)d->collation < collationStringsCount); #ifdef QT_USE_ICU - const char *collationString = collationStrings[(int)d->collation]; UErrorCode status = U_ZERO_ERROR; - QByteArray name = (d->locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')) + QLatin1String("@collation=") + QLatin1String(collationString)).toLatin1(); - d->collator = ucol_open(name.constData(), &status); + QByteArray name = locale.bcp47Name().replace(QLatin1Char('-'), QLatin1Char('_')).toLocal8Bit(); + collator = ucol_open(name.constData(), &status); if (U_FAILURE(status)) qWarning("Could not create collator: %d", status); // enable normalization by default - ucol_setAttribute(d->collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); + ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status); #endif } @@ -215,8 +204,6 @@ void QCollator::detach() QCollatorPrivate *x = new QCollatorPrivate; x->ref.store(1); x->locale = d->locale; - x->collation = d->collation; - x->collator = 0; if (!d->ref.deref()) delete d; d = x; @@ -233,7 +220,7 @@ void QCollator::setLocale(const QLocale &locale) d->clear(); d->locale = locale; - init(); + d->init(); } /*! @@ -245,159 +232,36 @@ QLocale QCollator::locale() const } /*! - \enum QCollator::Collation - - This enum can be used to specify an alternate collation algorithm to be used instead - of the default algorithm for the locale. - - Possible values are: - - \value Default Use the default algorithm for the locale - \value Big5Han - \value Dictionary - \value Direct - \value GB2312Han - \value PhoneBook - \value Pinyin - \value Phonetic - \value Reformed - \value Standard - \value Stroke - \value Traditional - \value UniHan -*/ - -/*! - Sets the \a collation algorithm to be used. - - \sa QCollator::Collation + Sets the case \a cs of the collator. */ -void QCollator::setCollation(QCollator::Collation collation) -{ - if ((int)collation < 0 || (int)collation >= collationStringsCount) - return; - - if (d->ref.load() != 1) - detach(); - d->clear(); - d->collation = collation; - - init(); -} -/*! - Returns the currently used collation algorithm. - - \sa QCollator::Collation - */ -QCollator::Collation QCollator::collation() const -{ - return d->collation; -} - -/*! - Returns a unique identifer for this collation object. - - This method is helpful to save and restore defined collation - objects. - - \sa fromIdentifier() - */ -QString QCollator::identifier() const -{ - QString id = d->locale.bcp47Name(); - if (d->collation != QCollator::Default) { - id += QLatin1String("@collation="); - id += QLatin1String(collationStrings[d->collation]); - } - // this ensures the ID is compatible with ICU - id.replace('-', '_'); - return id; -} - -/*! - Creates a QCollator from a unique \a identifier and returns it. - - \sa identifier() - */ -QCollator QCollator::fromIdentifier(const QString &identifier) -{ - QString localeString = identifier; - QString collationString; - int at = identifier.indexOf(QLatin1Char('@')); - if (at >= 0) { - localeString = identifier.left(at); - collationString = identifier.mid(at + strlen("@collation=")); - } - - QLocale locale(localeString); - Collation collation = Default; - if (!collationString.isEmpty()) { - for (int i = 0; i < collationStringsCount; ++i) { - if (QLatin1String(collationStrings[i]) == collationString) { - collation = Collation(i); - break; - } - } - } - return QCollator(locale, collation); -} - -/*! - \enum QCollator::CasePreference - - This enum can be used to tailor the case preference during collation. - - \value CasePreferenceOff No case preference, use what is the standard for the locale - \value CasePreferenceUpper Sort upper case characters before lower case - \value CasePreferenceLower Sort lower case characters before upper case -*/ - -/*! - Sets the case \a preference of the collator. - - \sa QCollator::CasePreference - */ -void QCollator::setCasePreference(CasePreference preference) +void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs) { if (d->ref.load() != 1) detach(); #ifdef QT_USE_ICU - UColAttributeValue val = UCOL_OFF; - if (preference == QCollator::CasePreferenceUpper) - val = UCOL_UPPER_FIRST; - else if (preference == QCollator::CasePreferenceLower) - val = UCOL_LOWER_FIRST; + UColAttributeValue val = (cs == Qt::CaseSensitive) ? UCOL_UPPER_FIRST : UCOL_OFF; UErrorCode status = U_ZERO_ERROR; ucol_setAttribute(d->collator, UCOL_CASE_FIRST, val, &status); if (U_FAILURE(status)) qWarning("ucol_setAttribute: Case First failed: %d", status); #else - Q_UNUSED(preference); + Q_UNUSED(cs); #endif } /*! Returns case preference of the collator. - - \sa QCollator::CasePreference */ -QCollator::CasePreference QCollator::casePreference() const +Qt::CaseSensitivity QCollator::caseSensitivity() const { #ifdef QT_USE_ICU UErrorCode status = U_ZERO_ERROR; - switch (ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status)) { - case UCOL_UPPER_FIRST: - return QCollator::CasePreferenceUpper; - case UCOL_LOWER_FIRST: - return QCollator::CasePreferenceLower; - case UCOL_OFF: - default: - break; - } + UColAttributeValue attribute = ucol_getAttribute(d->collator, UCOL_CASE_FIRST, &status); + return (attribute == UCOL_OFF) ? Qt::CaseInsensitive : Qt::CaseSensitive; #endif - return QCollator::CasePreferenceOff; + return Qt::CaseSensitive; } /*! @@ -512,16 +376,16 @@ int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) con } /*! - Returns a sortKey for \a string. The sortkey can be used as a placeholder - for the string that can be then sorted using regular strcmp based sorting. + Returns a sortKey for \a string. - Creating the sort key is usually somewhat slower, then using the compare() + Creating the sort key is usually somewhat slower, than using the compare() methods directly. But if the string is compared repeatedly (e.g. when sorting a whole list of strings), it's usually faster to create the sort keys for each string and then sort using the keys. */ -QByteArray QCollator::sortKey(const QString &string) const +QCollatorSortKey QCollator::sortKey(const QString &string) const { + QByteArray key; #ifdef QT_USE_ICU QByteArray result(16 + string.size() + (string.size() >> 2), Qt::Uninitialized); int size = ucol_getSortKey(d->collator, (const UChar *)string.constData(), @@ -532,63 +396,91 @@ QByteArray QCollator::sortKey(const QString &string) const string.size(), (uint8_t *)result.data(), result.size()); } result.truncate(size); - return result; + key = result; #else - return string.toLower().toUtf8(); + key = string.toLatin1(); #endif + return QCollatorSortKey(new QCollatorSortKeyPrivate(key)); } -static QStringList englishIndexCharacters() +/*! + \fn bool QCollator::operator()(const QString &s1, const QString &s2) const + \internal +*/ + +/*! + \class QCollatorSortKey + \inmodule QtCore + \brief The QCollatorSortKey class can be used to speed up string collation. + + \since 5.2 + + The QCollatorSortKey class is always created by QCollator::sortKey() + and is used for fast strings collation, for example when collating many strings. + + \reentrant + \ingroup i18n + \ingroup string-processing + \ingroup shared + + \sa QCollator, QCollator::sortKey() +*/ + +/*! + \internal + */ +QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d) + : d(d) { - QString chars = QString::fromLatin1("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z"); - return chars.split(QLatin1Char(' '), QString::SkipEmptyParts); } /*! - Returns a string list of primary index characters. This is useful when presenting the - sorted list in a user interface with section headers. -*/ -QStringList QCollator::indexCharacters() const + Constructs a copy of the \a other collator sorting key. + */ +QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey& other) + : d(other.d) { - if (!d->indexCharacters.isEmpty()) - return d->indexCharacters; +} -#ifdef QT_USE_ICU - QByteArray id = identifier().toLatin1(); +/*! + Destroys the collator key. + */ +QCollatorSortKey::~QCollatorSortKey() +{ +} - UErrorCode status = U_ZERO_ERROR; - UResourceBundle *res = ures_open(NULL, id, &status); - - if (U_FAILURE(status)) { - d->indexCharacters = englishIndexCharacters(); - } else { - - qint32 len = 0; - status = U_ZERO_ERROR; - const UChar *val = ures_getStringByKey(res, "ExemplarCharactersIndex", &len, &status); - if (U_FAILURE(status)) { - d->indexCharacters = englishIndexCharacters(); - } else { - QString chars(reinterpret_cast<const QChar *>(val), len); - chars.remove('['); - chars.remove(']'); - chars.remove('{'); - chars.remove('}'); - d->indexCharacters = chars.split(QLatin1Char(' '), QString::SkipEmptyParts); - } +/*! + Assigns \a other to this collator key. + */ +QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other) +{ + if (this != &other) { + d = other.d; } + return *this; +} - ures_close(res); -#else - d->indexCharacters = englishIndexCharacters(); -#endif +/*! + According to the QCollator that created the key, returns true if the + key should be sorted before than \a otherKey; otherwise returns false. - return d->indexCharacters; + \sa compare() + */ +bool QCollatorSortKey::operator<(const QCollatorSortKey &otherKey) const +{ + return d->m_key < otherKey.d->m_key; } /*! - \fn bool QCollator::operator()(const QString &s1, const QString &s2) const - \internal -*/ + Compares the key to \a otherKey. 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. + + \sa operator<() + */ +int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const +{ + return qstrcmp(d->m_key, otherKey.d->m_key); +} QT_END_NAMESPACE diff --git a/src/corelib/tools/qcollator.h b/src/corelib/tools/qcollator.h index 02470c331f..677092c718 100644 --- a/src/corelib/tools/qcollator.h +++ b/src/corelib/tools/qcollator.h @@ -1,6 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org> ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -39,36 +40,46 @@ ** ****************************************************************************/ -#ifndef QCOLLATOR_P_H -#define QCOLLATOR_P_H +#ifndef QCOLLATOR_H +#define QCOLLATOR_H #include <QtCore/qstring.h> +#include <QtCore/qstringlist.h> #include <QtCore/qlocale.h> QT_BEGIN_NAMESPACE class QCollatorPrivate; +class QCollatorSortKeyPrivate; + +class Q_CORE_EXPORT QCollatorSortKey +{ + friend class QCollator; +public: + QCollatorSortKey(const QCollatorSortKey &other); + ~QCollatorSortKey(); + QCollatorSortKey &operator=(const QCollatorSortKey &other); +#ifdef Q_COMPILER_RVALUE_REFS + QCollatorSortKey &operator=(QCollatorSortKey &&other) + { qSwap(d, other.d); return *this; } +#endif + + bool operator<(const QCollatorSortKey &key) const; + int compare(const QCollatorSortKey &key) const; + +protected: + QCollatorSortKey(QCollatorSortKeyPrivate*); + + QSharedDataPointer<QCollatorSortKeyPrivate> d; + +private: + QCollatorSortKey(); +}; class Q_CORE_EXPORT QCollator { public: - enum Collation { - Default, - Big5Han, - Dictionary, - Direct, - GB2312Han, - PhoneBook, - Pinyin, - Phonetic, - Reformed, - Standard, - Stroke, - Traditional, - UniHan - }; - - QCollator(const QLocale &locale = QLocale(), QCollator::Collation collation = QCollator::Default); + QCollator(const QLocale &locale = QLocale()); QCollator(const QCollator &); ~QCollator(); QCollator &operator=(const QCollator &); @@ -76,20 +87,8 @@ public: void setLocale(const QLocale &locale); QLocale locale() const; - void setCollation(Collation collation); - Collation collation() const; - - QString identifier() const; - static QCollator fromIdentifier(const QString &identifier); - - enum CasePreference { - CasePreferenceOff = 0x0, - CasePreferenceUpper = 0x1, - CasePreferenceLower = 0x2 - }; - - CasePreference casePreference() const; - void setCasePreference(CasePreference preference); + Qt::CaseSensitivity caseSensitivity() const; + void setCaseSensitivity(Qt::CaseSensitivity cs); void setNumericMode(bool on); bool numericMode() const; @@ -104,15 +103,12 @@ public: bool operator()(const QString &s1, const QString &s2) const { return compare(s1, s2) < 0; } - QByteArray sortKey(const QString &string) const; - - QStringList indexCharacters() const; + QCollatorSortKey sortKey(const QString &string) const; private: QCollatorPrivate *d; void detach(); - void init(); }; QT_END_NAMESPACE |