summaryrefslogtreecommitdiffstats
path: root/src/corelib/text/qstringconverter.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/text/qstringconverter.h')
-rw-r--r--src/corelib/text/qstringconverter.h115
1 files changed, 93 insertions, 22 deletions
diff --git a/src/corelib/text/qstringconverter.h b/src/corelib/text/qstringconverter.h
index 213de9fe55..055019836a 100644
--- a/src/corelib/text/qstringconverter.h
+++ b/src/corelib/text/qstringconverter.h
@@ -13,9 +13,7 @@
#include <QtCore/qstringconverter_base.h>
#include <QtCore/qstring.h>
-#if defined(QT_USE_FAST_OPERATOR_PLUS) || defined(QT_USE_QSTRINGBUILDER)
#include <QtCore/qstringbuilder.h>
-#endif
QT_BEGIN_NAMESPACE
@@ -32,16 +30,10 @@ public:
constexpr explicit QStringEncoder(Encoding encoding, Flags flags = Flag::Default)
: QStringConverter(encoding, flags)
{}
- explicit QStringEncoder(const char *name, Flags flags = Flag::Default) noexcept
+ explicit QStringEncoder(const char *name, Flags flags = Flag::Default)
: QStringConverter(name, flags)
{}
-#if defined(Q_QDOC)
- QByteArray operator()(const QString &in);
- QByteArray operator()(QStringView in);
- QByteArray encode(const QString &in);
- QByteArray encode(QStringView in);
-#else
template<typename T>
struct DecodedData
{
@@ -59,15 +51,25 @@ public:
{ return DecodedData<const QString &>{this, str}; }
DecodedData<QStringView> encode(QStringView in)
{ return DecodedData<QStringView>{this, in}; }
-#endif
qsizetype requiredSpace(qsizetype inputLength) const
- { return iface->fromUtf16Len(inputLength); }
+ { return iface ? iface->fromUtf16Len(inputLength) : 0; }
char *appendToBuffer(char *out, QStringView in)
- { return iface->fromUtf16(out, in, &state); }
+ {
+ if (!iface) {
+ state.invalidChars = 1;
+ return out;
+ }
+ return iface->fromUtf16(out, in, &state);
+ }
private:
QByteArray encodeAsByteArray(QStringView in)
{
+ if (!iface) {
+ // ensure that hasError returns true
+ state.invalidChars = 1;
+ return {};
+ }
QByteArray result(iface->fromUtf16Len(in.size()), Qt::Uninitialized);
char *out = result.data();
out = iface->fromUtf16(out, in, &state);
@@ -90,16 +92,10 @@ public:
constexpr QStringDecoder() noexcept
: QStringConverter()
{}
- explicit QStringDecoder(const char *name, Flags f = Flag::Default) noexcept
+ explicit QStringDecoder(const char *name, Flags f = Flag::Default)
: QStringConverter(name, f)
{}
-#if defined(Q_QDOC)
- QString operator()(const QByteArray &ba);
- QString operator()(QByteArrayView ba);
- QString decode(const QByteArray &ba);
- QString decode(QByteArrayView ba);
-#else
template<typename T>
struct EncodedData
{
@@ -117,15 +113,30 @@ public:
{ return EncodedData<const QByteArray &>{this, ba}; }
EncodedData<QByteArrayView> decode(QByteArrayView ba)
{ return EncodedData<QByteArrayView>{this, ba}; }
-#endif
qsizetype requiredSpace(qsizetype inputLength) const
- { return iface->toUtf16Len(inputLength); }
+ { return iface ? iface->toUtf16Len(inputLength) : 0; }
QChar *appendToBuffer(QChar *out, QByteArrayView ba)
- { return iface->toUtf16(out, ba, &state); }
+ {
+ if (!iface) {
+ state.invalidChars = 1;
+ return out;
+ }
+ return iface->toUtf16(out, ba, &state);
+ }
+ char16_t *appendToBuffer(char16_t *out, QByteArrayView ba)
+ { return reinterpret_cast<char16_t *>(appendToBuffer(reinterpret_cast<QChar *>(out), ba)); }
+
+ Q_CORE_EXPORT static QStringDecoder decoderForHtml(QByteArrayView data);
+
private:
QString decodeAsString(QByteArrayView in)
{
+ if (!iface) {
+ // ensure that hasError returns true
+ state.invalidChars = 1;
+ return {};
+ }
QString result(iface->toUtf16Len(in.size()), Qt::Uninitialized);
const QChar *out = iface->toUtf16(result.data(), in, &state);
result.truncate(out - result.constData());
@@ -186,6 +197,66 @@ QByteArray &operator+=(QByteArray &a, const QStringEncoder::DecodedData<T> &b)
}
#endif
+template <typename InputIterator>
+void QString::assign_helper_char8(InputIterator first, InputIterator last)
+{
+ static_assert(!QString::is_contiguous_iterator_v<InputIterator>,
+ "Internal error: Should have been handed over to the QAnyStringView overload."
+ );
+
+ using ValueType = typename std::iterator_traits<InputIterator>::value_type;
+ constexpr bool IsFwdIt = std::is_convertible_v<
+ typename std::iterator_traits<InputIterator>::iterator_category,
+ std::forward_iterator_tag
+ >;
+
+ resize(0);
+ // In case of not being shared, there is the possibility of having free space at begin
+ // even after the resize to zero.
+ if (const auto offset = d.freeSpaceAtBegin())
+ d.setBegin(d.begin() - offset);
+
+ if constexpr (IsFwdIt)
+ reserve(static_cast<qsizetype>(std::distance(first, last)));
+
+ auto toUtf16 = QStringDecoder(QStringDecoder::Utf8);
+ auto availableCapacity = d.constAllocatedCapacity();
+ auto *dst = d.data();
+ auto *dend = d.data() + availableCapacity;
+
+ while (true) {
+ if (first == last) { // ran out of input elements
+ Q_ASSERT(!std::less<>{}(dend, dst));
+ d.size = dst - d.begin();
+ return;
+ }
+ const ValueType next = *first; // decays proxies, if any
+ const auto chunk = QUtf8StringView(&next, 1);
+ // UTF-8 characters can have a maximum size of 4 bytes and may result in a surrogate
+ // pair of UTF-16 code units. In the input-iterator case, we don't know the size
+ // and would need to always reserve space for 2 code units. To keep our promise
+ // of 'not allocating if it fits', we have to pre-check this condition.
+ // We know that it fits in the forward-iterator case.
+ if constexpr (!IsFwdIt) {
+ constexpr qsizetype Pair = 2;
+ char16_t buf[Pair];
+ const qptrdiff n = toUtf16.appendToBuffer(buf, chunk) - buf;
+ if (dend - dst < n) { // ran out of allocated memory
+ const auto offset = dst - d.begin();
+ reallocData(d.constAllocatedCapacity() + Pair, QArrayData::Grow);
+ // update the pointers since we've re-allocated
+ availableCapacity = d.constAllocatedCapacity();
+ dst = d.data() + offset;
+ dend = d.data() + availableCapacity;
+ }
+ dst = std::copy_n(buf, n, dst);
+ } else { // take the fast path
+ dst = toUtf16.appendToBuffer(dst, chunk);
+ }
+ ++first;
+ }
+}
+
QT_END_NAMESPACE
#endif