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 
47 QT_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 */
QCollator()79 QCollator::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  */
QCollator(const QLocale & locale)90 QCollator::QCollator(const QLocale &locale)
91     : d(new QCollatorPrivate(locale))
92 {
93 }
94 
95 /*!
96     Creates a copy of \a other.
97  */
QCollator(const QCollator & other)98 QCollator::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  */
~QCollator()112 QCollator::~QCollator()
113 {
114     if (d && !d->ref.deref())
115         delete d;
116 }
117 
118 /*!
119     Assigns \a other to this collator.
120  */
operator =(const QCollator & other)121 QCollator &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  */
detach()167 void 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  */
setLocale(const QLocale & locale)182 void 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  */
locale() const194 QLocale 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  */
setCaseSensitivity(Qt::CaseSensitivity cs)206 void 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  */
caseSensitivity() const222 Qt::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  */
setNumericMode(bool on)239 void 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  */
numericMode() const255 bool 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  */
setIgnorePunctuation(bool on)273 void 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  */
ignorePunctuation() const290 bool 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 */
compare(const QString & s1,const QString & s2) const324 int 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.
333 
334     Returns an integer less than, equal to, or greater than zero depending on
335     whether \a s1 sorts before, with or after \a s2.
336  */
compare(const QStringRef & s1,const QStringRef & s2) const337 int QCollator::compare(const QStringRef &s1, const QStringRef &s2) const
338 {
339     return compare(QStringView(s1), QStringView(s2));
340 }
341 
342 /*!
343     \overload
344 
345     Compares \a s1 with \a s2. \a len1 and \a len2 specify the lengths of the
346     QChar arrays pointed to by \a s1 and \a s2.
347 
348     Returns an integer less than, equal to, or greater than zero depending on
349     whether \a s1 sorts before, with or after \a s2.
350 */
compare(const QChar * s1,int len1,const QChar * s2,int len2) const351 int QCollator::compare(const QChar *s1, int len1, const QChar *s2, int len2) const
352 {
353     return compare(QStringView(s1, len1), QStringView(s2, len2));
354 }
355 #endif // QT_STRINGVIEW_LEVEL < 2
356 
357 /*!
358     \fn QCollatorSortKey QCollator::sortKey(const QString &string) const
359 
360     Returns a sortKey for \a string.
361 
362     Creating the sort key is usually somewhat slower, than using the compare()
363     methods directly. But if the string is compared repeatedly (e.g. when
364     sorting a whole list of strings), it's usually faster to create the sort
365     keys for each string and then sort using the keys.
366 
367     \note Not supported with the C (a.k.a. POSIX) locale on Darwin.
368  */
369 
370 /*!
371     \class QCollatorSortKey
372     \inmodule QtCore
373     \brief The QCollatorSortKey class can be used to speed up string collation.
374 
375     \since 5.2
376 
377     The QCollatorSortKey class is always created by QCollator::sortKey() and is
378     used for fast strings collation, for example when collating many strings.
379 
380     \reentrant
381     \ingroup i18n
382     \ingroup string-processing
383     \ingroup shared
384 
385     \sa QCollator, QCollator::sortKey()
386 */
387 
388 /*!
389     \internal
390  */
QCollatorSortKey(QCollatorSortKeyPrivate * d)391 QCollatorSortKey::QCollatorSortKey(QCollatorSortKeyPrivate *d)
392     : d(d)
393 {
394 }
395 
396 /*!
397     Constructs a copy of the \a other collator key.
398 */
QCollatorSortKey(const QCollatorSortKey & other)399 QCollatorSortKey::QCollatorSortKey(const QCollatorSortKey &other)
400     : d(other.d)
401 {
402 }
403 
404 /*!
405     Destroys the collator key.
406  */
~QCollatorSortKey()407 QCollatorSortKey::~QCollatorSortKey()
408 {
409 }
410 
411 /*!
412     Assigns \a other to this collator key.
413  */
operator =(const QCollatorSortKey & other)414 QCollatorSortKey& QCollatorSortKey::operator=(const QCollatorSortKey &other)
415 {
416     if (this != &other) {
417         d = other.d;
418     }
419     return *this;
420 }
421 
422 /*!
423     \fn QCollatorSortKey &QCollatorSortKey::operator=(QCollatorSortKey && other)
424 
425     Move-assigns \a other to this collator key.
426 */
427 
428 /*!
429     \fn bool operator<(const QCollatorSortKey &lhs, const QCollatorSortKey &rhs)
430     \relates QCollatorSortKey
431 
432     According to the QCollator that created the keys, returns \c true if \a lhs
433     should be sorted before \a rhs; otherwise returns \c false.
434 
435     \sa QCollatorSortKey::compare()
436  */
437 
438 /*!
439     \fn void QCollatorSortKey::swap(QCollatorSortKey & other)
440 
441     Swaps this collator key with \a other.
442 */
443 
444 /*!
445     \fn int QCollatorSortKey::compare(const QCollatorSortKey &otherKey) const
446 
447     Compares this key to \a otherKey.
448 
449     Returns a negative value if the key is less than \a otherKey, 0 if the key
450     is equal to \a otherKey or a positive value if the key is greater than \a
451     otherKey.
452 
453     \sa operator<()
454  */
455 
456 QT_END_NAMESPACE
457