QLocale tools: add q(u)int128toBasicLatin()

Add q(u)int128toBasicLatin() as helper functions until QString::number()
natively supports q(u)int128.

Change-Id: I920dff145eaa4e849d1f340ca5d5491d2da2821a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Christian Ehrlicher 2024-04-26 22:33:54 +02:00
parent 28fd273080
commit 9d693dbfb1
2 changed files with 90 additions and 0 deletions

View File

@ -807,4 +807,78 @@ QByteArray qdtoAscii(double d, QLocaleData::DoubleForm form, int precision, bool
return dtoString<QByteArray>(d, form, precision, uppercase);
}
#if defined(QT_SUPPORTS_INT128) || (defined(Q_CC_MSVC) && (_MSC_VER >= 1930))
static inline quint64 toUInt64(qinternaluint128 v)
{
#ifdef Q_CC_MSVC
return quint64(v._Word[0]);
#else
return quint64(v);
#endif
}
QString quint128toBasicLatin(qinternaluint128 number, int base)
{
// We divide our 128-bit number into parts that we can do text
// concatenation with. This list is the maximum power of the
// base that is less than 2^64.
static constexpr auto dividers = []() constexpr {
std::array<quint64, 35> bases {};
for (int base = 2; base <= 36; ++base) {
quint64 v = base;
while (v * base > v)
v *= base;
bases[base - 2] = v;
}
return bases;
}();
static constexpr auto digitCounts = []() constexpr {
std::array<quint8, 35> digits{};
for (int base = 2; base <= 36; ++base) {
quint64 v = base;
int i = 0;
for (i = 0; v * base > v; ++i)
v *= base;
digits[base - 2] = i;
}
return digits;
}();
QString result;
constexpr unsigned flags = QLocaleData::NoFlags;
const QLocaleData *dd = QLocaleData::c();
// special base cases:
constexpr int Width = -1;
if (base == 2 || base == 4 || base == 16) {
// 2^64 is a power of 2, 4 and 16
result = dd->unsLongLongToString(quint64(number), 64, base, Width, flags);
result.prepend(dd->unsLongLongToString(quint64(number >> 64), -1, base, Width, flags));
} else {
int digitCount = digitCounts[base - 2];
quint64 divider = dividers[base - 2];
quint64 lower = toUInt64(number % divider);
number /= divider;
while (number) {
result.prepend(dd->unsLongLongToString(lower, digitCount, base, Width, flags));
lower = toUInt64(number % divider);
number /= divider;
}
result.prepend(dd->unsLongLongToString(lower, -1, base, Width, flags));
}
return result;
}
QString qint128toBasicLatin(qinternalint128 number, int base)
{
const bool negative = number < 0;
if (negative)
number *= -1;
QString result = quint128toBasicLatin(qinternaluint128(number), base);
if (negative)
result.prepend(u'-');
return result;
}
#endif // defined(QT_SUPPORTS_INT128) || (defined(Q_CC_MSVC) && (_MSC_VER >= 1930))
QT_END_NAMESPACE

View File

@ -20,6 +20,15 @@
QT_BEGIN_NAMESPACE
#if defined(QT_SUPPORTS_INT128)
using qinternalint128 = qint128;
using qinternaluint128 = quint128;
#elif defined(Q_CC_MSVC) && (_MSC_VER >= 1930)
#include <__msvc_int128.hpp>
using qinternalint128 = std::_Signed128;
using qinternaluint128 = std::_Unsigned128;
#endif
enum StrayCharacterMode {
TrailingJunkProhibited,
TrailingJunkAllowed,
@ -43,6 +52,13 @@ void qt_doubleToAscii(double d, QLocaleData::DoubleForm form, int precision,
[[nodiscard]] QByteArray qdtoAscii(double d, QLocaleData::DoubleForm form,
int precision, bool uppercase);
#if defined(QT_SUPPORTS_INT128) || (defined(Q_CC_MSVC) && (_MSC_VER >= 1930))
[[nodiscard]] Q_CORE_EXPORT QString quint128toBasicLatin(qinternaluint128 number,
int base = 10);
[[nodiscard]] Q_CORE_EXPORT QString qint128toBasicLatin(qinternalint128 number,
int base = 10);
#endif
[[nodiscard]] constexpr inline bool isZero(double d)
{
return d == 0; // Amusingly, compilers do not grumble.