diff options
Diffstat (limited to 'src/corelib/io/qurlrecode.cpp')
| -rw-r--r-- | src/corelib/io/qurlrecode.cpp | 84 |
1 files changed, 34 insertions, 50 deletions
diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp index 0c7b1df716a..443ae18b214 100644 --- a/src/corelib/io/qurlrecode.cpp +++ b/src/corelib/io/qurlrecode.cpp @@ -500,9 +500,7 @@ static bool simdCheckNonEncoded(ushort *&output, const ushort *&input, const ush __m256i data = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(input + offset)); __m256i comparison = _mm256_cmpeq_epi16(data, percents256); mask = _mm256_movemask_epi8(comparison); - - if (output) - _mm256_storeu_si256(reinterpret_cast<__m256i *>(output + offset), data); + _mm256_storeu_si256(reinterpret_cast<__m256i *>(output + offset), data); # else // do 32 bytes at a time using unrolled SSE2 __m128i data1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input + offset)); @@ -512,11 +510,9 @@ static bool simdCheckNonEncoded(ushort *&output, const ushort *&input, const ush uint mask1 = _mm_movemask_epi8(comparison1); uint mask2 = _mm_movemask_epi8(comparison2); - if (output) { - _mm_storeu_si128(reinterpret_cast<__m128i *>(output + offset), data1); - if (!mask1) - _mm_storeu_si128(reinterpret_cast<__m128i *>(output + offset + 8), data2); - } + _mm_storeu_si128(reinterpret_cast<__m128i *>(output + offset), data1); + if (!mask1) + _mm_storeu_si128(reinterpret_cast<__m128i *>(output + offset + 8), data2); mask = mask1 | (mask2 << 16); # endif @@ -534,21 +530,14 @@ static bool simdCheckNonEncoded(ushort *&output, const ushort *&input, const ush __m128i data = _mm_loadu_si128(reinterpret_cast<const __m128i *>(input)); __m128i comparison = _mm_cmpeq_epi16(data, percents); mask = _mm_movemask_epi8(comparison); - - // speculatively store everything - if (output) - _mm_storeu_si128(reinterpret_cast<__m128i *>(output), data); - + _mm_storeu_si128(reinterpret_cast<__m128i *>(output), data); idx = qCountTrailingZeroBits(quint16(mask)) / 2; } else if (input + 4 <= end) { // do 8 bytes only __m128i data = _mm_loadl_epi64(reinterpret_cast<const __m128i *>(input)); __m128i comparison = _mm_cmpeq_epi16(data, percents); mask = _mm_movemask_epi8(comparison) & 0xffu; - - if (output) - _mm_storel_epi64(reinterpret_cast<__m128i *>(output), data); - + _mm_storel_epi64(reinterpret_cast<__m128i *>(output), data); idx = qCountTrailingZeroBits(quint8(mask)) / 2; } else { // no percents found (because we didn't check) @@ -557,8 +546,7 @@ static bool simdCheckNonEncoded(ushort *&output, const ushort *&input, const ush // advance to the next non-encoded input += idx; - if (output) - output += idx; + output += idx; return !mask; } @@ -592,26 +580,22 @@ static bool simdCheckNonEncoded(...) */ static int decode(QString &appendTo, const ushort *begin, const ushort *end) { - const int origSize = appendTo.size(); - const ushort *input = begin; - ushort *output = 0; - while (input != end) { - if (simdCheckNonEncoded(output, input, end)) { - ushort uc = 0; - while (input != end) { - uc = *input; - if (uc == '%') - break; - if (output) - *output++ = uc; - ++input; - } + // fast check whether there's anything to be decoded in the first place + const ushort *input = QtPrivate::qustrchr(QStringView(begin, end), '%'); + if (Q_LIKELY(input == end)) + return 0; // nothing to do, it was already decoded! - if (uc != '%') - break; // we're done - } + // detach + const int origSize = appendTo.size(); + appendTo.resize(origSize + (end - begin)); + ushort *output = reinterpret_cast<ushort *>(appendTo.begin()) + origSize; + memcpy(static_cast<void *>(output), static_cast<const void *>(begin), (input - begin) * sizeof(ushort)); + output += input - begin; + while (input != end) { // something was encoded + Q_ASSERT(*input == '%'); + if (Q_UNLIKELY(end - input < 3 || !isHex(input[1]) || !isHex(input[2]))) { // badly-encoded data appendTo.resize(origSize + (end - begin)); @@ -619,27 +603,27 @@ static int decode(QString &appendTo, const ushort *begin, const ushort *end) return end - begin; } - if (Q_UNLIKELY(!output)) { - // detach - appendTo.resize(origSize + (end - begin)); - output = reinterpret_cast<ushort *>(appendTo.begin()) + origSize; - memcpy(static_cast<void *>(output), static_cast<const void *>(begin), (input - begin) * sizeof(ushort)); - output += input - begin; - } - ++input; *output++ = decodeNibble(input[0]) << 4 | decodeNibble(input[1]); if (output[-1] >= 0x80) output[-1] = QChar::ReplacementCharacter; input += 2; - } - if (output) { - int len = output - reinterpret_cast<ushort *>(appendTo.begin()); - appendTo.truncate(len); - return len - origSize; + // search for the next percent, copying from input to output + if (simdCheckNonEncoded(output, input, end)) { + while (input != end) { + ushort uc = *input; + if (uc == '%') + break; + *output++ = uc; + ++input; + } + } } - return 0; + + int len = output - reinterpret_cast<ushort *>(appendTo.begin()); + appendTo.truncate(len); + return len - origSize; } template <size_t N> |
