1 | // Copyright (C) 2016 Intel Corporation. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QSTRINGALGORITHMS_P_H |
5 | #define QSTRINGALGORITHMS_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists for the convenience |
12 | // of internal files. This header file may change from version to version |
13 | // without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include "qstring.h" |
19 | #include "qlocale_p.h" // for ascii_isspace |
20 | |
21 | QT_BEGIN_NAMESPACE |
22 | |
23 | template <typename StringType> struct QStringAlgorithms |
24 | { |
25 | typedef typename StringType::value_type Char; |
26 | typedef typename StringType::size_type size_type; |
27 | typedef typename std::remove_cv<StringType>::type NakedStringType; |
28 | static const bool isConst = std::is_const<StringType>::value; |
29 | |
30 | static inline bool isSpace(char ch) { return ascii_isspace(c: ch); } |
31 | static inline bool isSpace(QChar ch) { return ch.isSpace(); } |
32 | |
33 | // Surrogate pairs are not handled in either of the functions below. That is |
34 | // not a problem because there are no space characters (Zs, Zl, Zp) outside the |
35 | // Basic Multilingual Plane. |
36 | |
37 | static inline StringType trimmed_helper_inplace(NakedStringType &str, const Char *begin, const Char *end) |
38 | { |
39 | // in-place trimming: |
40 | Char *data = const_cast<Char *>(str.cbegin()); |
41 | if (begin != data) |
42 | memmove(data, begin, (end - begin) * sizeof(Char)); |
43 | str.resize(end - begin); |
44 | return std::move(str); |
45 | } |
46 | |
47 | static inline StringType trimmed_helper_inplace(const NakedStringType &, const Char *, const Char *) |
48 | { |
49 | // can't happen |
50 | Q_UNREACHABLE_RETURN(StringType()); |
51 | } |
52 | |
53 | static inline void trimmed_helper_positions(const Char *&begin, const Char *&end) |
54 | { |
55 | // skip white space from end |
56 | while (begin < end && isSpace(end[-1])) |
57 | --end; |
58 | // skip white space from start |
59 | while (begin < end && isSpace(*begin)) |
60 | begin++; |
61 | } |
62 | |
63 | static inline StringType trimmed_helper(StringType &str) |
64 | { |
65 | const Char *begin = str.cbegin(); |
66 | const Char *end = str.cend(); |
67 | trimmed_helper_positions(begin, end); |
68 | |
69 | if (begin == str.cbegin() && end == str.cend()) |
70 | return str; |
71 | if (!isConst && str.isDetached()) |
72 | return trimmed_helper_inplace(str, begin, end); |
73 | return StringType(begin, end - begin); |
74 | } |
75 | |
76 | static inline StringType simplified_helper(StringType &str) |
77 | { |
78 | if (str.isEmpty()) |
79 | return str; |
80 | const Char *src = str.cbegin(); |
81 | const Char *end = str.cend(); |
82 | NakedStringType result = isConst || !str.isDetached() ? |
83 | StringType(str.size(), Qt::Uninitialized) : |
84 | std::move(str); |
85 | |
86 | Char *dst = const_cast<Char *>(result.cbegin()); |
87 | Char *ptr = dst; |
88 | bool unmodified = true; |
89 | forever { |
90 | while (src != end && isSpace(*src)) |
91 | ++src; |
92 | while (src != end && !isSpace(*src)) |
93 | *ptr++ = *src++; |
94 | if (src == end) |
95 | break; |
96 | if (*src != QChar::Space) |
97 | unmodified = false; |
98 | *ptr++ = QChar::Space; |
99 | } |
100 | if (ptr != dst && ptr[-1] == QChar::Space) |
101 | --ptr; |
102 | |
103 | qsizetype newlen = ptr - dst; |
104 | if (isConst && newlen == str.size() && unmodified) { |
105 | // nothing happened, return the original |
106 | return str; |
107 | } |
108 | result.resize(newlen); |
109 | return result; |
110 | } |
111 | }; |
112 | |
113 | QT_END_NAMESPACE |
114 | |
115 | #endif // QSTRINGALGORITHMS_P_H |
116 | |