34using ucol_getSortKey_t = int32_t (*)(
const UCollator*,
const UChar*, int32_t, uint8_t*, int32_t);
54void QCollatorPrivate::init()
60#if !QT_CONFIG(icu) && defined(Q_OS_ANDROID)
61 static bool icuLoaded = []() {
63 QLibrary icuLib(QStringLiteral(
"libicu"));
65 qWarning().nospace() <<
"ICU loading failed: " << icuLib.errorString()
66 <<
". Fallback collator will be used instead, not all features will be available.";
70 s_ucol.open =
reinterpret_cast<ucol_open_t>(icuLib.resolve(
"ucol_open"));
71 s_ucol.setAttribute =
reinterpret_cast<ucol_setAttribute_t>(icuLib.resolve(
"ucol_setAttribute"));
72 s_ucol.close =
reinterpret_cast<ucol_close_t>(icuLib.resolve(
"ucol_close"));
73 s_ucol.strcoll =
reinterpret_cast<ucol_strcoll_t>(icuLib.resolve(
"ucol_strcoll"));
74 s_ucol.getSortKey =
reinterpret_cast<ucol_getSortKey_t>(icuLib.resolve(
"ucol_getSortKey"));
75 s_ucol.errorName =
reinterpret_cast<u_errorName_t>(icuLib.resolve(
"u_errorName"));
76 return s_ucol.open && s_ucol.setAttribute && s_ucol.close && s_ucol.strcoll && s_ucol.getSortKey;
83 if (options.testFlag(Opt::DiacriticInsensitive) && options.testFlag(Opt::CaseInsensitive))
84 strength = UCOL_PRIMARY;
85 else if (options.testFlag(Opt::CaseInsensitive))
86 strength = UCOL_SECONDARY;
87 fallbackCollator = QtJniTypes::QtCollator::callStaticMethod<QtJniTypes::Collator>(
"getCollator", locale.bcp47Name(), strength);
93 auto errorName = [](UErrorCode status) ->
const char * {
94#if !QT_CONFIG(icu) && defined(Q_OS_ANDROID)
95 if (!s_ucol.errorName)
96 return "[Unknown ICU Error]";
98 const char *name = u_errorName(status);
100 return name ? name :
"[Unknown ICU Error]";
103 UErrorCode status = U_ZERO_ERROR;
104 QByteArray name = QLocalePrivate::get(locale)->bcp47Name(
'_');
105 collator = ucol_open(name.constData(), &status);
106 if (U_FAILURE(status)) {
107 if (status == U_FILE_ACCESS_ERROR)
108 qFatal(
"QCollator: ICU data file is not accessible: %s", errorName(status));
109 qCWarning(lcQCollator,
"Could not create collator: %s", errorName(status));
116 ucol_setAttribute(collator, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
125 if (options.testFlag(Opt::DiacriticInsensitive)) {
127 status = U_ZERO_ERROR;
128 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
129 if (U_FAILURE(status)) {
130 qCWarning(lcQCollator,
131 "ucol_setAttribute: Diacritic and case insensitivity failed: %s",
135 if (!options.testFlag(Opt::CaseInsensitive)) {
137 status = U_ZERO_ERROR;
138 ucol_setAttribute(collator, UCOL_CASE_LEVEL, UCOL_ON, &status);
139 if (U_FAILURE(status)) {
140 qCWarning(lcQCollator,
141 "ucol_setAttribute: Diacritic insensitivity with case distinction failed:"
142 " %s", errorName(status));
146 const UColAttributeValue strength
147 = options.testFlag(Opt::CaseInsensitive) ? UCOL_SECONDARY : UCOL_DEFAULT_STRENGTH;
149 status = U_ZERO_ERROR;
150 ucol_setAttribute(collator, UCOL_STRENGTH, strength, &status);
151 if (U_FAILURE(status)) {
152 qCWarning(lcQCollator,
"ucol_setAttribute: Case sensitivity failed: %s",
157 status = U_ZERO_ERROR;
158 ucol_setAttribute(collator, UCOL_NUMERIC_COLLATION,
159 options.testFlag(Opt::NumericSort) ? UCOL_ON : UCOL_OFF, &status);
160 if (U_FAILURE(status)) {
161 qCWarning(lcQCollator,
"ucol_setAttribute: numeric collation failed: %s",
165 status = U_ZERO_ERROR;
166 ucol_setAttribute(collator, UCOL_ALTERNATE_HANDLING,
167 options.testFlag(Opt::IgnorePunctuation) ? UCOL_SHIFTED
168 : UCOL_NON_IGNORABLE, &status);
169 if (U_FAILURE(status)) {
170 qCWarning(lcQCollator,
"ucol_setAttribute: Alternate handling failed: %s",
184int QCollator::compare(QStringView s1, QStringView s2)
const
187 return s2.size() ? -1 : 0;
192 d =
new QCollatorPrivate(QLocale().collation());
194 d->ensureInitialized();
198 return ucol_strcoll(d->collator,
199 reinterpret_cast<
const UChar *>(s1.data()), s1.size(),
200 reinterpret_cast<
const UChar *>(s2.data()), s2.size());
202#if !QT_CONFIG(icu) && defined(Q_OS_ANDROID)
203 else if (d->fallbackCollator.isValid()) {
204 return d->fallbackCollator.callMethod<
int>(
"compare", s1, s2);
208 return QtPrivate::compareStrings(s1, s2, caseSensitivity());
211QCollatorSortKey QCollator::sortKey(
const QString &string)
const
214 d =
new QCollatorPrivate(QLocale().collation());
216 d->ensureInitialized();
219 return QCollatorPrivate::sortKeyFromData(string.toUtf8());
222 QByteArray result(16 + string.size() + (string.size() >> 2), Qt::Uninitialized);
224 int size = ucol_getSortKey(d->collator, (
const UChar *)string.constData(),
225 string.size(), (uint8_t *)result.data(), result.size());
226 if (size > result.size()) {
228 size = ucol_getSortKey(d->collator, (
const UChar *)string.constData(),
229 string.size(), (uint8_t *)result.data(), result.size());
231 result.truncate(size);
232 return QCollatorPrivate::sortKeyFromData(std::move(result));
234#if !QT_CONFIG(icu) && defined(Q_OS_ANDROID)
235 else if (d->fallbackCollator.isValid()) {
236 return QCollatorPrivate::sortKeyFromData(QtJniTypes::QtCollator::callStaticMethod<QByteArray>(
"getCollationKey", d->fallbackCollator, string));
240 return QCollatorPrivate::sortKeyFromData(QByteArray());