summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2022-10-27 15:55:42 -0700
committerThiago Macieira <thiago.macieira@intel.com>2022-11-16 16:15:31 -0800
commitd50d34e5de7f5cf5e34243210e3df519974d7794 (patch)
treeff86a644a6dc271da7817767e1f7668d7b82ed25 /src
parent649dccf57b18626f6a0790d46e5e619e4e603078 (diff)
QLocale: make qstrnto(u)ll not have output arguments
That is, return everything in the return argument. On the SysV ABI, that means everything gets returned in registers, in both 32- and 64-bit platforms (unlike QtPrivate::ParsedNumber). There's a minor but perceptible performance improvement in parsing strings and byte arrays. Before: Parsed string "42" "1234" "-1548860221" Clock (ns) 16.673 18.878 25.517 CPU cycles 46.548 52.704 71.243 Instructions 201 233 331 After: Parsed string "42" "1234" "-1548860221" Clock (ns) 15.577 17.998 24.198 CPU cycles 43.491 49.942 67.552 Instructions 179 211 308 On my Core i7-1165G7 @ 2.80 GHz, the 22-23 instruction gain per iteration results in half the expected clock gain in runtime (22 / 2.8 GHz = 7.8 ns) because of a slightly lower instruction per cycle rate. That's acceptable because we need less speculative execution. Pick-to: 6.4 Task-number: QTBUG-107788 Change-Id: I07ec23f3cb174fb197c3fffd17220fd64d473cc0 Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/corelib/io/qipaddress.cpp12
-rw-r--r--src/corelib/io/qstorageinfo_unix.cpp29
-rw-r--r--src/corelib/text/qlocale.cpp14
-rw-r--r--src/corelib/text/qlocale_tools.cpp62
-rw-r--r--src/corelib/text/qlocale_tools_p.h13
-rw-r--r--src/corelib/text/qlocale_win.cpp10
-rw-r--r--src/corelib/text/qstring.cpp8
-rw-r--r--src/corelib/time/qtimezoneprivate_tz.cpp23
-rw-r--r--src/corelib/tools/qhash.cpp26
-rw-r--r--src/corelib/tools/qversionnumber.cpp9
10 files changed, 89 insertions, 117 deletions
diff --git a/src/corelib/io/qipaddress.cpp b/src/corelib/io/qipaddress.cpp
index eeb3d79b06..feed38bef6 100644
--- a/src/corelib/io/qipaddress.cpp
+++ b/src/corelib/io/qipaddress.cpp
@@ -60,11 +60,9 @@ static bool parseIp4Internal(IPv4Address &address, const char *ptr, bool acceptL
ptr[1] != '.' && ptr[1] != '\0')
return false;
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 0, &ok);
+ auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 0);
quint32 x = ll;
- if (!ok || endptr == ptr || ll != x)
+ if (!endptr || endptr == ptr || ll != x)
return false;
if (*endptr == '.' || dotCount == 3) {
@@ -176,15 +174,13 @@ const QChar *parseIp6(IPv6Address &address, const QChar *begin, const QChar *end
continue;
}
- const char *endptr;
- bool ok;
- quint64 ll = qstrntoull(ptr, stop - ptr, &endptr, 16, &ok);
+ auto [ll, endptr] = qstrntoull(ptr, stop - ptr, 16);
quint16 x = ll;
// Reject malformed fields:
// - failed to parse
// - too many hex digits
- if (!ok || endptr > ptr + 4)
+ if (!endptr || endptr > ptr + 4)
return begin + (ptr - buffer.data());
if (*endptr == '.') {
diff --git a/src/corelib/io/qstorageinfo_unix.cpp b/src/corelib/io/qstorageinfo_unix.cpp
index 5f3fa32482..be3bf0252d 100644
--- a/src/corelib/io/qstorageinfo_unix.cpp
+++ b/src/corelib/io/qstorageinfo_unix.cpp
@@ -451,32 +451,35 @@ inline bool QStorageIterator::next()
const char *const stop = ptr + len - 1;
// parse the line
- bool ok;
mnt.mnt_freq = 0;
mnt.mnt_passno = 0;
- mnt.mount_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ auto r = qstrntoll(ptr, stop - ptr, 10);
+ if (!r.ok())
return false;
+ mnt.mount_id = r.result;
- int parent_id = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- Q_UNUSED(parent_id);
- if (!ok)
+ r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ if (!r.ok())
return false;
+ int parent_id = r.result;
+ Q_UNUSED(parent_id);
- int rdevmajor = qstrntoll(ptr, stop - ptr, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ r = qstrntoll(r.endptr, stop - r.endptr, 10);
+ if (!r.ok())
return false;
- if (*ptr != ':')
+ if (*r.endptr != ':')
return false;
- int rdevminor = qstrntoll(ptr + 1, stop - ptr - 1, const_cast<const char **>(&ptr), 10, &ok);
- if (!ok)
+ int rdevmajor = r.result;
+ r = qstrntoll(r.endptr + 1, stop - r.endptr - 1, 10);
+ if (!r.ok())
return false;
- mnt.rdev = makedev(rdevmajor, rdevminor);
+ mnt.rdev = makedev(rdevmajor, r.result);
- if (*ptr != ' ')
+ if (*r.endptr != ' ')
return false;
+ ptr = const_cast<char *>(r.endptr);
mnt.subvolume = ++ptr;
ptr = parseMangledPath(ptr);
if (!ptr)
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp
index a6ba1931cb..16c80dd667 100644
--- a/src/corelib/text/qlocale.cpp
+++ b/src/corelib/text/qlocale.cpp
@@ -4147,11 +4147,8 @@ qulonglong QLocaleData::stringToUnsLongLong(QStringView str, int base, bool *ok,
qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *ok)
{
- bool _ok;
- const char *endptr;
- const qlonglong l = qstrntoll(num.data(), num.size(), &endptr, base, &_ok);
-
- if (!_ok || endptr == num.data()) {
+ auto [l, endptr] = qstrntoll(num.data(), num.size(), base);
+ if (!endptr) {
if (ok != nullptr)
*ok = false;
return 0;
@@ -4177,11 +4174,8 @@ qlonglong QLocaleData::bytearrayToLongLong(QByteArrayView num, int base, bool *o
qulonglong QLocaleData::bytearrayToUnsLongLong(QByteArrayView num, int base, bool *ok)
{
- bool _ok;
- const char *endptr;
- const qulonglong l = qstrntoull(num.data(), num.size(), &endptr, base, &_ok);
-
- if (!_ok || endptr == num.data()) {
+ auto [l, endptr] = qstrntoull(num.data(), num.size(), base);
+ if (!endptr) {
if (ok != nullptr)
*ok = false;
return 0;
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index f3e664ea41..76ea6c9f33 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -191,11 +191,10 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision,
// which case the missing digits are zeroes. In the 'e' case decptInTarget is always 1,
// as variants of snprintf always generate numbers with one digit before the '.' then.
// This is why the final decimal point is offset by 1, relative to the number after 'e'.
- bool ok;
- const char *endptr;
- decpt = qstrntoll(target.data() + eSign + 1, length - eSign - 1, &endptr, 10, &ok) + 1;
- Q_ASSERT(ok);
- Q_ASSERT(endptr - target.data() <= length);
+ auto r = qstrntoll(target.data() + eSign + 1, length - eSign - 1, 10);
+ decpt = r.result + 1;
+ Q_ASSERT(r.ok());
+ Q_ASSERT(r.endptr - target.data() <= length);
} else {
// No 'e' found, so it's the 'f' form. Variants of snprintf generate numbers with
// potentially multiple digits before the '.', but without decimal exponent then. So we
@@ -423,36 +422,25 @@ static bool isDigitForBase(char d, int base)
return false;
}
-unsigned long long
-qstrntoull(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
+QSimpleParsedNumber<qulonglong> qstrntoull(const char *begin, qsizetype size, int base)
{
const char *p = begin, *const stop = begin + size;
while (p < stop && ascii_isspace(*p))
++p;
unsigned long long result = 0;
- if (p >= stop || *p == '-') {
- *ok = false;
- if (endptr)
- *endptr = begin;
- return result;
- }
+ if (p >= stop || *p == '-')
+ return { };
const auto prefix = scanPrefix(*p == '+' ? p + 1 : p, stop, base);
- if (!prefix.base || prefix.next >= stop) {
- if (endptr)
- *endptr = begin;
- *ok = false;
- return 0;
- }
+ if (!prefix.base || prefix.next >= stop)
+ return { };
const auto res = std::from_chars(prefix.next, stop, result, prefix.base);
- *ok = res.ec == std::errc{};
- if (endptr)
- *endptr = res.ptr == prefix.next ? begin : res.ptr;
- return result;
+ if (res.ec != std::errc{})
+ return { };
+ return { result, res.ptr == prefix.next ? begin : res.ptr };
}
-long long
-qstrntoll(const char *begin, qsizetype size, const char **endptr, int base, bool *ok)
+QSimpleParsedNumber<qlonglong> qstrntoll(const char *begin, qsizetype size, int base)
{
const char *p = begin, *const stop = begin + size;
while (p < stop && ascii_isspace(*p))
@@ -467,30 +455,22 @@ qstrntoll(const char *begin, qsizetype size, const char **endptr, int base, bool
const auto prefix = scanPrefix(p, stop, base);
// Must check for digit, as from_chars() will accept a sign, which would be
// a second sign, that we should reject.
- if (!prefix.base || prefix.next >= stop || !isDigitForBase(*prefix.next, prefix.base)) {
- if (endptr)
- *endptr = begin;
- *ok = false;
- return 0;
- }
+ if (!prefix.base || prefix.next >= stop || !isDigitForBase(*prefix.next, prefix.base))
+ return { };
long long result = 0;
auto res = std::from_chars(prefix.next, stop, result, prefix.base);
- *ok = res.ec == std::errc{};
if (negate && res.ec == std::errc::result_out_of_range) {
// Maybe LLONG_MIN:
unsigned long long check = 0;
res = std::from_chars(prefix.next, stop, check, prefix.base);
- if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0) {
- *ok = true;
- if (endptr)
- *endptr = res.ptr;
- return std::numeric_limits<long long>::min();
- }
+ if (res.ec == std::errc{} && check + std::numeric_limits<long long>::min() == 0)
+ return { std::numeric_limits<long long>::min(), res.ptr };
+ return { };
}
- if (endptr)
- *endptr = res.ptr == prefix.next ? begin : res.ptr;
- return negate && *ok ? -result : result;
+ if (res.ec != std::errc{})
+ return { };
+ return { negate ? -result : result, res.ptr };
}
template <typename Char>
diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h
index 2f676eced5..b5eb4d344b 100644
--- a/src/corelib/text/qlocale_tools_p.h
+++ b/src/corelib/text/qlocale_tools_p.h
@@ -26,6 +26,13 @@ enum StrayCharacterMode {
WhitespacesAllowed
};
+template <typename T> struct QSimpleParsedNumber
+{
+ T result;
+ const char *endptr;
+ bool ok() { return endptr; }
+};
+
// API note: this function can't process a number with more than 2.1 billion digits
[[nodiscard]] double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &processed,
StrayCharacterMode strayCharMode = TrailingJunkProhibited);
@@ -81,10 +88,8 @@ template <typename UcsInt>
return qstrntod(s00, len, se, ok);
}
-[[nodiscard]] qlonglong qstrntoll(const char *nptr, qsizetype size, const char **endptr,
- int base, bool *ok);
-[[nodiscard]] qulonglong qstrntoull(const char *nptr, qsizetype size, const char **endptr,
- int base, bool *ok);
+[[nodiscard]] QSimpleParsedNumber<qlonglong> qstrntoll(const char *nptr, qsizetype size, int base);
+[[nodiscard]] QSimpleParsedNumber<qulonglong> qstrntoull(const char *nptr, qsizetype size, int base);
QT_END_NAMESPACE
diff --git a/src/corelib/text/qlocale_win.cpp b/src/corelib/text/qlocale_win.cpp
index 821369ff89..598de83b0e 100644
--- a/src/corelib/text/qlocale_win.cpp
+++ b/src/corelib/text/qlocale_win.cpp
@@ -1074,11 +1074,9 @@ static QString winIso639LangName(LCID id)
lang_code = QString::fromWCharArray(out);
if (!lang_code.isEmpty()) {
- const char *endptr;
- bool ok;
const QByteArray latin1 = std::move(lang_code).toLatin1();
- const auto i = qstrntoull(latin1.data(), latin1.size(), &endptr, 16, &ok);
- if (ok && *endptr == '\0') {
+ const auto [i, endptr] = qstrntoull(latin1.data(), latin1.size(), 16);
+ if (endptr && *endptr == '\0') {
switch (i) {
case 0x814:
result = u"nn"_s; // Nynorsk
@@ -1118,8 +1116,8 @@ static QByteArray getWinLocaleName(LCID id)
result = langEnvVar;
if (result == "C"
|| (!result.isEmpty() && qt_splitLocaleName(QString::fromLocal8Bit(result)))) {
- bool ok = false; // See if we have a Windows locale code instead of a locale name:
- long id = qstrntoll(result.data(), result.size(), 0, 0, &ok);
+ // See if we have a Windows locale code instead of a locale name:
+ auto [id, ok] = qstrntoll(result.data(), result.size(), 0);
if (!ok || id == 0 || id < INT_MIN || id > INT_MAX) // Assume real locale name
return result;
return winLangCodeToIsoName(int(id));
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 5984fa9c0a..4db2723be7 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -6887,14 +6887,14 @@ static int parse_field_width(const char *&c, qsizetype size)
// can't be negative - started with a digit
// contains at least one digit
- const char *endp;
- bool ok;
- const qulonglong result = qstrntoull(c, size, &endp, 10, &ok);
+ auto [result, endp] = qstrntoull(c, size, 10);
c = endp;
+ if (!endp)
+ return false;
// preserve Qt 5.5 behavior of consuming all digits, no matter how many
while (c < stop && qIsDigit(*c))
++c;
- return ok && result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
+ return result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0;
}
enum LengthMod { lm_none, lm_hh, lm_h, lm_l, lm_ll, lm_L, lm_j, lm_z, lm_t };
diff --git a/src/corelib/time/qtimezoneprivate_tz.cpp b/src/corelib/time/qtimezoneprivate_tz.cpp
index 099bccb071..d7c529ad10 100644
--- a/src/corelib/time/qtimezoneprivate_tz.cpp
+++ b/src/corelib/time/qtimezoneprivate_tz.cpp
@@ -392,27 +392,28 @@ static int parsePosixTime(const char *begin, const char *end)
int hour, min = 0, sec = 0;
const int maxHour = 137; // POSIX's extended range.
- bool ok = false;
- const char *cut = begin;
- hour = qstrntoll(begin, end - begin, &cut, 10, &ok);
- if (!ok || hour < -maxHour || hour > maxHour || cut > begin + 2)
+ auto r = qstrntoll(begin, end - begin, 10);
+ hour = r.result;
+ if (!r.ok() || hour < -maxHour || hour > maxHour || r.endptr > begin + 2)
return INT_MIN;
- begin = cut;
+ begin = r.endptr;
if (begin < end && *begin == ':') {
// minutes
++begin;
- min = qstrntoll(begin, end - begin, &cut, 10, &ok);
- if (!ok || min < 0 || min > 59 || cut > begin + 2)
+ r = qstrntoll(begin, end - begin, 10);
+ min = r.result;
+ if (!r.ok() || min < 0 || min > 59 || r.endptr > begin + 2)
return INT_MIN;
- begin = cut;
+ begin = r.endptr;
if (begin < end && *begin == ':') {
// seconds
++begin;
- sec = qstrntoll(begin, end - begin, &cut, 10, &ok);
- if (!ok || sec < 0 || sec > 59 || cut > begin + 2)
+ r = qstrntoll(begin, end - begin, 10);
+ sec = r.result;
+ if (!r.ok() || sec < 0 || sec > 59 || r.endptr > begin + 2)
return INT_MIN;
- begin = cut;
+ begin = r.endptr;
}
}
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 7ff53fe67e..a97fc50f3a 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -111,22 +111,18 @@ private:
#else
// can't use qEnvironmentVariableIntValue (reentrancy)
const char *seedstr = getenv("QT_HASH_SEED");
- const char *endptr = nullptr;
- bool ok = false;
- int seed = 0;
- if (seedstr)
- seed = qstrntoll(seedstr, strlen(seedstr), &endptr, 10, &ok);
- if (ok && endptr != seedstr + strlen(seedstr))
- ok = false;
- if (ok) {
- if (seed) {
- // can't use qWarning here (reentrancy)
- fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
+ if (seedstr) {
+ auto r = qstrntoll(seedstr, strlen(seedstr), 10);
+ if (r.endptr == seedstr + strlen(seedstr)) {
+ if (r.result) {
+ // can't use qWarning here (reentrancy)
+ fprintf(stderr, "QT_HASH_SEED: forced seed value is not 0; ignored.\n");
+ }
+
+ // we don't have to store to the seed, since it's pre-initialized by
+ // the compiler to zero
+ return result;
}
-
- // we don't have to store to the seed, since it's pre-initialized by
- // the compiler to zero
- return result;
}
// update the full seed
diff --git a/src/corelib/tools/qversionnumber.cpp b/src/corelib/tools/qversionnumber.cpp
index 7d6ddc9bcd..f44d5e4e8c 100644
--- a/src/corelib/tools/qversionnumber.cpp
+++ b/src/corelib/tools/qversionnumber.cpp
@@ -404,19 +404,18 @@ static QVersionNumber from_string(QLatin1StringView string, qsizetype *suffixInd
QVarLengthArray<int, 32> seg;
const char *start = string.begin();
- const char *end = start;
const char *lastGoodEnd = start;
const char *endOfString = string.end();
do {
- bool ok = false;
- const qulonglong value = qstrntoull(start, endOfString - start, &end, 10, &ok);
- if (!ok || value > qulonglong(std::numeric_limits<int>::max()))
+ // parsing as unsigned so a minus sign is rejected
+ auto [value, end] = qstrntoull(start, endOfString - start, 10);
+ if (!end || value > qulonglong(std::numeric_limits<int>::max()))
break;
seg.append(int(value));
start = end + 1;
lastGoodEnd = end;
- } while (start < endOfString && end < endOfString && *end == '.');
+ } while (start < endOfString && *lastGoodEnd == '.');
if (suffixIndex)
*suffixIndex = lastGoodEnd - string.begin();