summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2018-05-15 14:13:24 -0700
committerThiago Macieira <thiago.macieira@intel.com>2018-08-03 20:26:56 +0000
commitdc8d4fe30f2f88982166b5c593f90deb3964fb52 (patch)
tree8f5b2e08e2bdc0248e09b6f5af8a9c8f3d6851c5 /src/corelib/io
parent98dda3f5ac8e96fe34a343b4fc8cab1dc6939513 (diff)
QUrl: Add qustrchr() and use it to speed up the fast URL full decoding
The character search in the findChar() static function in qstring.cpp is more efficient than what we had in qurlrecode.cpp and there's no point in duplicating it. It also has a Neon implementation. So make the implementation available for use in QtPrivate::qustrchr(). This also simplifies the implementation. Change-Id: Ib48364abee9f464c96c6fffd152eedd0cd8ad7f8 Reviewed-by: Samuel Gaist <samuel.gaist@idiap.ch> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/qurlrecode.cpp84
1 files changed, 34 insertions, 50 deletions
diff --git a/src/corelib/io/qurlrecode.cpp b/src/corelib/io/qurlrecode.cpp
index 0c7b1df716..443ae18b21 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>