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