1 | // Copyright (C) 2020 The Qt Company Ltd. |
---|---|
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #if 0 |
5 | // keep existing syncqt header working after the move of the class |
6 | // into qstringconverter_base |
7 | #pragma qt_class(QStringConverter) |
8 | #pragma qt_class(QStringConverterBase) |
9 | #endif |
10 | |
11 | #ifndef QSTRINGCONVERTER_H |
12 | #define QSTRINGCONVERTER_H |
13 | |
14 | #include <QtCore/qstringconverter_base.h> |
15 | #include <QtCore/qstring.h> |
16 | #include <QtCore/qstringbuilder.h> |
17 | |
18 | QT_BEGIN_NAMESPACE |
19 | |
20 | class QStringEncoder : public QStringConverter |
21 | { |
22 | protected: |
23 | constexpr explicit QStringEncoder(const Interface *i) noexcept |
24 | : QStringConverter(i) |
25 | {} |
26 | public: |
27 | constexpr QStringEncoder() noexcept |
28 | : QStringConverter() |
29 | {} |
30 | constexpr explicit QStringEncoder(Encoding encoding, Flags flags = Flag::Default) |
31 | : QStringConverter(encoding, flags) |
32 | {} |
33 | explicit QStringEncoder(QAnyStringView name, Flags flags = Flag::Default) |
34 | : QStringConverter(name, flags) |
35 | {} |
36 | |
37 | template<typename T> |
38 | struct DecodedData |
39 | { |
40 | QStringEncoder *encoder; |
41 | T data; |
42 | operator QByteArray() const { return encoder->encodeAsByteArray(in: data); } |
43 | }; |
44 | Q_WEAK_OVERLOAD |
45 | DecodedData<const QString &> operator()(const QString &str) |
46 | { return DecodedData<const QString &>{.encoder: this, .data: str}; } |
47 | DecodedData<QStringView> operator()(QStringView in) |
48 | { return DecodedData<QStringView>{.encoder: this, .data: in}; } |
49 | Q_WEAK_OVERLOAD |
50 | DecodedData<const QString &> encode(const QString &str) |
51 | { return DecodedData<const QString &>{.encoder: this, .data: str}; } |
52 | DecodedData<QStringView> encode(QStringView in) |
53 | { return DecodedData<QStringView>{.encoder: this, .data: in}; } |
54 | |
55 | qsizetype requiredSpace(qsizetype inputLength) const |
56 | { return iface ? iface->fromUtf16Len(inputLength) : 0; } |
57 | char *appendToBuffer(char *out, QStringView in) |
58 | { |
59 | if (!iface) { |
60 | state.invalidChars = 1; |
61 | return out; |
62 | } |
63 | return iface->fromUtf16(out, in, &state); |
64 | } |
65 | private: |
66 | QByteArray encodeAsByteArray(QStringView in) |
67 | { |
68 | if (!iface) { |
69 | // ensure that hasError returns true |
70 | state.invalidChars = 1; |
71 | return {}; |
72 | } |
73 | QByteArray result(iface->fromUtf16Len(in.size()), Qt::Uninitialized); |
74 | char *out = result.data(); |
75 | out = iface->fromUtf16(out, in, &state); |
76 | result.truncate(pos: out - result.constData()); |
77 | return result; |
78 | } |
79 | |
80 | }; |
81 | |
82 | class QStringDecoder : public QStringConverter |
83 | { |
84 | protected: |
85 | constexpr explicit QStringDecoder(const Interface *i) noexcept |
86 | : QStringConverter(i) |
87 | {} |
88 | public: |
89 | constexpr explicit QStringDecoder(Encoding encoding, Flags flags = Flag::Default) |
90 | : QStringConverter(encoding, flags) |
91 | {} |
92 | constexpr QStringDecoder() noexcept |
93 | : QStringConverter() |
94 | {} |
95 | explicit QStringDecoder(QAnyStringView name, Flags f = Flag::Default) |
96 | : QStringConverter(name, f) |
97 | {} |
98 | |
99 | template<typename T> |
100 | struct EncodedData |
101 | { |
102 | QStringDecoder *decoder; |
103 | T data; |
104 | operator QString() const { return decoder->decodeAsString(in: data); } |
105 | }; |
106 | Q_WEAK_OVERLOAD |
107 | EncodedData<const QByteArray &> operator()(const QByteArray &ba) |
108 | { return EncodedData<const QByteArray &>{.decoder: this, .data: ba}; } |
109 | EncodedData<QByteArrayView> operator()(QByteArrayView ba) |
110 | { return EncodedData<QByteArrayView>{.decoder: this, .data: ba}; } |
111 | Q_WEAK_OVERLOAD |
112 | EncodedData<const QByteArray &> decode(const QByteArray &ba) |
113 | { return EncodedData<const QByteArray &>{.decoder: this, .data: ba}; } |
114 | EncodedData<QByteArrayView> decode(QByteArrayView ba) |
115 | { return EncodedData<QByteArrayView>{.decoder: this, .data: ba}; } |
116 | |
117 | qsizetype requiredSpace(qsizetype inputLength) const |
118 | { return iface ? iface->toUtf16Len(inputLength) : 0; } |
119 | QChar *appendToBuffer(QChar *out, QByteArrayView ba) |
120 | { |
121 | if (!iface) { |
122 | state.invalidChars = 1; |
123 | return out; |
124 | } |
125 | return iface->toUtf16(out, ba, &state); |
126 | } |
127 | char16_t *appendToBuffer(char16_t *out, QByteArrayView ba) |
128 | { return reinterpret_cast<char16_t *>(appendToBuffer(out: reinterpret_cast<QChar *>(out), ba)); } |
129 | |
130 | Q_CORE_EXPORT static QStringDecoder decoderForHtml(QByteArrayView data); |
131 | |
132 | private: |
133 | QString decodeAsString(QByteArrayView in) |
134 | { |
135 | if (!iface) { |
136 | // ensure that hasError returns true |
137 | state.invalidChars = 1; |
138 | return {}; |
139 | } |
140 | QString result(iface->toUtf16Len(in.size()), Qt::Uninitialized); |
141 | const QChar *out = iface->toUtf16(result.data(), in, &state); |
142 | result.truncate(pos: out - result.constData()); |
143 | return result; |
144 | } |
145 | }; |
146 | |
147 | |
148 | #if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER) |
149 | template <typename T> |
150 | struct QConcatenable<QStringDecoder::EncodedData<T>> |
151 | : private QAbstractConcatenable |
152 | { |
153 | typedef QChar type; |
154 | typedef QString ConvertTo; |
155 | enum { ExactSize = false }; |
156 | static qsizetype size(const QStringDecoder::EncodedData<T> &s) { return s.decoder->requiredSpace(s.data.size()); } |
157 | static inline void appendTo(const QStringDecoder::EncodedData<T> &s, QChar *&out) |
158 | { |
159 | out = s.decoder->appendToBuffer(out, s.data); |
160 | } |
161 | }; |
162 | |
163 | template <typename T> |
164 | struct QConcatenable<QStringEncoder::DecodedData<T>> |
165 | : private QAbstractConcatenable |
166 | { |
167 | typedef char type; |
168 | typedef QByteArray ConvertTo; |
169 | enum { ExactSize = false }; |
170 | static qsizetype size(const QStringEncoder::DecodedData<T> &s) { return s.encoder->requiredSpace(s.data.size()); } |
171 | static inline void appendTo(const QStringEncoder::DecodedData<T> &s, char *&out) |
172 | { |
173 | out = s.encoder->appendToBuffer(out, s.data); |
174 | } |
175 | }; |
176 | |
177 | template <typename T> |
178 | QString &operator+=(QString &a, const QStringDecoder::EncodedData<T> &b) |
179 | { |
180 | qsizetype len = a.size() + QConcatenable<QStringDecoder::EncodedData<T>>::size(b); |
181 | a.reserve(asize: len); |
182 | QChar *it = a.data() + a.size(); |
183 | QConcatenable<QStringDecoder::EncodedData<T>>::appendTo(b, it); |
184 | a.resize(size: qsizetype(it - a.constData())); //may be smaller than len |
185 | return a; |
186 | } |
187 | |
188 | template <typename T> |
189 | QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b) |
190 | { |
191 | qsizetype len = a.size() + QConcatenable<QStringEncoder::DecodedData<T>>::size(b); |
192 | a.reserve(asize: len); |
193 | char *it = a.data() + a.size(); |
194 | QConcatenable<QStringEncoder::DecodedData<T>>::appendTo(b, it); |
195 | a.resize(size: qsizetype(it - a.constData())); //may be smaller than len |
196 | return a; |
197 | } |
198 | #endif |
199 | |
200 | template <typename InputIterator> |
201 | void QString::assign_helper_char8(InputIterator first, InputIterator last) |
202 | { |
203 | static_assert(!QString::is_contiguous_iterator_v<InputIterator>, |
204 | "Internal error: Should have been handed over to the QAnyStringView overload." |
205 | ); |
206 | |
207 | using ValueType = typename std::iterator_traits<InputIterator>::value_type; |
208 | constexpr bool IsFwdIt = std::is_convertible_v< |
209 | typename std::iterator_traits<InputIterator>::iterator_category, |
210 | std::forward_iterator_tag |
211 | >; |
212 | |
213 | resize(size: 0); |
214 | // In case of not being shared, there is the possibility of having free space at begin |
215 | // even after the resize to zero. |
216 | if (const auto offset = d.freeSpaceAtBegin()) |
217 | d.setBegin(d.begin() - offset); |
218 | |
219 | if constexpr (IsFwdIt) |
220 | reserve(asize: static_cast<qsizetype>(std::distance(first, last))); |
221 | |
222 | auto toUtf16 = QStringDecoder(QStringDecoder::Utf8); |
223 | auto availableCapacity = d.constAllocatedCapacity(); |
224 | auto *dst = d.data(); |
225 | auto *dend = d.data() + availableCapacity; |
226 | |
227 | while (true) { |
228 | if (first == last) { // ran out of input elements |
229 | Q_ASSERT(!std::less<>{}(dend, dst)); |
230 | d.size = dst - d.begin(); |
231 | return; |
232 | } |
233 | const ValueType next = *first; // decays proxies, if any |
234 | const auto chunk = QUtf8StringView(&next, 1); |
235 | // UTF-8 characters can have a maximum size of 4 bytes and may result in a surrogate |
236 | // pair of UTF-16 code units. In the input-iterator case, we don't know the size |
237 | // and would need to always reserve space for 2 code units. To keep our promise |
238 | // of 'not allocating if it fits', we have to pre-check this condition. |
239 | // We know that it fits in the forward-iterator case. |
240 | if constexpr (!IsFwdIt) { |
241 | constexpr qsizetype Pair = 2; |
242 | char16_t buf[Pair]; |
243 | const qptrdiff n = toUtf16.appendToBuffer(out: buf, ba: chunk) - buf; |
244 | if (dend - dst < n) { // ran out of allocated memory |
245 | const auto offset = dst - d.begin(); |
246 | reallocData(alloc: d.constAllocatedCapacity() + Pair, option: QArrayData::Grow); |
247 | // update the pointers since we've re-allocated |
248 | availableCapacity = d.constAllocatedCapacity(); |
249 | dst = d.data() + offset; |
250 | dend = d.data() + availableCapacity; |
251 | } |
252 | dst = std::copy_n(first: buf, n: n, result: dst); |
253 | } else { // take the fast path |
254 | dst = toUtf16.appendToBuffer(out: dst, ba: chunk); |
255 | } |
256 | ++first; |
257 | } |
258 | } |
259 | |
260 | QT_END_NAMESPACE |
261 | |
262 | #endif |
263 |
Definitions
- QStringEncoder
- QStringEncoder
- QStringEncoder
- QStringEncoder
- QStringEncoder
- DecodedData
- operator QByteArray
- operator()
- operator()
- encode
- encode
- requiredSpace
- appendToBuffer
- encodeAsByteArray
- QStringDecoder
- QStringDecoder
- QStringDecoder
- QStringDecoder
- QStringDecoder
- EncodedData
- operator QString
- operator()
- operator()
- decode
- decode
- requiredSpace
- appendToBuffer
- appendToBuffer
- decodeAsString
- QConcatenable
- size
- appendTo
- QConcatenable
- size
- appendTo
- operator+=
- operator+=
Learn Advanced QML with KDAB
Find out more