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
44 \since 5.2
45
46 \reentrant
47 \ingroup i18n
48 \ingroup string-processing
49 \ingroup shared
50
51 QCollator is initialized with a QLocale. It can then be used to compare and
52 sort strings by using the ordering appropriate for that locale.
53
54 A QCollator object can be used together with template-based sorting
55 algorithms, such as std::sort(), to sort a list with QString entries.
56
57 \snippet code/src_corelib_text_qcollator.cpp 0
58
59 In addition to the locale, several optional flags can be set that influence
60 the result of the collation.
61
62 \section1 POSIX fallback implementation
63
64 On Unix systems, Qt is normally compiled to use ICU (except for \macos,
65 where Qt defaults to using an equivalent Apple API). However, if ICU was
66 not available at compile time or explicitly disabled, Qt will use a
67 fallback backend that uses the POSIX API only. This backend has several
68 limitations:
69
70 \list
71 \li Only the QLocale::c() and QLocale::system() locales are supported.
72 Consult the POSIX and C Standard Library manuals for the
73 \c{<locale.h>} header for more information on the system locale.
74 \li caseSensitivity() is not supported: only case-sensitive collation
75 can be performed.
76 \li numericMode() and ignorePunctuation() are not supported.
77 \endlist
78
79 The use of any of the unsupported options will cause a warning to be
80 printed to the application's output.
81*/
82
83/*!
84 \since 5.13
85
86 Constructs a QCollator using the default locale's collation locale.
87
88 The system locale, when used as default locale, may have a collation locale
89 other than itself (e.g. on Unix, if LC_COLLATE is set differently to LANG in
90 the environment). All other locales are their own collation locales.
91
92 \sa setLocale(), QLocale::collation(), QLocale::setDefault()
93*/
94QCollator::QCollator()
95 : d(nullptr)
96{
97}
98
99/*!
100 Constructs a QCollator using the given \a locale.
101
102 \sa setLocale()
103*/
104QCollator::QCollator(const QLocale &locale)
105 : d(new QCollatorPrivate(locale))
106{
107}
108
109/*!
110 Creates a copy of \a other.
111*/
112QCollator::QCollator(const QCollator &other)
113 : d(other.d)
114{
115 if (d) {
116 // Ensure clean, lest both copies try to init() at the same time:
117 d->ensureInitialized();
118 d->ref.ref();
119 }
120}
121
122/*!
123 Destroys this collator.
124*/
125QCollator::~QCollator()
126{
127 if (d && !d->ref.deref())
128 delete d;
129}
130
131/*!
132 Assigns \a other to this collator.
133*/
134QCollator &QCollator::operator=(const QCollator &other)
135{
136 if (this != &other) {
137 if (d && !d->ref.deref())
138 delete d;
139 d = other.d;
140 if (d) {
141 // Ensure clean, lest both copies try to init() at the same time:
142 d->ensureInitialized();
143 d->ref.ref();
144 }
145 }
146 return *this;
147}
148
149/*!
150 \fn QCollator::QCollator(QCollator &&other)
151
152 Move constructor. Moves from \a other into this collator.
153
154//! [partially-formed]
155 \note The moved-from object \a other is placed in a partially-formed state,
156 in which the only valid operations are destruction and assignment of a new
157 value.
158//! [partially-formed]
159*/
160
161/*!
162 \fn QCollator & QCollator::operator=(QCollator && other)
163
164 Move-assigns \a other to this QCollator instance.
165
166 \include qcollator.cpp partially-formed
167*/
168
169/*!
170 \fn void QCollator::swap(QCollator &other)
171 \memberswap{collator}
172*/
173
174bool comparesEqual(const QCollator &lhs, const QCollator &rhs) noexcept
175{
176 if (lhs.d == rhs.d)
177 return true;
178 if (!lhs.d || !rhs.d)
179 return false;
180
181 return lhs.d->caseSensitivity == rhs.d->caseSensitivity
182 && lhs.d->numericMode == rhs.d->numericMode
183 && lhs.d->ignorePunctuation == rhs.d->ignorePunctuation
184 && lhs.d->locale == rhs.d->locale;
185}
186
187/*!
188 \internal
189*/
190void QCollator::detach()
191{
192 if (!d) {
193 d = new QCollatorPrivate(QLocale().collation());
194 d->init();
195 } else if (d->ref.loadRelaxed() != 1) {
196 QCollatorPrivate *x = new QCollatorPrivate(d->locale);
197 if (!d->ref.deref())
198 delete d;
199 d = x;
200 }
201 // All callers need this, because about to modify the object:
202 d->dirty = true;
203}
204
205/*!
206 Sets the locale of the collator to \a locale.
207
208 \sa locale()
209*/
210void QCollator::setLocale(const QLocale &locale)
211{
212 if (locale == this->locale())
213 return;
214
215 detach();
216 d->locale = locale;
217}
218
219/*!
220 Returns the locale of the collator.
221
222 Unless supplied to the constructor or by calling setLocale(), the system's
223 default collation locale is used.
224
225 \sa setLocale(), QLocale::collation()
226*/
227QLocale QCollator::locale() const
228{
229 return d ? d->locale : QLocale().collation();
230}
231
232/*!
233 Sets the case-sensitivity of the collator to \a cs.
234
235 \sa caseSensitivity()
236*/
237void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
238{
239 if (cs == caseSensitivity())
240 return;
241
242 detach();
243 d->caseSensitivity = cs;
244}
245
246/*!
247 Returns case sensitivity of the collator.
248
249 This defaults to case-sensitive until set.
250
251 \note In the C locale, when case-sensitive, all lower-case letters sort
252 after all upper-case letters, where most locales sort each lower-case letter
253 either immediately before or immediately after its upper-case partner. Thus
254 "Zap" sorts before "ape" in the C locale but after in most others.
255
256 \sa setCaseSensitivity()
257*/
258Qt::CaseSensitivity QCollator::caseSensitivity() const
259{
260 return d ? d->caseSensitivity : Qt::CaseSensitive;
261}
262
263/*!
264 Enables numeric sorting mode when \a on is \c true.
265
266 \sa numericMode()
267*/
268void QCollator::setNumericMode(bool on)
269{
270 if (on == numericMode())
271 return;
272
273 detach();
274 d->numericMode = on;
275}
276
277/*!
278 Returns \c true if numeric sorting is enabled, \c false otherwise.
279
280 When \c true, numerals are recognized as numbers and sorted in arithmetic
281 order; for example, 100 sortes after 99. When \c false, numbers are sorted
282 in lexical order, so that 100 sorts before 99 (because 1 is before 9). By
283 default, this option is disabled.
284
285 \sa setNumericMode()
286*/
287bool QCollator::numericMode() const
288{
289 return d ? d->numericMode : false;
290}
291
292/*!
293 Ignores punctuation and symbols if \a on is \c true, attends to them if \c false.
294
295 \sa ignorePunctuation()
296*/
297void QCollator::setIgnorePunctuation(bool on)
298{
299 if (on == ignorePunctuation())
300 return;
301
302 detach();
303 d->ignorePunctuation = on;
304}
305
306/*!
307 Returns whether punctuation and symbols are ignored when collating.
308
309 When \c true, strings are compared as if all punctuation and symbols were
310 removed from each string.
311
312 \sa setIgnorePunctuation()
313*/
314bool QCollator::ignorePunctuation() const
315{
316 return d ? d->ignorePunctuation : false;
317}
318
319/*!
320 \since 5.13
321 \fn bool QCollator::operator()(QStringView s1, QStringView s2) const
322
323 A QCollator can be used as the comparison function of a sorting algorithm.
324 It returns \c true if \a s1 sorts before \a s2, otherwise \c false.
325
326 \sa compare()
327*/
328
329/*!
330 \since 5.13
331 \fn int QCollator::compare(QStringView s1, QStringView s2) const
332
333 Compares \a s1 with \a s2.
334
335 Returns a negative integer if \a s1 is less than \a s2, a positive integer
336 if it is greater than \a s2, and zero if they are equal.
337*/
338
339/*!
340 \fn bool QCollator::operator()(const QString &s1, const QString &s2) const
341 \overload
342 \since 5.2
343*/
344
345/*!
346 \fn int QCollator::compare(const QString &s1, const QString &s2) const
347 \overload
348 \since 5.2
349*/
350
351/*!
352 \fn int QCollator::compare(const QChar *s1, qsizetype len1, const QChar *s2, qsizetype len2) const
353 \overload
354 \since 5.2
355
356 Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the
357 QChar arrays pointed to by \a s1 and \a s2.
358
359 Returns a negative integer if \a s1 is less than \a s2, a positive integer
360 if it is greater than \a s2, and zero if they are equal.
361
362
363 \note In Qt versions prior to 6.4, the length arguments were of type
364 \c{int}, not \c{qsizetype}.
365*/
366
367/*!
368 \since 6.3
369
370 Compares the strings \a s1 and \a s2, returning their sorting order. This
371 function performs the same operation as compare() on a default-constructed
372 QCollator object.
373
374 \sa compare(), defaultSortKey()
375*/
376int QCollator::defaultCompare(QStringView s1, QStringView s2)
377{
378 return defaultCollator->localData().collator().compare(s1, s2);
379}
380
381/*!
382 \since 6.3
383
384 Returns the sort key for the string \a key. This function performs the same
385 operation as sortKey() on a default-constructed QCollator object.
386
387 \sa sortKey(), defaultCompare()
388*/
389QCollatorSortKey QCollator::defaultSortKey(QStringView key)
390{
391 return defaultCollator->localData().collator().sortKey(key.toString());
392}
393
394/*!
395 \fn QCollatorSortKey QCollator::sortKey(const QString &string) const
396
397 Returns a sortKey for \a string.
398
399 Creating the sort key is usually somewhat slower, than using the compare()
400 methods directly. But if the string is compared repeatedly (e.g. when
401 sorting a whole list of strings), it's usually faster to create the sort
402 keys for each string and then sort using the keys.
403
404 \note Not supported with the C (a.k.a. POSIX) locale on Darwin.
405*/
406
407/*!
408 \class QCollatorSortKey
409 \inmodule QtCore
410 \brief The QCollatorSortKey class can be used to speed up string collation.
411 \compares equality
412
413 \since 5.2
414
415 The QCollatorSortKey class is always created by QCollator::sortKey() and is
416 used for fast strings collation, for example when collating many strings.
417
418 \reentrant
419 \ingroup i18n
420 \ingroup string-processing
421 \ingroup shared
422
423 \sa QCollator, QCollator::sortKey(), compare()
424*/
425
426/*!
427 \internal
428*/
429QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d)
430 : d(d)
431{
432}
433
434/*!
435 Constructs a copy of the \a other collator key.
436*/
437QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey &other)
438 : d(other.d)
439{
440}
441
442/*!
443 \since 6.8
444 \fn QCollatorSortKey::QCollatorSortKey(QCollatorSortKey &&other)
445 Move-constructs a new QCollatorSortKey from \a other.
446
447 \include qcollator.cpp partially-formed
448*/
449
450/*!
451 Destroys the collator key.
452*/
453QCollatorSortKey::~QCollatorSortKey()
454{
455}
456
457/*!
458 Assigns \a other to this collator key.
459*/
460QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other)
461{
462 if (this != &other) {
463 d = other.d;
464 }
465 return *this;
466}
467
468/*!
469 \fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other)
470
471 Move-assigns \a other to this QCollatorSortKey instance.
472
473 \include qcollator.cpp partially-formed
474*/
475
476/*!
477 \fn bool QCollatorSortKey::operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
478
479 Both keys must have been created by the same QCollator's sortKey(). Returns
480 \c true if \a lhs should be sorted before \a rhs, according to the QCollator
481 that created them; otherwise returns \c false.
482
483 \sa QCollatorSortKey::compare()
484*/
485
486/*!
487 \fn void QCollatorSortKey::swap(QCollatorSortKey & other)
488 \memberswap{collator key}
489*/
490
491/*!
492 \fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
493
494 Compares this key to \a otherKey, which must have been created by the same
495 QCollator's sortKey() as this key. The comparison is performed in accordance
496 with that QCollator's sort order.
497
498 Returns a negative value if this key sorts before \a otherKey, 0 if the two
499 keys are equal or a positive value if this key sorts after \a otherKey.
500
501 \sa operator<()
502*/
503
504QT_END_NAMESPACE
Combined button and popup list for selecting options.
GenerationalCollator(const QCollator &copy)
Definition qcollator.cpp:24