Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qcollator.cpp
Go to the documentation of this file.
1
// Copyright (C) 2021 The Qt Company Ltd.
2
// Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org>
3
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
// Qt-Security score:critical reason:data-parser
5
6
#
include
"qcollator_p.h"
7
#
include
"qstringlist.h"
8
#
include
"qstring.h"
9
10
#
include
"qdebug.h"
11
#
include
"qlocale_p.h"
12
#
include
"qthreadstorage.h"
13
14
QT_BEGIN_NAMESPACE
15
QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QCollatorSortKeyPrivate)
16
Q_LOGGING_CATEGORY(lcQCollator,
"qt.core.qcollator"
)
17
18
namespace
{
19
struct
GenerationalCollator
20
{
21
QCollator
theCollator
;
22
int
generation
=
QLocalePrivate
::s_generation.loadRelaxed();
23
public
:
24
GenerationalCollator
() =
default
;
25
GenerationalCollator
(
const
QCollator ©) :
theCollator
(
copy
) {}
26
QCollator
&
collator
()
27
{
28
int
currentGeneration = QLocalePrivate::s_generation.loadRelaxed();
29
if
(Q_UNLIKELY(
generation
!= currentGeneration)) {
30
// reinitialize the collator
31
generation
= currentGeneration;
32
theCollator = QCollator();
33
}
34
return
theCollator;
35
}
36
};
37
class
GenerationalCollatorHolder
38
:
QThreadStorage
<
GenerationalCollator
>
39
{
40
public
:
41
~
GenerationalCollatorHolder
()
42
{
43
// Delete local data when the Q_GLOBAL_STATIC is destroyed.
44
// QThreadStorage's own cleanup for it runs too late, so we'd
45
// "leak" in an appless program.
46
clearLocalData();
47
}
48
49
using
QThreadStorage
<
GenerationalCollator
>::localData;
50
};
51
}
52
Q_GLOBAL_STATIC(GenerationalCollatorHolder, defaultCollator)
53
54
/*!
55
\class QCollator
56
\inmodule QtCore
57
\brief The QCollator class compares strings according to a localized collation algorithm.
58
\compares equality
59
60
\since 5.2
61
62
\reentrant
63
\ingroup i18n
64
\ingroup string-processing
65
\ingroup shared
66
67
QCollator is initialized with a QLocale. It can then be used to compare and
68
sort strings by using the ordering appropriate for that locale.
69
70
A QCollator object can be used together with template-based sorting
71
algorithms, such as std::sort(), to sort a list with QString entries.
72
73
\snippet code/src_corelib_text_qcollator.cpp 0
74
75
In addition to the locale, several optional flags can be set that influence
76
the result of the collation.
77
78
\section1 POSIX fallback implementation
79
80
On Unix systems, Qt is normally compiled to use ICU (except for \macos,
81
where Qt defaults to using an equivalent Apple API). However, if ICU was
82
not available at compile time or explicitly disabled, Qt will use a
83
fallback backend that uses the POSIX API only. This backend has several
84
limitations:
85
86
\list
87
\li Only the QLocale::c() and QLocale::system() locales are supported.
88
Consult the POSIX and C Standard Library manuals for the
89
\c{<locale.h>} header for more information on the system locale.
90
\li caseSensitivity() is not supported: only case-sensitive collation
91
can be performed.
92
\li The options set via numericMode(), ignorePunctuation(), and
93
options() are not supported.
94
\endlist
95
96
On Android systems, when not compiled to use an own copy of ICU Qt uses
97
the platform-provided ICU on Android 33 and newer. On older Android versions
98
it falls back to the Java Collator API, which has a few limitations:
99
100
\list
101
\li The IgnorePunctuation and NumericSort options are not supported.
102
\li The DiacriticInsensitive option only has an effect in combination
103
with CaseInsensitive also being set, using DiacriticInsensitive
104
without CaseInsensitive is not supported.
105
\endlist
106
107
The use of any of the unsupported options will cause a warning to be
108
printed to the application's output.
109
110
\section1 WebAssembly implementation
111
112
On WebAssembly, Qt uses the JavaScript \c{Intl.Collator} API as its
113
collation backend (unless ICU is available). This supports arbitrary
114
locales as well as numericMode(), caseSensitivity(), and ignorePunctuation().
115
\c{Intl.Collator} provides no sort-key extraction, so sortKey() produces
116
keys that delegate back to the collator when compared: their ordering
117
matches compare(), but they offer none of the performance benefit that sort
118
keys provide on the other backends (see QCollator::sortKey()).
119
*/
120
121
/*!
122
\since 6.13
123
\enum QCollator::CollationOption
124
125
Options that control how strings are compared by \l QCollator.
126
127
The \macos, Windows, and ICU backends support all options, with variations
128
where indicated. On non-\macos Unix (including Linux), if ICU is not
129
available a fallback (POSIX) backend is used, which supports none of
130
these options.
131
132
\value CaseInsensitive Ignore case differences when comparing strings.
133
134
\value IgnorePunctuation Ignore punctuation and symbols when comparing strings.
135
136
\value NumericSort Sort strings containing numbers by their numeric value,
137
so that for example "file10" sorts after "file9"
138
instead of between "file1" and "file2".
139
140
\value DiacriticInsensitive Ignore diacritical marks when comparing strings,
141
so that for example "e" and "é" compare as equal.
142
Depending on the locale, this may also include
143
ligature folding such as æ == ae.
144
See \l {DiacriticInsensitive behavior details}
145
below.
146
147
\value WidthInsensitive Treat CJK fullwidth and halfwidth forms of a
148
character as equivalent; for example, fullwidth
149
"A123" and halfwidth "A123", or fullwidth
150
Katakana "カ" and halfwidth "カ".
151
See \l {WidthInsensitive behavior details} below.
152
153
\section2 DiacriticInsensitive behavior details
154
155
This option is primarily intended for search and matching, where the user
156
may not type diacritics. For example, typing "resume" in a search field and
157
expecting to find "résumé".
158
159
The exact behavior depends on the locale and platform backend:
160
161
\list
162
\li Characters that are independent letters in a given alphabet are
163
not treated as diacritic variants. For example, in Swedish "å",
164
"ä" and "ö" are separate letters that sort after "z", so they
165
do not compare equal to "a" or "o", even with this option set.
166
Their position in the alphabet is also preserved. The same
167
characters may behave differently in another locale: in German,
168
"ö" and "ä" are treated as variants of "o" and "a" and do compare
169
equal to them with this option set.
170
\li Collation folding for locale-specific equivalences
171
(such as å == aa in Norwegian) is locale-dependent and works
172
consistently across backends. Note that this maps "å" to the
173
digraph "aa", not to a single "a"; "å" is an independent letter
174
and never folds to "a".
175
\li Ligature folding (such as ß == ss and æ == ae) is applied on
176
Windows and ICU, where the locale defines it; for example
177
"æ" folds to "ae" in English but is an independent letter in
178
Norwegian and does not fold. This folding is not supported by
179
the \macos backend. On Windows, some ligature folding is applied
180
implicitly, even without this option set.
181
\endlist
182
183
\section2 WidthInsensitive behavior details
184
185
Chinese, Japanese and Korean (CJK) characters are wider than those of
186
Latin-derived scripts. For compatibility, Unicode includes "fullwidth"
187
forms of European characters that have the same width as CJK characters,
188
as well as "halfwidth" forms of some CJK characters (for example,
189
Katakana) that have the narrower European width. These width variants are
190
formally separate characters in Unicode, but represent the same letter
191
or symbol. Users may enter text using input methods that produce either
192
form, and expect them to match when searching or comparing. This option
193
makes the fullwidth and halfwidth forms of the same character compare
194
as equal.
195
196
The exact behavior depends on the platform backend:
197
198
\list
199
\li On ICU, width sensitivity and case sensitivity are controlled
200
by the same collation strength level. As a result, in non-CJK
201
locales, this option has no effect unless CaseInsensitive option
202
is set. On the \macos and Windows backends, this option works
203
independently of case sensitivity.
204
\li In CJK locales, fullwidth and halfwidth forms may already
205
compare as equal on \macos and ICU backends due to
206
locale-specific collation rules, even without this option set.
207
On Windows, this option must be set explicitly.
208
\li The native Windows backend (without ICU) uses NLS
209
(\l {https://learn.microsoft.com/en-us/windows/win32/intl/national-language-support}
210
{National Language Support}) to handle language-specific sorting,
211
which gives a different default ordering of fullwidth and halfwidth
212
characters than
213
\l {https://en.wikipedia.org/wiki/Unicode_collation_algorithm}
214
{Unicode Collation Algorithm} based backends (\macos, ICU).
215
Setting this option makes them compare as equal on both.
216
\endlist
217
218
\sa setOptions(), options()
219
*/
220
221
/*!
222
\since 5.13
223
224
Constructs a QCollator using the default locale's collation locale.
225
226
The system locale, when used as default locale, may have a collation locale
227
other than itself (e.g. on Unix, if LC_COLLATE is set differently to LANG in
228
the environment). All other locales are their own collation locales.
229
230
\sa setLocale(), QLocale::collation(), QLocale::setDefault()
231
*/
232
QCollator::QCollator()
233
: d(
nullptr
)
234
{
235
}
236
237
/*!
238
Constructs a QCollator using the given \a locale.
239
240
\sa setLocale()
241
*/
242
QCollator::QCollator(
const
QLocale &locale)
243
: d(
new
QCollatorPrivate(locale))
244
{
245
}
246
247
/*!
248
Creates a copy of \a other.
249
*/
250
QCollator::QCollator(
const
QCollator &other)
251
: d(other.d)
252
{
253
if
(d) {
254
// Ensure clean, lest both copies try to init() at the same time:
255
d->ensureInitialized();
256
d->ref.ref();
257
}
258
}
259
260
/*!
261
Destroys this collator.
262
*/
263
QCollator::~QCollator()
264
{
265
if
(d && !d->ref.deref())
266
delete
d;
267
}
268
269
/*!
270
Assigns \a other to this collator.
271
*/
272
QCollator &QCollator::operator=(
const
QCollator &other)
273
{
274
if
(
this
!= &other) {
275
if
(d && !d->ref.deref())
276
delete
d;
277
d = other.d;
278
if
(d) {
279
// Ensure clean, lest both copies try to init() at the same time:
280
d->ensureInitialized();
281
d->ref.ref();
282
}
283
}
284
return
*
this
;
285
}
286
287
/*!
288
\fn QCollator::QCollator(QCollator &&other)
289
290
Move constructor. Moves from \a other into this collator.
291
292
//! [partially-formed]
293
\note The moved-from object \a other is placed in a partially-formed state,
294
in which the only valid operations are destruction and assignment of a new
295
value.
296
//! [partially-formed]
297
*/
298
299
/*!
300
\fn QCollator & QCollator::operator=(QCollator && other)
301
302
Move-assigns \a other to this QCollator instance.
303
304
\include qcollator.cpp partially-formed
305
*/
306
307
/*!
308
\fn void QCollator::swap(QCollator &other)
309
\memberswap{collator}
310
*/
311
312
/*!
313
\fn bool QCollator::operator==(const QCollator &lhs, const QCollator &rhs) noexcept
314
\fn bool QCollator::operator!=(const QCollator &lhs, const QCollator &rhs) noexcept
315
\since 6.12
316
317
Returns \c true if \a lhs and \a rhs use the same locale and collation
318
options, otherwise returns \c false.
319
*/
320
321
bool
comparesEqual(
const
QCollator &lhs,
const
QCollator &rhs)
noexcept
322
{
323
if
(lhs.d == rhs.d)
324
return
true
;
325
if
(!lhs.d || !rhs.d)
326
return
false
;
327
328
return
lhs.d->options == rhs.d->options
329
&& lhs.d->locale == rhs.d->locale;
330
}
331
332
/*!
333
\internal
334
*/
335
void
QCollator::detach()
336
{
337
if
(!d) {
338
d =
new
QCollatorPrivate(QLocale().collation());
339
d->init();
340
}
else
if
(d->ref.loadRelaxed() != 1) {
341
QCollatorPrivate *x =
new
QCollatorPrivate(d->locale);
342
x->options = d->options;
343
if
(!d->ref.deref())
344
delete
d;
345
d = x;
346
}
347
// All callers need this, because about to modify the object:
348
d->dirty =
true
;
349
}
350
351
/*!
352
Sets the locale of the collator to \a locale.
353
354
\sa locale()
355
*/
356
void
QCollator::setLocale(
const
QLocale &locale)
357
{
358
if
(locale ==
this
->locale())
359
return
;
360
361
detach();
362
d->locale = locale;
363
}
364
365
/*!
366
Returns the locale of the collator.
367
368
Unless supplied to the constructor or by calling setLocale(), the system's
369
default collation locale is used.
370
371
\sa setLocale(), QLocale::collation()
372
*/
373
QLocale QCollator::locale()
const
374
{
375
return
d ? d->locale : QLocale().collation();
376
}
377
378
/*!
379
Sets the case-sensitivity of the collator to \a cs.
380
381
\sa caseSensitivity()
382
*/
383
void
QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
384
{
385
if
(cs == caseSensitivity())
386
return
;
387
388
detach();
389
d->options.setFlag(CollationOption::CaseInsensitive, cs == Qt::CaseInsensitive);
390
}
391
392
/*!
393
Returns case sensitivity of the collator.
394
395
This defaults to case-sensitive until set.
396
397
\note In the C locale, when case-sensitive, all lower-case letters sort
398
after all upper-case letters, where most locales sort each lower-case letter
399
either immediately before or immediately after its upper-case partner. Thus
400
"Zap" sorts before "ape" in the C locale but after in most others.
401
402
\sa setCaseSensitivity()
403
*/
404
Qt::CaseSensitivity QCollator::caseSensitivity()
const
405
{
406
return
d && d->options.testFlag(CollationOption::CaseInsensitive) ? Qt::CaseInsensitive
407
: Qt::CaseSensitive;
408
}
409
410
/*!
411
Enables numeric sorting mode when \a on is \c true.
412
413
\sa numericMode()
414
*/
415
void
QCollator::setNumericMode(
bool
on)
416
{
417
if
(on == numericMode())
418
return
;
419
420
detach();
421
d->options.setFlag(CollationOption::NumericSort, on);
422
}
423
424
/*!
425
Returns \c true if numeric sorting is enabled, \c false otherwise.
426
427
When \c true, numerals are recognized as numbers and sorted in arithmetic
428
order; for example, 100 sortes after 99. When \c false, numbers are sorted
429
in lexical order, so that 100 sorts before 99 (because 1 is before 9). By
430
default, this option is disabled.
431
432
\sa setNumericMode()
433
*/
434
bool
QCollator::numericMode()
const
435
{
436
return
d && d->options.testFlag(CollationOption::NumericSort);
437
}
438
439
/*!
440
Ignores punctuation and symbols if \a on is \c true, attends to them if \c false.
441
442
\sa ignorePunctuation()
443
*/
444
void
QCollator::setIgnorePunctuation(
bool
on)
445
{
446
if
(on == ignorePunctuation())
447
return
;
448
449
detach();
450
d->options.setFlag(CollationOption::IgnorePunctuation, on);
451
}
452
453
/*!
454
Returns whether punctuation and symbols are ignored when collating.
455
456
When \c true, strings are compared as if all punctuation and symbols were
457
removed from each string.
458
459
\sa setIgnorePunctuation()
460
*/
461
bool
QCollator::ignorePunctuation()
const
462
{
463
return
d && d->options.testFlag(CollationOption::IgnorePunctuation);
464
}
465
466
/*!
467
\since 6.13
468
Sets the collation options to \a options.
469
This allows configuring multiple collation settings at once.
470
471
\note In the C locale, the collation options have no effect.
472
Use a specific locale to enable locale-aware collation.
473
474
\sa options(), CollationOption
475
*/
476
void
QCollator::setOptions(CollationOptions options)
477
{
478
if
(d && d->options == options)
479
return
;
480
detach();
481
d->options = options;
482
}
483
484
/*!
485
\since 6.13
486
Returns the collation options currently set on the collator.
487
488
\sa setOptions(), CollationOption
489
*/
490
QCollator::CollationOptions QCollator::options()
const
491
{
492
return
d ? d->options : CollationOptions{};
493
}
494
495
/*!
496
\since 5.13
497
\fn bool QCollator::operator()(QStringView s1, QStringView s2) const
498
499
A QCollator can be used as the comparison function of a sorting algorithm.
500
It returns \c true if \a s1 sorts before \a s2, otherwise \c false.
501
502
\sa compare()
503
*/
504
505
/*!
506
\since 5.13
507
\fn int QCollator::compare(QStringView s1, QStringView s2) const
508
509
Compares \a s1 with \a s2.
510
511
Returns a negative integer if \a s1 is less than \a s2, a positive integer
512
if it is greater than \a s2, and zero if they are equal.
513
*/
514
515
/*!
516
\fn bool QCollator::operator()(const QString &s1, const QString &s2) const
517
\overload
518
\since 5.2
519
*/
520
521
/*!
522
\fn int QCollator::compare(const QString &s1, const QString &s2) const
523
\overload
524
\since 5.2
525
*/
526
527
/*!
528
\fn int QCollator::compare(const QChar *s1, qsizetype len1, const QChar *s2, qsizetype len2) const
529
\overload
530
\since 5.2
531
532
Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the
533
QChar arrays pointed to by \a s1 and \a s2.
534
535
Returns a negative integer if \a s1 is less than \a s2, a positive integer
536
if it is greater than \a s2, and zero if they are equal.
537
538
539
\note In Qt versions prior to 6.4, the length arguments were of type
540
\c{int}, not \c{qsizetype}.
541
*/
542
543
/*!
544
\since 6.3
545
546
Compares the strings \a s1 and \a s2, returning their sorting order. This
547
function performs the same operation as compare() on a default-constructed
548
QCollator object.
549
550
\sa compare(), defaultSortKey()
551
*/
552
int
QCollator::defaultCompare(QStringView s1, QStringView s2)
553
{
554
return
defaultCollator->localData().collator().compare(s1, s2);
555
}
556
557
/*!
558
\since 6.3
559
560
Returns the sort key for the string \a key. This function performs the same
561
operation as sortKey() on a default-constructed QCollator object.
562
563
\sa sortKey(), defaultCompare()
564
*/
565
QCollatorSortKey QCollator::defaultSortKey(QStringView key)
566
{
567
return
defaultCollator->localData().collator().sortKey(key.toString());
568
}
569
570
/*!
571
\fn QCollatorSortKey QCollator::sortKey(const QString &string) const
572
573
Returns a sortKey for \a string.
574
575
Creating the sort key is usually somewhat slower, than using the compare()
576
methods directly. But if the string is compared repeatedly (e.g. when
577
sorting a whole list of strings), it's usually faster to create the sort
578
keys for each string and then sort using the keys.
579
580
\note Not supported with the C (a.k.a. POSIX) locale on Darwin.
581
\note Does not provide a performance improvement on Qt for WebAssembly
582
due to native API limitations.
583
*/
584
585
/*!
586
\class QCollatorSortKey
587
\inmodule QtCore
588
\brief The QCollatorSortKey class can be used to speed up string collation.
589
\compares weak
590
591
\since 5.2
592
593
The QCollatorSortKey class is always created by QCollator::sortKey() and is
594
used for fast strings collation, for example when collating many strings.
595
596
\reentrant
597
\ingroup i18n
598
\ingroup string-processing
599
\ingroup shared
600
601
\sa QCollator, QCollator::sortKey(), compare()
602
*/
603
604
/*!
605
\internal
606
*/
607
QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d)
608
: d(d)
609
{
610
}
611
612
/*!
613
Constructs a copy of the \a other collator key.
614
*/
615
QCollatorSortKey::QCollatorSortKey(
const
QCollatorSortKey &other)
616
: d(other.d)
617
{
618
}
619
620
/*!
621
\since 6.8
622
\fn QCollatorSortKey::QCollatorSortKey(QCollatorSortKey &&other)
623
Move-constructs a new QCollatorSortKey from \a other.
624
625
\include qcollator.cpp partially-formed
626
*/
627
628
/*!
629
Destroys the collator key.
630
*/
631
QCollatorSortKey::~QCollatorSortKey()
632
{
633
}
634
635
/*!
636
Assigns \a other to this collator key.
637
*/
638
QCollatorSortKey& QCollatorSortKey::operator=(
const
QCollatorSortKey &other)
639
{
640
if
(
this
!= &other) {
641
d = other.d;
642
}
643
return
*
this
;
644
}
645
646
/*!
647
\fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other)
648
649
Move-assigns \a other to this QCollatorSortKey instance.
650
651
\include qcollator.cpp partially-formed
652
*/
653
654
/*!
655
\fn bool QCollatorSortKey::operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
656
\fn bool QCollatorSortKey::operator<=(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
657
\fn bool QCollatorSortKey::operator>(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
658
\fn bool QCollatorSortKey::operator>=(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
659
\fn bool QCollatorSortKey::operator==(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
660
\fn bool QCollatorSortKey::operator!=(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
661
\since 6.12
662
663
Both keys must have been created by the same QCollator's sortKey(). Compares
664
\a lhs and \a rhs according to the QCollator that created them.
665
666
\sa QCollatorSortKey::compare()
667
*/
668
669
/*!
670
\fn void QCollatorSortKey::swap(QCollatorSortKey & other)
671
\memberswap{collator key}
672
*/
673
674
/*!
675
\fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const noexcept
676
677
Compares this key to \a otherKey, which must have been created by the same
678
QCollator's sortKey() as this key. The comparison is performed in accordance
679
with that QCollator's sort order.
680
681
Returns a negative value if this key sorts before \a otherKey, 0 if the
682
two keys are equal, or a positive value if this key sorts after \a otherKey.
683
684
\sa operator==(), operator!=(), operator<(), operator<=(),
685
operator>(), operator>=()
686
*/
687
688
QT_END_NAMESPACE
QT_BEGIN_NAMESPACE::GenerationalCollatorHolder
Definition
qcollator.cpp:39
QT_BEGIN_NAMESPACE::GenerationalCollatorHolder::~GenerationalCollatorHolder
~GenerationalCollatorHolder()
Definition
qcollator.cpp:41
QThreadStorage
\inmodule QtCore
Definition
qthreadstorage.h:159
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
QT_BEGIN_NAMESPACE::GenerationalCollator
Definition
qcollator.cpp:20
QT_BEGIN_NAMESPACE::GenerationalCollator::collator
QCollator & collator()
Definition
qcollator.cpp:26
QT_BEGIN_NAMESPACE::GenerationalCollator::GenerationalCollator
GenerationalCollator(const QCollator ©)
Definition
qcollator.cpp:25
QT_BEGIN_NAMESPACE::GenerationalCollator::generation
int generation
Definition
qcollator.cpp:22
QT_BEGIN_NAMESPACE::GenerationalCollator::GenerationalCollator
GenerationalCollator()=default
QT_BEGIN_NAMESPACE::GenerationalCollator::theCollator
QCollator theCollator
Definition
qcollator.cpp:21
qtbase
src
corelib
text
qcollator.cpp
Generated on
for Qt by
1.18.0