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

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