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

Provided by KDAB

Privacy Policy
Learn Advanced QML with KDAB
Find out more

source code of qtbase/src/corelib/text/qcollator.cpp