summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/text/qlocale_tools.cpp92
-rw-r--r--src/corelib/text/qlocale_tools_p.h1
-rw-r--r--src/corelib/text/qstring.cpp13
3 files changed, 60 insertions, 46 deletions
diff --git a/src/corelib/text/qlocale_tools.cpp b/src/corelib/text/qlocale_tools.cpp
index 24a6bcfd09..bdb00d3696 100644
--- a/src/corelib/text/qlocale_tools.cpp
+++ b/src/corelib/text/qlocale_tools.cpp
@@ -460,6 +460,53 @@ qstrtoll(const char * nptr, const char **endptr, int base, bool *ok)
return result;
}
+static Q_ALWAYS_INLINE void qulltoBasicLatin_helper(qulonglong number, int base, char16_t *&p)
+{
+ // Performance-optimized code. Compiler can generate faster code when base is known.
+ switch (base) {
+#define BIG_BASE_LOOP(b) \
+ do { \
+ const int r = number % b; \
+ *--p = (r < 10 ? u'0' : u'a' - 10) + r; \
+ number /= b; \
+ } while (number)
+#ifndef __OPTIMIZE_SIZE__
+#define SMALL_BASE_LOOP(b) \
+ do { \
+ *--p = u'0' + number % b; \
+ number /= b; \
+ } while (number)
+
+ case 2: SMALL_BASE_LOOP(2); break;
+ case 8: SMALL_BASE_LOOP(8); break;
+ case 10: SMALL_BASE_LOOP(10); break;
+ case 16: BIG_BASE_LOOP(16); break;
+#undef SMALL_BASE_LOOP
+#endif
+ default: BIG_BASE_LOOP(base); break;
+#undef BIG_BASE_LOOP
+ }
+}
+
+// This is technically "qulonglong to ascii", but that name's taken
+QString qulltoBasicLatin(qulonglong number, int base, bool negative)
+{
+ if (number == 0)
+ return QStringLiteral("0");
+ // Length of MIN_LLONG with the sign in front is 65; we never need surrogate pairs.
+ // We do not need a terminator.
+ const unsigned maxlen = 65;
+ static_assert(CHAR_BIT * sizeof(number) + 1 <= maxlen);
+ char16_t buff[maxlen];
+ char16_t *const end = buff + maxlen, *p = end;
+
+ qulltoBasicLatin_helper(number, base, p);
+ if (negative)
+ *--p = u'-';
+
+ return QString(reinterpret_cast<QChar *>(p), end - p);
+}
+
QString qulltoa(qulonglong number, int base, const QStringView zero)
{
// Length of MAX_ULLONG in base 2 is 64; and we may need a surrogate pair
@@ -469,51 +516,8 @@ QString qulltoa(qulonglong number, int base, const QStringView zero)
char16_t buff[maxlen];
char16_t *const end = buff + maxlen, *p = end;
- // Performance-optimized code. Compiler can generate faster code when base is known.
if (base != 10 || zero == u"0") {
- switch (base) {
-#ifndef __OPTIMIZE_SIZE__
- case 10:
- while (number != 0) {
- const int c = number % 10;
- const qulonglong temp = number / 10;
- *--p = '0' + c;
- number = temp;
- }
- break;
- case 2:
- while (number != 0) {
- const int c = number % 2;
- const qulonglong temp = number / 2;
- *--p = '0' + c;
- number = temp;
- }
- break;
- case 8:
- while (number != 0) {
- const int c = number % 8;
- const qulonglong temp = number / 8;
- *--p = '0' + c;
- number = temp;
- }
- break;
- case 16:
- while (number != 0) {
- const int c = number % 16;
- const qulonglong temp = number / 16;
- *--p = c < 10 ? '0' + c : c - 10 + 'a';
- number = temp;
- }
- break;
-#endif
- default:
- while (number != 0) {
- const int c = number % base;
- const qulonglong temp = number / base;
- *--p = c < 10 ? '0' + c : c - 10 + 'a';
- number = temp;
- }
- }
+ qulltoBasicLatin_helper(number, base, p);
} else if (zero.size() && !zero.at(0).isSurrogate()) {
const char16_t zeroUcs2 = zero.at(0).unicode();
while (number != 0) {
diff --git a/src/corelib/text/qlocale_tools_p.h b/src/corelib/text/qlocale_tools_p.h
index e10408741e..fa6619d4a1 100644
--- a/src/corelib/text/qlocale_tools_p.h
+++ b/src/corelib/text/qlocale_tools_p.h
@@ -68,6 +68,7 @@ double qt_asciiToDouble(const char *num, qsizetype numLen, bool &ok, int &proces
void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize,
bool &sign, int &length, int &decpt);
+QString qulltoBasicLatin(qulonglong l, int base, bool negative);
QString qulltoa(qulonglong l, int base, const QStringView zero);
Q_CORE_EXPORT QString qdtoa(qreal d, int *decpt, int *sign);
diff --git a/src/corelib/text/qstring.cpp b/src/corelib/text/qstring.cpp
index 99534cb3d1..11caefc8ec 100644
--- a/src/corelib/text/qstring.cpp
+++ b/src/corelib/text/qstring.cpp
@@ -7307,7 +7307,16 @@ QString QString::number(qlonglong n, int base)
base = 10;
}
#endif
- return QLocaleData::c()->longLongToString(n, -1, base);
+QT_WARNING_PUSH
+ /* "unary minus operator applied to unsigned type, result still unsigned" */
+QT_WARNING_DISABLE_MSVC(4146)
+ bool negative = n < 0;
+ /*
+ Negating std::numeric_limits<qlonglong>::min() hits undefined behavior, so
+ taking an absolute value has to cast to unsigned to change sign.
+ */
+ return qulltoBasicLatin(negative ? -qulonglong(n) : qulonglong(n), base, negative);
+QT_WARNING_POP
}
/*!
@@ -7321,7 +7330,7 @@ QString QString::number(qulonglong n, int base)
base = 10;
}
#endif
- return QLocaleData::c()->unsLongLongToString(n, -1, base);
+ return qulltoBasicLatin(n, base, false);
}