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