diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2022-11-02 11:42:39 -0700 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2023-02-20 17:30:44 +0000 |
commit | 97890c9ab4d63b9ee7e62287dd6bdd4bd2323677 (patch) | |
tree | 2b0da5e9e4ecf1c57953cc48456223fd3f8e6bec /src/corelib/text | |
parent | daceee6a9004565cee6ccd50c6a96216066b4f29 (diff) |
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>
Diffstat (limited to 'src/corelib/text')
-rw-r--r-- | src/corelib/text/qlocale.cpp | 2 | ||||
-rw-r--r-- | src/corelib/text/qlocale_p.h | 67 |
2 files changed, 61 insertions, 8 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index 0714434d2d..a80f982330 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -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'))); /****************************************************************************** diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index 831bfe9eda..2509193ba9 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -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 |