QLocale: modernize ascii_isspace() to C++17

And on 64-bit platforms, use a 64-bit integer, which removes a
subtraction from the matching code.

The loop in bytearrayToLongLong() looks like, on x86-64:

        movabsq $4294983168, %rsi
.L1217:
        movzbl  (%rdx), %ecx
        cmpl    $64, %ecx
        ja      .L1216
        btq     %rcx, %rsi
        jnc     .L1216
        incq    %rdx
        cmpq    %rbx, %rdx
        jne     .L1217

Change-Id: I3d74c753055744deb8acfffd1723d8b51e151432
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
bb10
Thiago Macieira 2022-11-02 11:42:39 -07:00 committed by Marc Mutz
parent daceee6a90
commit 97890c9ab4
2 changed files with 61 additions and 8 deletions

View File

@ -79,7 +79,7 @@ static_assert(!ascii_isspace('\a'));
static_assert(!ascii_isspace('a'));
static_assert(!ascii_isspace('\177'));
static_assert(!ascii_isspace(uchar('\200')));
static_assert(!ascii_isspace(uchar('\xA0')));
static_assert(!ascii_isspace(uchar('\xA0'))); // NBSP (is a space but Latin 1, not ASCII)
static_assert(!ascii_isspace(uchar('\377')));
/******************************************************************************

View File

@ -28,9 +28,67 @@
#include <limits>
#include <cmath>
#include <string_view>
QT_BEGIN_NAMESPACE
template <typename MaskType, uchar Lowest> struct QCharacterSetMatch
{
static constexpr int MaxRange = std::numeric_limits<MaskType>::digits;
MaskType mask;
constexpr QCharacterSetMatch(std::string_view set)
: mask(0)
{
for (char c : set) {
int idx = uchar(c) - Lowest;
mask |= MaskType(1) << idx;
}
}
constexpr bool matches(uchar c) const
{
unsigned idx = c - Lowest;
if (idx >= MaxRange)
return false;
return (mask >> idx) & 1;
}
};
namespace {
static constexpr char ascii_space_chars[] =
"\t" // 9: HT - horizontal tab
"\n" // 10: LF - line feed
"\v" // 11: VT - vertical tab
"\f" // 12: FF - form feed
"\r" // 13: CR - carriage return
" "; // 32: space
template <const char *Set, int ForcedLowest = -1> static constexpr auto makeCharacterSetMatch()
{
constexpr auto view = std::string_view(Set);
constexpr uchar MinElement = *std::min_element(view.begin(), view.end());
constexpr uchar MaxElement = *std::max_element(view.begin(), view.end());
constexpr int Range = MaxElement - MinElement;
static_assert(Range < 64, "Characters in the set are 64 or more values apart");
if constexpr (ForcedLowest >= 0) {
// use the force
static_assert(ForcedLowest <= int(MinElement), "The force is not with you");
using MaskType = std::conditional_t<MaxElement - ForcedLowest < 32, quint32, quint64>;
return QCharacterSetMatch<MaskType, ForcedLowest>(view);
} else if constexpr (MaxElement < std::numeric_limits<qregisteruint>::digits) {
// if we can use a Lowest of zero, we can remove a subtraction
// from the matches() code at runtime
using MaskType = std::conditional_t<(MaxElement < 32), quint32, qregisteruint>;
return QCharacterSetMatch<MaskType, 0>(view);
} else {
using MaskType = std::conditional_t<(Range < 32), quint32, quint64>;
return QCharacterSetMatch<MaskType, MinElement>(view);
}
}
} // unnamed namespace
struct QLocaleData;
// Subclassed by Android platform plugin:
class Q_CORE_EXPORT QSystemLocale
@ -477,15 +535,10 @@ QString qt_readEscapedFormatString(QStringView format, qsizetype *idx);
QStringView *script = nullptr, QStringView *cntry = nullptr);
[[nodiscard]] qsizetype qt_repeatCount(QStringView s);
enum { AsciiSpaceMask = (1u << (' ' - 1)) |
(1u << ('\t' - 1)) | // 9: HT - horizontal tab
(1u << ('\n' - 1)) | // 10: LF - line feed
(1u << ('\v' - 1)) | // 11: VT - vertical tab
(1u << ('\f' - 1)) | // 12: FF - form feed
(1u << ('\r' - 1)) }; // 13: CR - carriage return
[[nodiscard]] constexpr inline bool ascii_isspace(uchar c)
{
return c >= 1u && c <= 32u && (AsciiSpaceMask >> uint(c - 1)) & 1u;
constexpr auto matcher = makeCharacterSetMatch<ascii_space_chars>();
return matcher.matches(c);
}
QT_END_NAMESPACE