1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
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#ifndef QSTRINGITERATOR_H
7#define QSTRINGITERATOR_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include <QtCore/private/qglobal_p.h>
21#include <QtCore/qstring.h>
22
23QT_BEGIN_NAMESPACE
24
25class QStringIterator
26{
27 QString::const_iterator i, pos, e;
28 static_assert((std::is_same<QString::const_iterator, const QChar *>::value));
29 static bool less(const QChar *lhs, const QChar *rhs) noexcept
30 { return std::less{}(lhs, rhs); }
31public:
32 explicit QStringIterator(QStringView string, qsizetype idx = 0)
33 : i(string.begin()),
34 pos(i + idx),
35 e(string.end())
36 {
37 }
38
39 inline explicit QStringIterator(const QChar *begin, const QChar *end)
40 : i(begin),
41 pos(begin),
42 e(end)
43 {
44 }
45
46 explicit QStringIterator(const QChar *begin, qsizetype idx, const QChar *end)
47 : i(begin),
48 pos(begin + idx),
49 e(end)
50 {
51 }
52
53 inline QString::const_iterator position() const
54 {
55 return pos;
56 }
57
58 qsizetype index() const
59 {
60 return pos - i;
61 }
62
63 inline void setPosition(QString::const_iterator position)
64 {
65 Q_ASSERT_X(!less(position, i) && !less(e, position),
66 Q_FUNC_INFO, "position out of bounds");
67 pos = position;
68 }
69
70 // forward iteration
71
72 inline bool hasNext() const
73 {
74 return less(lhs: pos, rhs: e);
75 }
76
77 inline void advance()
78 {
79 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
80
81 if (Q_UNLIKELY((pos++)->isHighSurrogate())) {
82 if (Q_LIKELY(pos != e && pos->isLowSurrogate()))
83 ++pos;
84 }
85 }
86
87 inline void advanceUnchecked()
88 {
89 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
90
91 if (Q_UNLIKELY((pos++)->isHighSurrogate())) {
92 Q_ASSERT(hasNext() && pos->isLowSurrogate());
93 ++pos;
94 }
95 }
96
97 inline char32_t peekNextUnchecked() const
98 {
99 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
100
101 if (Q_UNLIKELY(pos->isHighSurrogate())) {
102 Q_ASSERT(less(pos + 1, e) && pos[1].isLowSurrogate());
103 return QChar::surrogateToUcs4(high: pos[0], low: pos[1]);
104 }
105
106 return pos->unicode();
107 }
108
109 inline char32_t peekNext(char32_t invalidAs = QChar::ReplacementCharacter) const
110 {
111 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
112
113 if (Q_UNLIKELY(pos->isSurrogate())) {
114 if (Q_LIKELY(pos->isHighSurrogate())) {
115 const QChar *low = pos + 1;
116 if (Q_LIKELY(low != e && low->isLowSurrogate()))
117 return QChar::surrogateToUcs4(high: *pos, low: *low);
118 }
119 return invalidAs;
120 }
121
122 return pos->unicode();
123 }
124
125 inline char32_t nextUnchecked()
126 {
127 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
128
129 const QChar cur = *pos++;
130 if (Q_UNLIKELY(cur.isHighSurrogate())) {
131 Q_ASSERT(hasNext() && pos->isLowSurrogate());
132 return QChar::surrogateToUcs4(high: cur, low: *pos++);
133 }
134 return cur.unicode();
135 }
136
137 inline char32_t next(char32_t invalidAs = QChar::ReplacementCharacter)
138 {
139 Q_ASSERT_X(hasNext(), Q_FUNC_INFO, "iterator hasn't a next item");
140
141 const QChar uc = *pos++;
142 if (Q_UNLIKELY(uc.isSurrogate())) {
143 if (Q_LIKELY(uc.isHighSurrogate() && hasNext() && pos->isLowSurrogate()))
144 return QChar::surrogateToUcs4(high: uc, low: *pos++);
145 return invalidAs;
146 }
147
148 return uc.unicode();
149 }
150
151 // backwards iteration
152
153 inline bool hasPrevious() const
154 {
155 return less(lhs: i, rhs: pos);
156 }
157
158 inline void recede()
159 {
160 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
161
162 if (Q_UNLIKELY((--pos)->isLowSurrogate())) {
163 const QChar *high = pos - 1;
164 if (Q_LIKELY(high != i - 1 && high->isHighSurrogate()))
165 --pos;
166 }
167 }
168
169 inline void recedeUnchecked()
170 {
171 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
172
173 if (Q_UNLIKELY((--pos)->isLowSurrogate())) {
174 Q_ASSERT(hasPrevious() && pos[-1].isHighSurrogate());
175 --pos;
176 }
177 }
178
179 inline char32_t peekPreviousUnchecked() const
180 {
181 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
182
183 if (Q_UNLIKELY(pos[-1].isLowSurrogate())) {
184 Q_ASSERT(less(i + 1, pos) && pos[-2].isHighSurrogate());
185 return QChar::surrogateToUcs4(high: pos[-2], low: pos[-1]);
186 }
187 return pos[-1].unicode();
188 }
189
190 inline char32_t peekPrevious(char32_t invalidAs = QChar::ReplacementCharacter) const
191 {
192 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
193
194 if (Q_UNLIKELY(pos[-1].isSurrogate())) {
195 if (Q_LIKELY(pos[-1].isLowSurrogate())) {
196 const QChar *high = pos - 2;
197 if (Q_LIKELY(high != i - 1 && high->isHighSurrogate()))
198 return QChar::surrogateToUcs4(high: *high, low: pos[-1]);
199 }
200 return invalidAs;
201 }
202
203 return pos[-1].unicode();
204 }
205
206 inline char32_t previousUnchecked()
207 {
208 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
209
210 const QChar cur = *--pos;
211 if (Q_UNLIKELY(cur.isLowSurrogate())) {
212 Q_ASSERT(hasPrevious() && pos[-1].isHighSurrogate());
213 return QChar::surrogateToUcs4(high: *--pos, low: cur);
214 }
215 return cur.unicode();
216 }
217
218 inline char32_t previous(char32_t invalidAs = QChar::ReplacementCharacter)
219 {
220 Q_ASSERT_X(hasPrevious(), Q_FUNC_INFO, "iterator hasn't a previous item");
221
222 const QChar uc = *--pos;
223 if (Q_UNLIKELY(uc.isSurrogate())) {
224 if (Q_LIKELY(uc.isLowSurrogate() && hasPrevious() && pos[-1].isHighSurrogate()))
225 return QChar::surrogateToUcs4(high: *--pos, low: uc);
226 return invalidAs;
227 }
228
229 return uc.unicode();
230 }
231};
232
233QT_END_NAMESPACE
234
235#endif // QSTRINGITERATOR_H
236

source code of qtbase/src/corelib/text/qstringiterator_p.h