1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2013 Aleix Pol Gonzalez <aleixpol@kde.org>
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the QtCore module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 3 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL3 included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 3 requirements
24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
25**
26** GNU General Public License Usage
27** Alternatively, this file may be used under the terms of the GNU
28** General Public License version 2.0 or (at your option) the GNU General
29** Public license version 3 or any later version approved by the KDE Free
30** Qt Foundation. The licenses are as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
32** included in the packaging of this file. Please review the following
33** information to ensure the GNU General Public License requirements will
34** be met: https://www.gnu.org/licenses/gpl-2.0.html and
35** https://www.gnu.org/licenses/gpl-3.0.html.
36**
37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include "qcollator_p.h"
42#include "qstringlist.h"
43#include "qstring.h"
44
45#include "qdebug.h"
46
47QT_BEGIN_NAMESPACE
48
49/*!
50 \class QCollator
51 \inmodule QtCore
52 \brief The QCollator class compares strings according to a localized collation algorithm.
53
54 \since 5.2
55
56 \reentrant
57 \ingroup i18n
58 \ingroup string-processing
59 \ingroup shared
60
61 QCollator is initialized with a QLocale and an optional collation strategy.
62 It tries to initialize the collator with the specified values. The collator
63 can then be used to compare and sort strings in a locale dependent fashion.
64
65 A QCollator object can be used together with template based sorting
66 algorithms such as std::sort to sort a list of QStrings.
67
68 In addition to the locale and collation strategy, several optional flags can
69 be set that influence the result of the collation.
70*/
71
72/*!
73 \since 5.13
74
75 Constructs a QCollator using the system's default collation locale.
76
77 \sa setLocale(), QLocale::collation()
78*/
79QCollator::QCollator()
80 : d(new QCollatorPrivate(QLocale::system().collation()))
81{
82 d->init();
83}
84
85/*!
86 Constructs a QCollator from \a locale.
87
88 \sa setLocale()
89 */
90QCollator::QCollator(const QLocale &locale)
91 : d(new QCollatorPrivate(locale))
92{
93}
94
95/*!
96 Creates a copy of \a other.
97 */
98QCollator::QCollator(const QCollator &other)
99 : d(other.d)
100{
101 if (d) {
102 // Ensure clean, lest both copies try to init() at the same time:
103 if (d->dirty)
104 d->init();
105 d->ref.ref();
106 }
107}
108
109/*!
110 Destroys the collator.
111 */
112QCollator::~QCollator()
113{
114 if (d && !d->ref.deref())
115 delete d;
116}
117
118/*!
119 Assigns \a other to this collator.
120 */
121QCollator &QCollator::operator=(const QCollator &other)
122{
123 if (this != &other) {
124 if (d && !d->ref.deref())
125 delete d;
126 d = other.d;
127 if (d) {
128 // Ensure clean, lest both copies try to init() at the same time:
129 if (d->dirty)
130 d->init();
131 d->ref.ref();
132 }
133 }
134 return *this;
135}
136
137/*!
138 \fn QCollator::QCollator(QCollator &&other)
139
140 Move constructor. Moves from \a other into this collator.
141
142 Note that a moved-from QCollator can only be destroyed or assigned to.
143 The effect of calling other functions than the destructor or one of the
144 assignment operators is undefined.
145*/
146
147/*!
148 \fn QCollator & QCollator::operator=(QCollator && other)
149
150 Move-assigns from \a other to this collator.
151
152 Note that a moved-from QCollator can only be destroyed or assigned to.
153 The effect of calling other functions than the destructor or one of the
154 assignment operators is undefined.
155*/
156
157/*!
158 \fn void QCollator::swap(QCollator &other)
159
160 Swaps this collator with \a other. This function is very fast and
161 never fails.
162*/
163
164/*!
165 \internal
166 */
167void QCollator::detach()
168{
169 if (d->ref.loadRelaxed() != 1) {
170 QCollatorPrivate *x = new QCollatorPrivate(d->locale);
171 if (!d->ref.deref())
172 delete d;
173 d = x;
174 }
175 // All callers need this, because about to modify the object:
176 d->dirty = true;
177}
178
179/*!
180 Sets the locale of the collator to \a locale.
181 */
182void QCollator::setLocale(const QLocale &locale)
183{
184 if (locale == d->locale)
185 return;
186
187 detach();
188 d->locale = locale;
189}
190
191/*!
192 Returns the locale of the collator.
193 */
194QLocale QCollator::locale() const
195{
196 return d->locale;
197}
198
199/*!
200 \fn void QCollator::setCaseSensitivity(Qt::CaseSensitivity sensitivity)
201
202 Sets the case \a sensitivity of the collator.
203
204 \sa caseSensitivity()
205 */
206void QCollator::setCaseSensitivity(Qt::CaseSensitivity cs)
207{
208 if (d->caseSensitivity == cs)
209 return;
210
211 detach();
212 d->caseSensitivity = cs;
213}
214
215/*!
216 \fn Qt::CaseSensitivity QCollator::caseSensitivity() const
217
218 Returns case sensitivity of the collator.
219
220 \sa setCaseSensitivity()
221 */
222Qt::CaseSensitivity QCollator::caseSensitivity() const
223{
224 return d->caseSensitivity;
225}
226
227/*!
228 \fn void QCollator::setNumericMode(bool on)
229
230 Enables numeric sorting mode when \a on is set to true.
231
232 This will enable proper sorting of numeric digits, so that e.g. 100 sorts
233 after 99.
234
235 By default this mode is off.
236
237 \sa numericMode()
238 */
239void QCollator::setNumericMode(bool on)
240{
241 if (d->numericMode == on)
242 return;
243
244 detach();
245 d->numericMode = on;
246}
247
248/*!
249 \fn bool QCollator::numericMode() const
250
251 Returns \c true if numeric sorting is enabled, false otherwise.
252
253 \sa setNumericMode()
254 */
255bool QCollator::numericMode() const
256{
257 return d->numericMode;
258}
259
260/*!
261 \fn void QCollator::setIgnorePunctuation(bool on)
262
263 If \a on is set to true, punctuation characters and symbols are ignored when
264 determining sort order.
265
266 The default is locale dependent.
267
268 \note This method is not currently supported if Qt is configured to not use
269 ICU on Linux.
270
271 \sa ignorePunctuation()
272 */
273void QCollator::setIgnorePunctuation(bool on)
274{
275 if (d->ignorePunctuation == on)
276 return;
277
278 detach();
279 d->ignorePunctuation = on;
280}
281
282/*!
283 \fn bool QCollator::ignorePunctuation() const
284
285 Returns \c true if punctuation characters and symbols are ignored when
286 determining sort order.
287
288 \sa setIgnorePunctuation()
289 */
290bool QCollator::ignorePunctuation() const
291{
292 return d->ignorePunctuation;
293}
294
295/*!
296 \since 5.13
297 \fn bool QCollator::operator()(QStringView s1, QStringView s2) const
298 \internal
299*/
300
301/*!
302 \since 5.13
303 \fn int QCollator::compare(QStringView s1, QStringView s2) const
304
305 Compares \a s1 with \a s2.
306
307 Returns an integer less than, equal to, or greater than zero depending on
308 whether \a s1 sorts before, with or after \a s2.
309*/
310#if QT_STRINGVIEW_LEVEL < 2
311/*!
312 \fn bool QCollator::operator()(const QString &s1, const QString &s2) const
313 \internal
314*/
315
316/*!
317 \overload
318
319 Compares \a s1 with \a s2.
320
321 Returns an integer less than, equal to, or greater than zero depending on
322 whether \a s1 sorts before, with or after \a s2.
323*/
324int QCollator::compare(const QString &s1, const QString &s2) const
325{
326 return compare(QStringView(s1), QStringView(s2));
327}
328
329/*!
330 \overload
331
332 Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the
333 QChar arrays pointed to by \a s1 and \a s2.
334
335 Returns an integer less than, equal to, or greater than zero depending on
336 whether \a s1 sorts before, with or after \a s2.
337*/
338int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
339{
340 return compare(QStringView(s1, len1), QStringView(s2, len2));
341}
342#endif // QT_STRINGVIEW_LEVEL < 2
343
344/*!
345 \fn QCollatorSortKey QCollator::sortKey(const QString &string) const
346
347 Returns a sortKey for \a string.
348
349 Creating the sort key is usually somewhat slower, than using the compare()
350 methods directly. But if the string is compared repeatedly (e.g. when
351 sorting a whole list of strings), it's usually faster to create the sort
352 keys for each string and then sort using the keys.
353
354 \note Not supported with the C (a.k.a. POSIX) locale on Darwin.
355 */
356
357/*!
358 \class QCollatorSortKey
359 \inmodule QtCore
360 \brief The QCollatorSortKey class can be used to speed up string collation.
361
362 \since 5.2
363
364 The QCollatorSortKey class is always created by QCollator::sortKey() and is
365 used for fast strings collation, for example when collating many strings.
366
367 \reentrant
368 \ingroup i18n
369 \ingroup string-processing
370 \ingroup shared
371
372 \sa QCollator, QCollator::sortKey()
373*/
374
375/*!
376 \internal
377 */
378QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d)
379 : d(d)
380{
381}
382
383/*!
384 Constructs a copy of the \a other collator key.
385*/
386QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey &other)
387 : d(other.d)
388{
389}
390
391/*!
392 Destroys the collator key.
393 */
394QCollatorSortKey::~QCollatorSortKey()
395{
396}
397
398/*!
399 Assigns \a other to this collator key.
400 */
401QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other)
402{
403 if (this != &other) {
404 d = other.d;
405 }
406 return *this;
407}
408
409/*!
410 \fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other)
411
412 Move-assigns \a other to this collator key.
413*/
414
415/*!
416 \fn bool operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
417 \relates QCollatorSortKey
418
419 According to the QCollator that created the keys, returns \c true if \a lhs
420 should be sorted before \a rhs; otherwise returns \c false.
421
422 \sa QCollatorSortKey::compare()
423 */
424
425/*!
426 \fn void QCollatorSortKey::swap(QCollatorSortKey & other)
427
428 Swaps this collator key with \a other.
429*/
430
431/*!
432 \fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
433
434 Compares this key to \a otherKey.
435
436 Returns a negative value if the key is less than \a otherKey, 0 if the key
437 is equal to \a otherKey or a positive value if the key is greater than \a
438 otherKey.
439
440 \sa operator<()
441 */
442
443QT_END_NAMESPACE
444