diff options
Diffstat (limited to 'src/corelib/tools')
27 files changed, 1007 insertions, 3126 deletions
diff --git a/src/corelib/tools/qalgorithms.h b/src/corelib/tools/qalgorithms.h index ffa3082d5e..27630aea87 100644 --- a/src/corelib/tools/qalgorithms.h +++ b/src/corelib/tools/qalgorithms.h @@ -620,7 +620,11 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint8 v) Q_DECL_NOT Q_DECL_RELAXED_CONSTEXPR inline uint qCountTrailingZeroBits(quint16 v) Q_DECL_NOTHROW { #if defined(Q_CC_GNU) +# if QT_HAS_BUILTIN(__builtin_ctzs) || defined(__BMI__) + return v ? __builtin_ctzs(v) : 16U; +# else return v ? __builtin_ctz(v) : 16U; +# endif #else unsigned int c = 16; // c will be the number of zero bits on the right v &= -signed(v); @@ -679,7 +683,11 @@ Q_DECL_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint8 v) Q_DECL_NOTH Q_DECL_RELAXED_CONSTEXPR inline uint qCountLeadingZeroBits(quint16 v) Q_DECL_NOTHROW { #if defined(Q_CC_GNU) +# if QT_HAS_BUILTIN(__builtin_clzs) || defined(__BMI__) + return v ? __builtin_clzs(v) : 16U; +# else return v ? __builtin_clz(v)-16U : 16U; +# endif #else v = v | (v >> 1); v = v | (v >> 2); diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 00d15fd518..b972be68a3 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -39,6 +39,7 @@ #include "qlist.h" #include "qlocale.h" #include "qlocale_p.h" +#include "qlocale_tools_p.h" #include "qstringalgorithms_p.h" #include "qscopedpointer.h" #include "qbytearray_p.h" @@ -1713,6 +1714,14 @@ QByteArray &QByteArray::prepend(const char *str, int len) return *this; } +/*! \fn QByteArray &QByteArray::prepend(int count, char ch) + + \overload + \since 5.7 + + Prepends \a count copies of character \a ch to this byte array. +*/ + /*! \overload @@ -1825,6 +1834,17 @@ QByteArray &QByteArray::append(const char *str, int len) return *this; } +/*! \fn QByteArray &QByteArray::append(int count, char ch) + + \overload + \since 5.7 + + Appends \a count copies of character \a ch to this byte + array and returns a reference to this byte array. + + If \a count is negative or zero nothing is appended to the byte array. +*/ + /*! \overload @@ -1941,6 +1961,33 @@ QByteArray &QByteArray::insert(int i, char ch) return qbytearray_insert(this, i, &ch, 1); } +/*! \fn QByteArray &QByteArray::insert(int i, int count, char ch) + + \overload + \since 5.7 + + Inserts \a count copies of character \a ch at index position \a i in the + byte array. + + If \a i is greater than size(), the array is first extended using resize(). +*/ + +QByteArray &QByteArray::insert(int i, int count, char ch) +{ + if (i < 0 || count <= 0) + return *this; + + int oldsize = size(); + resize(qMax(i, oldsize) + count); + char *dst = d->data(); + if (i > oldsize) + ::memset(dst + oldsize, 0x20, i - oldsize); + else if (i < oldsize) + ::memmove(dst + i + count, dst + i, oldsize - i); + ::memset(dst + i, ch, count); + return *this; +} + /*! Removes \a len bytes from the array, starting at index position \a pos, and returns a reference to the array. @@ -3648,7 +3695,13 @@ ushort QByteArray::toUShort(bool *ok, int base) const double QByteArray::toDouble(bool *ok) const { - return QLocaleData::bytearrayToDouble(nulTerminated().constData(), ok); + QByteArray nulled = nulTerminated(); + bool nonNullOk = false; + int processed = 0; + double d = asciiToDouble(nulled.constData(), nulled.length(), nonNullOk, processed); + if (ok) + *ok = nonNullOk; + return d; } /*! @@ -3877,10 +3930,10 @@ QByteArray &QByteArray::setNum(qulonglong n, int base) QByteArray &QByteArray::setNum(double n, char f, int prec) { QLocaleData::DoubleForm form = QLocaleData::DFDecimal; - uint flags = 0; + uint flags = QLocaleData::ZeroPadExponent; if (qIsUpper(f)) - flags = QLocaleData::CapitalEorX; + flags |= QLocaleData::CapitalEorX; f = qToLower(f); switch (f) { diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index f0032227e8..6c79a603d3 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -255,21 +255,21 @@ public: # define Q_REQUIRED_RESULT # define Q_REQUIRED_RESULT_pushed # endif - QByteArray toLower() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray toLower() const & Q_REQUIRED_RESULT { return toLower_helper(*this); } - QByteArray toLower() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray toLower() && Q_REQUIRED_RESULT { return toLower_helper(*this); } - QByteArray toUpper() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray toUpper() const & Q_REQUIRED_RESULT { return toUpper_helper(*this); } - QByteArray toUpper() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray toUpper() && Q_REQUIRED_RESULT { return toUpper_helper(*this); } - QByteArray trimmed() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray trimmed() const & Q_REQUIRED_RESULT { return trimmed_helper(*this); } - QByteArray trimmed() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray trimmed() && Q_REQUIRED_RESULT { return trimmed_helper(*this); } - QByteArray simplified() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray simplified() const & Q_REQUIRED_RESULT { return simplified_helper(*this); } - QByteArray simplified() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QByteArray simplified() && Q_REQUIRED_RESULT { return simplified_helper(*this); } # ifdef Q_REQUIRED_RESULT_pushed # pragma pop_macro("Q_REQUIRED_RESULT") @@ -285,14 +285,17 @@ public: QByteArray rightJustified(int width, char fill = ' ', bool truncate = false) const Q_REQUIRED_RESULT; QByteArray &prepend(char c); + QByteArray &prepend(int count, char c); QByteArray &prepend(const char *s); QByteArray &prepend(const char *s, int len); QByteArray &prepend(const QByteArray &a); QByteArray &append(char c); + QByteArray &append(int count, char c); QByteArray &append(const char *s); QByteArray &append(const char *s, int len); QByteArray &append(const QByteArray &a); QByteArray &insert(int i, char c); + QByteArray &insert(int i, int count, char c); QByteArray &insert(int i, const char *s); QByteArray &insert(int i, const char *s, int len); QByteArray &insert(int i, const QByteArray &a); @@ -568,6 +571,10 @@ inline QByteArray::const_iterator QByteArray::cend() const { return d->data() + d->size; } inline QByteArray::const_iterator QByteArray::constEnd() const { return d->data() + d->size; } +inline QByteArray &QByteArray::append(int n, char ch) +{ return insert(d->size, n, ch); } +inline QByteArray &QByteArray::prepend(int n, char ch) +{ return insert(0, n, ch); } inline QByteArray &QByteArray::operator+=(char c) { return append(c); } inline QByteArray &QByteArray::operator+=(const char *s) diff --git a/src/corelib/tools/qdoublescanprint_p.h b/src/corelib/tools/qdoublescanprint_p.h new file mode 100644 index 0000000000..30ac584d06 --- /dev/null +++ b/src/corelib/tools/qdoublescanprint_p.h @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QDOUBLESCANPRINT_P_H +#define QDOUBLESCANPRINT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of internal files. This header file may change from version to version +// without notice, or even be removed. +// +// We mean it. +// + +#include <qglobal.h> + +#if defined(Q_CC_MSVC) && (defined(QT_BOOTSTRAPPED) || defined(QT_NO_DOUBLECONVERSION)) +# include <stdio.h> +# include <locale.h> + +QT_BEGIN_NAMESPACE + +// We can always use _sscanf_l and _snprintf_l on MSVC as those were introduced in 2005. + +// MSVC doesn't document what it will do with a NULL locale passed to _sscanf_l or _snprintf_l. +// The documentation for _create_locale() does not formally document "C" to be valid, but an example +// code snippet in the same documentation shows it. + +struct QCLocaleT { + QCLocaleT() : locale(_create_locale(LC_ALL, "C")) + { + } + + ~QCLocaleT() + { + _free_locale(locale); + } + + const _locale_t locale; +}; + +# define QT_CLOCALE_HOLDER Q_GLOBAL_STATIC(QCLocaleT, cLocaleT) +# define QT_CLOCALE cLocaleT()->locale + +inline int qDoubleSscanf(const char *buf, _locale_t locale, const char *format, double *d, + int *processed) +{ + return _sscanf_l(buf, format, locale, d, processed); +} + +inline int qDoubleSnprintf(char *buf, size_t buflen, _locale_t locale, const char *format, double d) +{ + return _snprintf_l(buf, buflen, format, locale, d); +} + +QT_END_NAMESPACE + +#elif defined(QT_BOOTSTRAPPED) +# include <stdio.h> + +QT_BEGIN_NAMESPACE + +// When bootstrapping we don't have libdouble-conversion available, yet. We can also not use locale +// aware snprintf and sscanf variants in the general case because those are only available on select +// platforms. We can use the regular snprintf and sscanf because we don't do setlocale(3) when +// bootstrapping and the locale is always "C" then. + +# define QT_CLOCALE_HOLDER +# define QT_CLOCALE 0 + +inline int qDoubleSscanf(const char *buf, int, const char *format, double *d, int *processed) +{ + return sscanf(buf, format, d, processed); +} +inline int qDoubleSnprintf(char *buf, size_t buflen, int, const char *format, double d) +{ + return snprintf(buf, buflen, format, d); +} + +QT_END_NAMESPACE + +#else // !QT_BOOTSTRAPPED && (!Q_CC_MSVC || !QT_NO_DOUBLECONVERSION) +# ifdef QT_NO_DOUBLECONVERSION +# include <stdio.h> +# include <xlocale.h> + +QT_BEGIN_NAMESPACE + +// OS X and FreeBSD both treat NULL as the "C" locale for snprintf_l and sscanf_l. +// When other implementations with different behavior show up, we'll have to do newlocale(3) and +// freelocale(3) here. The arguments to those will depend on what the other implementations will +// offer. OS X and FreeBSD again interpret a locale name of NULL as "C", but "C" itself is not +// documented as valid locale name. Mind that the names of the LC_* constants differ between e.g. +// BSD variants and linux. + +# define QT_CLOCALE_HOLDER +# define QT_CLOCALE NULL + +inline int qDoubleSscanf(const char *buf, locale_t locale, const char *format, double *d, + int *processed) +{ + return sscanf_l(buf, locale, format, d, processed); +} +inline int qDoubleSnprintf(char *buf, size_t buflen, locale_t locale, const char *format, double d) +{ + return snprintf_l(buf, buflen, locale, format, d); +} + +QT_END_NAMESPACE + +# else // !QT_NO_DOUBLECONVERSION +# include <double-conversion/double-conversion.h> +# define QT_CLOCALE_HOLDER +# endif // QT_NO_DOUBLECONVERSION +#endif // QT_BOOTSTRAPPED + +#endif // QDOUBLESCANPRINT_P_H diff --git a/src/corelib/tools/qeasingcurve.h b/src/corelib/tools/qeasingcurve.h index d04d5ef30a..da423f2ee7 100644 --- a/src/corelib/tools/qeasingcurve.h +++ b/src/corelib/tools/qeasingcurve.h @@ -75,12 +75,12 @@ public: QEasingCurve &operator=(const QEasingCurve &other) { if ( this != &other ) { QEasingCurve copy(other); swap(copy); } return *this; } #ifdef Q_COMPILER_RVALUE_REFS - QEasingCurve(QEasingCurve &&other) : d_ptr(other.d_ptr) { other.d_ptr = Q_NULLPTR; } - QEasingCurve &operator=(QEasingCurve &&other) + QEasingCurve(QEasingCurve &&other) Q_DECL_NOTHROW : d_ptr(other.d_ptr) { other.d_ptr = Q_NULLPTR; } + QEasingCurve &operator=(QEasingCurve &&other) Q_DECL_NOTHROW { qSwap(d_ptr, other.d_ptr); return *this; } #endif - inline void swap(QEasingCurve &other) { qSwap(d_ptr, other.d_ptr); } + void swap(QEasingCurve &other) Q_DECL_NOTHROW { qSwap(d_ptr, other.d_ptr); } bool operator==(const QEasingCurve &other) const; inline bool operator!=(const QEasingCurve &other) const diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp index b334a697a9..7724516a5d 100644 --- a/src/corelib/tools/qhash.cpp +++ b/src/corelib/tools/qhash.cpp @@ -682,17 +682,17 @@ void QHashData::dump() void QHashData::checkSanity() { - if (fakeNext) + if (Q_UNLIKELY(fakeNext)) qFatal("Fake next isn't 0"); for (int i = 0; i < numBuckets; ++i) { Node *n = buckets[i]; Node *p = n; - if (!n) + if (Q_UNLIKELY(!n)) qFatal("%d: Bucket entry is 0", i); if (n != reinterpret_cast<Node *>(this)) { while (n != reinterpret_cast<Node *>(this)) { - if (!n->next) + if (Q_UNLIKELY(!n->next)) qFatal("%d: Next of %p is 0, should be %p", i, n, this); n = n->next; } diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index b1f53dc7a2..1f4d0c88c5 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -521,7 +521,7 @@ int qt_repeatCount(const QString &s, int i) } static const QLocaleData *default_data = 0; -static uint default_number_options = 0; +static QLocale::NumberOptions default_number_options = QLocale::DefaultNumberOptions; static const QLocaleData *const c_data = locale_data; static QLocalePrivate *c_private() @@ -699,7 +699,8 @@ static QLocalePrivate *localePrivateByName(const QString &name) if (name == QLatin1String("C")) return c_private(); const QLocaleData *data = findLocaleData(name); - return QLocalePrivate::create(data, data->m_language_id == QLocale::C ? QLocale::OmitGroupSeparator : 0); + return QLocalePrivate::create(data, data->m_language_id == QLocale::C ? + QLocale::OmitGroupSeparator : QLocale::DefaultNumberOptions); } static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Script script, @@ -710,7 +711,7 @@ static QLocalePrivate *findLocalePrivate(QLocale::Language language, QLocale::Sc const QLocaleData *data = QLocaleData::findLocaleData(language, script, country); - int numberOptions = 0; + QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions; // If not found, should default to system if (data->m_language_id == QLocale::C && language != QLocale::C) { @@ -903,7 +904,7 @@ void QLocale::setNumberOptions(NumberOptions options) */ QLocale::NumberOptions QLocale::numberOptions() const { - return static_cast<NumberOption>(d->m_numberOptions); + return static_cast<NumberOptions>(d->m_numberOptions); } /*! @@ -1071,13 +1072,13 @@ QString QLocale::name() const } static qlonglong toIntegral_helper(const QLocaleData *d, const QChar *data, int len, bool *ok, - QLocaleData::GroupSeparatorMode mode, qlonglong) + QLocale::NumberOptions mode, qlonglong) { return d->stringToLongLong(data, len, 10, ok, mode); } static qulonglong toIntegral_helper(const QLocaleData *d, const QChar *data, int len, bool *ok, - QLocaleData::GroupSeparatorMode mode, qulonglong) + QLocale::NumberOptions mode, qulonglong) { return d->stringToUnsLongLong(data, len, 10, ok, mode); } @@ -1089,13 +1090,8 @@ T toIntegral_helper(const QLocalePrivate *d, const QChar *data, int len, bool *o const bool isUnsigned = T(0) < T(-1); typedef typename QtPrivate::QConditional<isUnsigned, qulonglong, qlonglong>::Type Int64; - QLocaleData::GroupSeparatorMode mode - = d->m_numberOptions & QLocale::RejectGroupSeparator - ? QLocaleData::FailOnGroupSeparators - : QLocaleData::ParseGroupSeparators; - // we select the right overload by the last, unused parameter - Int64 val = toIntegral_helper(d->m_data, data, len, ok, mode, Int64()); + Int64 val = toIntegral_helper(d->m_data, data, len, ok, d->m_numberOptions, Int64()); if (T(val) != val) { if (ok) *ok = false; @@ -1314,12 +1310,7 @@ float QLocale::toFloat(const QString &s, bool *ok) const double QLocale::toDouble(const QString &s, bool *ok) const { - QLocaleData::GroupSeparatorMode mode - = d->m_numberOptions & RejectGroupSeparator - ? QLocaleData::FailOnGroupSeparators - : QLocaleData::ParseGroupSeparators; - - return d->m_data->stringToDouble(s.constData(), s.size(), ok, mode); + return d->m_data->stringToDouble(s.constData(), s.size(), ok, d->m_numberOptions); } /*! @@ -1488,12 +1479,7 @@ float QLocale::toFloat(const QStringRef &s, bool *ok) const double QLocale::toDouble(const QStringRef &s, bool *ok) const { - QLocaleData::GroupSeparatorMode mode - = d->m_numberOptions & RejectGroupSeparator - ? QLocaleData::FailOnGroupSeparators - : QLocaleData::ParseGroupSeparators; - - return d->m_data->stringToDouble(s.constData(), s.size(), ok, mode); + return d->m_data->stringToDouble(s.constData(), s.size(), ok, d->m_numberOptions); } @@ -2019,6 +2005,8 @@ QString QLocale::toString(double i, char f, int prec) const if (!(d->m_numberOptions & OmitGroupSeparator)) flags |= QLocaleData::ThousandsGroup; + if (!(d->m_numberOptions & OmitLeadingZeroInExponent)) + flags |= QLocaleData::ZeroPadExponent; return d->m_data->doubleToString(i, prec, form, -1, flags); } @@ -2743,57 +2731,33 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q const QChar exponential, const QChar group, const QChar decimal, double d, int precision, DoubleForm form, int width, unsigned flags) { - if (precision < 0) + if (precision != QLocale::FloatingPointShortest && precision < 0) precision = 6; if (width < 0) width = 0; bool negative = false; - bool special_number = false; // nan, +/-inf QString num_str; - // Detect special numbers (nan, +/-inf) - if (qt_is_inf(d)) { - num_str = QString::fromLatin1("inf"); - special_number = true; - negative = d < 0; - } else if (qt_is_nan(d)) { - num_str = QString::fromLatin1("nan"); - special_number = true; - } - - // Handle normal numbers - if (!special_number) { - int decpt, sign; - QString digits; - - int mode; - if (form == DFDecimal) - mode = 3; - else - mode = 2; - - /* This next bit is a bit quirky. In DFExponent form, the precision - is the number of digits after decpt. So that would suggest using - mode=3 for qdtoa. But qdtoa behaves strangely when mode=3 and - precision=0. So we get around this by using mode=2 and reasoning - that we want precision+1 significant digits, since the decimal - point in this mode is always after the first digit. */ - int pr = precision; - if (form == DFExponent) - ++pr; - - char *rve = 0; - char *buff = 0; - QT_TRY { - digits = QLatin1String(qdtoa(d, mode, pr, &decpt, &sign, &rve, &buff)); - } QT_CATCH(...) { - if (buff != 0) - free(buff); - QT_RETHROW; - } - if (buff != 0) - free(buff); + int decpt; + int bufSize = 1; + if (precision == QLocale::FloatingPointShortest) + bufSize += DoubleMaxSignificant; + else if (form == DFDecimal) // optimize for numbers between -512k and 512k + bufSize += ((d > (1 << 19) || d < -(1 << 19)) ? DoubleMaxDigitsBeforeDecimal : 6) + + precision; + else // Add extra digit due to different interpretations of precision. Also, "nan" has to fit. + bufSize += qMax(2, precision) + 1; + + QVarLengthArray<char> buf(bufSize); + int length; + + doubleToAscii(d, form, precision, buf.data(), bufSize, negative, length, decpt); + + if (qstrncmp(buf.data(), "inf", 3) == 0 || qstrncmp(buf.data(), "nan", 3) == 0) { + num_str = QString::fromLatin1(buf.data(), length); + } else { // Handle normal numbers + QString digits = QString::fromLatin1(buf.data(), length); if (_zero.unicode() != '0') { ushort z = _zero.unicode() - '0'; @@ -2806,7 +2770,7 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q case DFExponent: { num_str = exponentForm(_zero, decimal, exponential, group, plus, minus, digits, decpt, precision, PMDecimalDigits, - always_show_decpt); + always_show_decpt, flags & ZeroPadExponent); break; } case DFDecimal: { @@ -2819,10 +2783,23 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q PrecisionMode mode = (flags & Alternate) ? PMSignificantDigits : PMChopTrailingZeros; - if (decpt != digits.length() && (decpt <= -4 || decpt > precision)) + int cutoff = precision < 0 ? 6 : precision; + // Find out which representation is shorter + if (precision == QLocale::FloatingPointShortest && decpt > 0) { + cutoff = digits.length() + 4; // 'e', '+'/'-', one digit exponent + if (decpt <= 10) { + ++cutoff; + } else { + cutoff += decpt > 100 ? 2 : 1; + } + if (!always_show_decpt && digits.length() > decpt) + ++cutoff; // decpt shown in exponent form, but not in decimal form + } + + if (decpt != digits.length() && (decpt <= -4 || decpt > cutoff)) num_str = exponentForm(_zero, decimal, exponential, group, plus, minus, digits, decpt, precision, mode, - always_show_decpt); + always_show_decpt, flags & ZeroPadExponent); else num_str = decimalForm(_zero, decimal, group, digits, decpt, precision, mode, @@ -2831,23 +2808,22 @@ QString QLocaleData::doubleToString(const QChar _zero, const QChar plus, const Q } } - negative = sign != 0 && !isZero(d); - } - - // pad with zeros. LeftAdjusted overrides this flag). Also, we don't - // pad special numbers - if (flags & QLocaleData::ZeroPadded - && !(flags & QLocaleData::LeftAdjusted) - && !special_number) { - int num_pad_chars = width - num_str.length(); - // leave space for the sign - if (negative - || flags & QLocaleData::AlwaysShowSign - || flags & QLocaleData::BlankBeforePositive) - --num_pad_chars; - - for (int i = 0; i < num_pad_chars; ++i) - num_str.prepend(_zero); + if (isZero(d)) + negative = false; + + // pad with zeros. LeftAdjusted overrides this flag). Also, we don't + // pad special numbers + if (flags & QLocaleData::ZeroPadded && !(flags & QLocaleData::LeftAdjusted)) { + int num_pad_chars = width - num_str.length(); + // leave space for the sign + if (negative + || flags & QLocaleData::AlwaysShowSign + || flags & QLocaleData::BlankBeforePositive) + --num_pad_chars; + + for (int i = 0; i < num_pad_chars; ++i) + num_str.prepend(_zero); + } } // add sign @@ -3042,9 +3018,8 @@ QString QLocaleData::unsLongLongToString(const QChar zero, const QChar group, number. We can't detect junk here, since we don't even know the base of the number. */ -bool QLocaleData::numberToCLocale(const QChar *str, int len, - GroupSeparatorMode group_sep_mode, - CharBuff *result) const +bool QLocaleData::numberToCLocale(const QChar *str, int len, QLocale::NumberOptions number_options, + CharBuff *result) const { const QChar *uc = str; int l = len; @@ -3066,6 +3041,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, int decpt_idx = -1; int last_separator_idx = -1; int start_of_digits_idx = -1; + int exponent_idx = -1; while (idx < l) { const QChar in = uc[idx]; @@ -3084,7 +3060,19 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, else break; } - if (group_sep_mode == ParseGroupSeparators) { + + if (number_options & QLocale::RejectLeadingZeroInExponent) { + if (out == 'e' || out == 'E') { + exponent_idx = idx; + } else if (exponent_idx != -1) { + if (out >= '1' && out <= '9') + exponent_idx = -1; // leading digit is not 0, forget exponent_idx + else if (out == '0' && idx < l - 1) + return false; + } + } + + if (!(number_options & QLocale::RejectGroupSeparator)) { if (start_of_digits_idx == -1 && out >= '0' && out <= '9') { start_of_digits_idx = idx; } else if (out == ',') { @@ -3127,7 +3115,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, ++idx; } - if (group_sep_mode == ParseGroupSeparators) { + if (!(number_options & QLocale::RejectGroupSeparator)) { // group separator post-processing // did we end in a separator? if (last_separator_idx + 1 == idx) @@ -3142,7 +3130,7 @@ bool QLocaleData::numberToCLocale(const QChar *str, int len, } bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArray *buff, - int decDigits, bool rejectGroupSeparators) const + int decDigits, QLocale::NumberOptions number_options) const { buff->clear(); buff->reserve(str.length()); @@ -3164,6 +3152,13 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr if (dec && decDigits != -1 && decDigits < ++decDigitCnt) return false; } + + // The only non-digit character after the 'e' can be '+' or '-'. + // If a zero is directly after that, then the exponent is zero-padded. + if ((number_options & QLocale::RejectLeadingZeroInExponent) && c == '0' && eCnt > 0 && + !lastWasDigit) + return false; + lastWasDigit = true; } else { switch (c) { @@ -3203,7 +3198,8 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr case ',': //it can only be placed after a digit which is before the decimal point - if (rejectGroupSeparators || !lastWasDigit || decPointCnt > 0) + if ((number_options & QLocale::RejectGroupSeparator) || !lastWasDigit || + decPointCnt > 0) return false; break; @@ -3235,22 +3231,27 @@ bool QLocaleData::validateChars(const QString &str, NumberMode numMode, QByteArr } double QLocaleData::stringToDouble(const QChar *begin, int len, bool *ok, - GroupSeparatorMode group_sep_mode) const + QLocale::NumberOptions number_options) const { CharBuff buff; - if (!numberToCLocale(begin, len, group_sep_mode, &buff)) { + if (!numberToCLocale(begin, len, number_options, &buff)) { if (ok != 0) *ok = false; return 0.0; } - return bytearrayToDouble(buff.constData(), ok); + int processed = 0; + bool nonNullOk = false; + double d = asciiToDouble(buff.constData(), buff.length() - 1, nonNullOk, processed); + if (ok) + *ok = nonNullOk; + return d; } -qlonglong QLocaleData::stringToLongLong(const QChar *begin, int len, int base, - bool *ok, GroupSeparatorMode group_sep_mode) const +qlonglong QLocaleData::stringToLongLong(const QChar *begin, int len, int base, bool *ok, + QLocale::NumberOptions number_options) const { CharBuff buff; - if (!numberToCLocale(begin, len, group_sep_mode, &buff)) { + if (!numberToCLocale(begin, len, number_options, &buff)) { if (ok != 0) *ok = false; return 0; @@ -3259,11 +3260,11 @@ qlonglong QLocaleData::stringToLongLong(const QChar *begin, int len, int base, return bytearrayToLongLong(buff.constData(), base, ok); } -qulonglong QLocaleData::stringToUnsLongLong(const QChar *begin, int len, int base, - bool *ok, GroupSeparatorMode group_sep_mode) const +qulonglong QLocaleData::stringToUnsLongLong(const QChar *begin, int len, int base, bool *ok, + QLocale::NumberOptions number_options) const { CharBuff buff; - if (!numberToCLocale(begin, len, group_sep_mode, &buff)) { + if (!numberToCLocale(begin, len, number_options, &buff)) { if (ok != 0) *ok = false; return 0; @@ -3274,53 +3275,15 @@ qulonglong QLocaleData::stringToUnsLongLong(const QChar *begin, int len, int bas double QLocaleData::bytearrayToDouble(const char *num, bool *ok, bool *overflow) { - if (ok != 0) - *ok = true; - if (overflow != 0) - *overflow = false; - - if (*num == '\0') { - if (ok != 0) - *ok = false; - return 0.0; - } - - if (qstrcmp(num, "nan") == 0) - return qt_snan(); - - if (qstrcmp(num, "+inf") == 0 || qstrcmp(num, "inf") == 0) - return qt_inf(); - - if (qstrcmp(num, "-inf") == 0) - return -qt_inf(); - - bool _ok; - const char *endptr; - double d = qstrtod(num, &endptr, &_ok); - - if (!_ok) { - // the only way strtod can fail with *endptr != '\0' on a non-empty - // input string is overflow - if (ok != 0) - *ok = false; - if (overflow != 0) - *overflow = *endptr != '\0'; - return 0.0; - } - - if (*endptr != '\0') { - // we stopped at a non-digit character after converting some digits - if (ok != 0) - *ok = false; - if (overflow != 0) - *overflow = false; - return 0.0; - } - - if (ok != 0) - *ok = true; - if (overflow != 0) - *overflow = false; + bool nonNullOk = false; + int len = static_cast<int>(strlen(num)); + Q_ASSERT(len >= 0); + int processed = 0; + double d = asciiToDouble(num, len, nonNullOk, processed); + if (ok) + *ok = nonNullOk; + if (overflow) + *overflow = processed < len; return d; } diff --git a/src/corelib/tools/qlocale.h b/src/corelib/tools/qlocale.h index 729fd73a5d..e90354138c 100644 --- a/src/corelib/tools/qlocale.h +++ b/src/corelib/tools/qlocale.h @@ -843,11 +843,18 @@ public: enum FormatType { LongFormat, ShortFormat, NarrowFormat }; enum NumberOption { + DefaultNumberOptions = 0x0, OmitGroupSeparator = 0x01, - RejectGroupSeparator = 0x02 + RejectGroupSeparator = 0x02, + OmitLeadingZeroInExponent = 0x04, + RejectLeadingZeroInExponent = 0x08 }; Q_DECLARE_FLAGS(NumberOptions, NumberOption) + enum FloatingPointPrecisionOption { + FloatingPointShortest = -128 + }; + enum CurrencySymbolFormat { CurrencyIsoCode, CurrencySymbol, diff --git a/src/corelib/tools/qlocale.qdoc b/src/corelib/tools/qlocale.qdoc index c87e67cf17..76195ab666 100644 --- a/src/corelib/tools/qlocale.qdoc +++ b/src/corelib/tools/qlocale.qdoc @@ -930,17 +930,44 @@ conversions. They can be retrieved with numberOptions() and set with setNumberOptions(). + \value DefaultNumberOptions This option represents the default behavior, with + group separators and with one leading zero in single digit exponents. \value OmitGroupSeparator If this option is set, the number-to-string functions will not insert group separators in their return values. The default is to insert group separators. \value RejectGroupSeparator If this option is set, the string-to-number functions will fail if they encounter group separators in their input. The default is to accept numbers containing correctly placed group separators. + \value OmitLeadingZeroInExponent If this option is set, the number-to-string + functions will not pad exponents with zeroes when printing floating point + numbers in scientific notation. The default is to add one leading zero to + single digit exponents. + \value RejectLeadingZeroInExponent If this option is set, the string-to-number + functions will fail if they encounter an exponent padded with zeroes when + parsing a floating point number in scientific notation. The default is to + accept such padding. \sa setNumberOptions(), numberOptions() */ /*! + \enum QLocale::FloatingPointPrecisionOption + + This enum defines constants that can be given as precision to QString::number(), + QByteArray::number(), and QLocale::toString() when converting floats or doubles, + in order to express a variable number of digits as precision. + + \value FloatingPointShortest The conversion algorithm will try to find the + shortest accurate representation for the given number. "Accurate" means + that you get the exact same number back from an inverse conversion on + the generated string representation. + + \sa toString(), QString, QByteArray + + \since 5.7 +*/ + +/*! \enum QLocale::MeasurementSystem This enum defines which units are used for measurement. diff --git a/src/corelib/tools/qlocale_blackberry.cpp b/src/corelib/tools/qlocale_blackberry.cpp deleted file mode 100644 index c8543ca9b8..0000000000 --- a/src/corelib/tools/qlocale_blackberry.cpp +++ /dev/null @@ -1,333 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qlocale_blackberry.h" -#include "qlocale_p.h" - -#include "qdatetime.h" - -#include "qcoreapplication.h" -#include "private/qcore_unix_p.h" - -#include <errno.h> -#include <sys/pps.h> -#include <unistd.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_SYSTEMLOCALE - -static const char ppsUomPath[] = "/pps/services/locale/uom"; -static const char ppsRegionLocalePath[] = "/pps/services/locale/settings"; -static const char ppsLanguageLocalePath[] = "/pps/services/confstr/_CS_LOCALE"; -static const char ppsHourFormatPath[] = "/pps/system/settings"; - -static const int MAX_PPS_SIZE = 16000; - -QBBSystemLocaleData::QBBSystemLocaleData() - : languageNotifier(0) - , regionNotifier(0) - , measurementNotifier(0) - , hourNotifier(0) -{ - // Do not use qWarning to log warnings if qt_safe_open fails to open the pps file - // since the user code may install a message handler that invokes QLocale API again - // (i.e QDate, QDateTime, ...) which will cause a deadlock. - if ((measurementFd = qt_safe_open(ppsUomPath, O_RDONLY)) == -1) - fprintf(stderr, "Failed to open uom pps, errno=%d\n", errno); - - if ((regionFd = qt_safe_open(ppsRegionLocalePath, O_RDONLY)) == -1) - fprintf(stderr, "Failed to open region pps, errno=%d\n", errno); - - if ((languageFd = qt_safe_open(ppsLanguageLocalePath, O_RDONLY)) == -1) - fprintf(stderr, "Failed to open language pps, errno=%d\n", errno); - - if ((hourFd = qt_safe_open(ppsHourFormatPath, O_RDONLY)) == -1) - fprintf(stderr, "Failed to open hour format pps, errno=%d\n", errno); - - // we cannot call this directly, because by the time this constructor is - // called, the event dispatcher has not yet been created, causing the - // subsequent call to QSocketNotifier constructor to fail. - QMetaObject::invokeMethod(this, "installSocketNotifiers", Qt::QueuedConnection); - - readLanguageLocale(); - readRegionLocale(); - readMeasurementSystem(); - readHourFormat(); -} - -QBBSystemLocaleData::~QBBSystemLocaleData() -{ - if (measurementFd != -1) - qt_safe_close(measurementFd); - - if (languageFd != -1) - qt_safe_close(languageFd); - - if (regionFd != -1) - qt_safe_close(regionFd); - - if (hourFd != -1) - qt_safe_close(hourFd); -} - -uint QBBSystemLocaleData::measurementSystem() -{ - return m_measurementSystem; -} - -QVariant QBBSystemLocaleData::timeFormat(QLocale::FormatType formatType) -{ - return getCorrectFormat(regionLocale().timeFormat(formatType), formatType); -} - -QVariant QBBSystemLocaleData::dateTimeFormat(QLocale::FormatType formatType) -{ - return getCorrectFormat(regionLocale().dateTimeFormat(formatType), formatType); -} - -QLocale QBBSystemLocaleData::languageLocale() -{ - if (!lc_language.isEmpty()) - return QLocale(QLatin1String(lc_language)); - - return QLocale::c(); -} - -QLocale QBBSystemLocaleData::regionLocale() -{ - if (!lc_region.isEmpty()) - return QLocale(QLatin1String(lc_region)); - - return QLocale::c(); -} - -void QBBSystemLocaleData::installSocketNotifiers() -{ - Q_ASSERT(!languageNotifier || !regionNotifier || !measurementNotifier || !hourNotifier); - Q_ASSERT(QCoreApplication::instance()); - - languageNotifier = new QSocketNotifier(languageFd, QSocketNotifier::Read, this); - QObject::connect(languageNotifier, SIGNAL(activated(int)), this, SLOT(readLanguageLocale())); - - regionNotifier = new QSocketNotifier(regionFd, QSocketNotifier::Read, this); - QObject::connect(regionNotifier, SIGNAL(activated(int)), this, SLOT(readRegionLocale())); - - measurementNotifier = new QSocketNotifier(measurementFd, QSocketNotifier::Read, this); - QObject::connect(measurementNotifier, SIGNAL(activated(int)), this, SLOT(readMeasurementSystem())); - - hourNotifier = new QSocketNotifier(hourFd, QSocketNotifier::Read, this); - QObject::connect(hourNotifier, SIGNAL(activated(int)), this, SLOT(readHourFormat())); -} - -void QBBSystemLocaleData::readLanguageLocale() -{ - lc_language = readPpsValue("_CS_LOCALE", languageFd); -} - -void QBBSystemLocaleData::readRegionLocale() -{ - lc_region = readPpsValue("region", regionFd); -} - -void QBBSystemLocaleData::readMeasurementSystem() -{ - QByteArray measurement = readPpsValue("uom", measurementFd); - m_measurementSystem = (qstrcmp(measurement, "imperial") == 0) ? QLocale::ImperialSystem : QLocale::MetricSystem; -} - -void QBBSystemLocaleData::readHourFormat() -{ - QByteArray hourFormat = readPpsValue("hourFormat", hourFd); - is24HourFormat = (qstrcmp(hourFormat, "24") == 0); -} - -QByteArray QBBSystemLocaleData::readPpsValue(const char *ppsObject, int ppsFd) -{ - QByteArray result; - if (!ppsObject || ppsFd == -1) - return result; - - // PPS objects are of unknown size, but must be read all at once. - // Relying on the file size may not be a good idea since the size may change before reading. - // Let's try with an initial size (512), and if the buffer is too small try with bigger one, - // until we succeed or until other non buffer-size-related error occurs. - // Using QVarLengthArray means the first try (of size == 512) uses a buffer on the stack - no allocation necessary. - // Hopefully that covers most use cases. - int bytes; - QVarLengthArray<char, 512> buffer(512); - for (;;) { - errno = 0; - bytes = qt_safe_read(ppsFd, buffer.data(), buffer.size() - 1); - const bool bufferIsTooSmall = (bytes == -1 && errno == EMSGSIZE && buffer.size() < MAX_PPS_SIZE); - if (!bufferIsTooSmall) - break; - - buffer.resize(qMin(buffer.size()*2, MAX_PPS_SIZE)); - } - - // This method is called in the ctor(), so do not use qWarning to log warnings - // if qt_safe_read fails to read the pps file - // since the user code may install a message handler that invokes QLocale API again - // (i.e QDate, QDateTime, ...) which will cause a deadlock. - if (bytes == -1) { - fprintf(stderr, "Failed to read pps object:%s, errno=%d\n", ppsObject, errno); - return result; - } - // ensure data is null terminated - buffer[bytes] = '\0'; - - pps_decoder_t ppsDecoder; - pps_decoder_initialize(&ppsDecoder, 0); - if (pps_decoder_parse_pps_str(&ppsDecoder, buffer.data()) == PPS_DECODER_OK) { - pps_decoder_push(&ppsDecoder, 0); - const char *ppsBuff; - if (pps_decoder_get_string(&ppsDecoder, ppsObject, &ppsBuff) == PPS_DECODER_OK) { - result = ppsBuff; - } else { - int val; - if (pps_decoder_get_int(&ppsDecoder, ppsObject, &val) == PPS_DECODER_OK) - result = QByteArray::number(val); - } - } - - pps_decoder_cleanup(&ppsDecoder); - - return result; -} - -QString QBBSystemLocaleData::getCorrectFormat(const QString &baseFormat, QLocale::FormatType formatType) -{ - QString format = baseFormat; - if (is24HourFormat) { - if (format.contains(QStringLiteral("AP"), Qt::CaseInsensitive)) { - format.replace(QStringLiteral("AP"), QStringLiteral(""), Qt::CaseInsensitive); - format.replace(QStringLiteral("h"), QStringLiteral("H"), Qt::CaseSensitive); - } - - } else { - - if (!format.contains(QStringLiteral("AP"), Qt::CaseInsensitive)) { - format.contains(QStringLiteral("HH"), Qt::CaseSensitive) ? - format.replace(QStringLiteral("HH"), QStringLiteral("hh"), Qt::CaseSensitive) : - format.replace(QStringLiteral("H"), QStringLiteral("h"), Qt::CaseSensitive); - - formatType == QLocale::LongFormat ? format.append(QStringLiteral(" AP t")) : format.append(QStringLiteral(" AP")); - } - } - - return format; -} - -Q_GLOBAL_STATIC(QBBSystemLocaleData, bbSysLocaleData) - -QLocale QSystemLocale::fallbackUiLocale() const -{ - return bbSysLocaleData()->languageLocale(); -} - -QVariant QSystemLocale::query(QueryType type, QVariant in) const -{ - QBBSystemLocaleData *d = bbSysLocaleData(); - - QReadLocker locker(&d->lock); - - const QLocale &lc_language = d->languageLocale(); - const QLocale &lc_region = d->regionLocale(); - - switch (type) { - case DecimalPoint: - return lc_region.decimalPoint(); - case GroupSeparator: - return lc_region.groupSeparator(); - case NegativeSign: - return lc_region.negativeSign(); - case PositiveSign: - return lc_region.positiveSign(); - case DateFormatLong: - return lc_region.dateFormat(QLocale::LongFormat); - case DateFormatShort: - return lc_region.dateFormat(QLocale::ShortFormat); - case TimeFormatLong: - return d->timeFormat(QLocale::LongFormat); - case TimeFormatShort: - return d->timeFormat(QLocale::ShortFormat); - case DateTimeFormatLong: - return d->dateTimeFormat(QLocale::LongFormat); - case DateTimeFormatShort: - return d->dateTimeFormat(QLocale::ShortFormat); - case DayNameLong: - return lc_language.dayName(in.toInt(), QLocale::LongFormat); - case DayNameShort: - return lc_language.dayName(in.toInt(), QLocale::ShortFormat); - case MonthNameLong: - return lc_language.monthName(in.toInt(), QLocale::LongFormat); - case MonthNameShort: - return lc_language.monthName(in.toInt(), QLocale::ShortFormat); - case StandaloneMonthNameLong: - return lc_language.standaloneMonthName(in.toInt(), QLocale::LongFormat); - case StandaloneMonthNameShort: - return lc_language.standaloneMonthName(in.toInt(), QLocale::ShortFormat); - case DateToStringLong: - return lc_region.toString(in.toDate(), QLocale::LongFormat); - case DateToStringShort: - return lc_region.toString(in.toDate(), QLocale::ShortFormat); - case TimeToStringLong: - return lc_region.toString(in.toTime(), d->timeFormat(QLocale::LongFormat).toString()); - case TimeToStringShort: - return lc_region.toString(in.toTime(), d->timeFormat(QLocale::ShortFormat).toString()); - case DateTimeToStringShort: - return lc_region.toString(in.toDateTime(), d->dateTimeFormat(QLocale::ShortFormat).toString()); - case DateTimeToStringLong: - return lc_region.toString(in.toDateTime(), d->dateTimeFormat(QLocale::LongFormat).toString()); - case MeasurementSystem: - return d->measurementSystem(); - case ZeroDigit: - return lc_region.zeroDigit(); - case CountryId: - return lc_region.country(); - case LanguageId: - return lc_language.language(); - case AMText: - return lc_language.amText(); - case PMText: - return lc_language.pmText(); - default: - break; - } - return QVariant(); -} - -#endif - -QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_blackberry.h b/src/corelib/tools/qlocale_blackberry.h deleted file mode 100644 index 317ae375ae..0000000000 --- a/src/corelib/tools/qlocale_blackberry.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QLOCALE_BLACKBERRY_H -#define QLOCALE_BLACKBERRY_H - -#include <QtCore/qsocketnotifier.h> -#include <QtCore/qreadwritelock.h> -#include <QtCore/qlocale.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_SYSTEMLOCALE - -class QBBSystemLocaleData : public QObject -{ - Q_OBJECT - -public: - QBBSystemLocaleData(); - virtual ~QBBSystemLocaleData(); - uint measurementSystem(); - QVariant timeFormat(QLocale::FormatType); - QVariant dateTimeFormat(QLocale::FormatType); - QLocale languageLocale(); - QLocale regionLocale(); - - QReadWriteLock lock; - -public Q_SLOTS: - void installSocketNotifiers(); - void readLanguageLocale(); - void readRegionLocale(); - void readMeasurementSystem(); - void readHourFormat(); - -private: - QByteArray readPpsValue(const char *ppsObject, int ppsFd); - QString getCorrectFormat(const QString &baseFormat, QLocale::FormatType typeFormat); - - QByteArray lc_language; - QByteArray lc_region; - uint m_measurementSystem; - bool is24HourFormat; - - QSocketNotifier *languageNotifier; - QSocketNotifier *regionNotifier; - QSocketNotifier *measurementNotifier; - QSocketNotifier *hourNotifier; - - int languageFd; - int regionFd; - int measurementFd; - int hourFd; -}; -#endif // QT_NO_SYSTEMLOCALE - -QT_END_NAMESPACE - -#endif // QLOCALE_BLACKBERRY_H - diff --git a/src/corelib/tools/qlocale_p.h b/src/corelib/tools/qlocale_p.h index b3fd7a96b8..65d4d58def 100644 --- a/src/corelib/tools/qlocale_p.h +++ b/src/corelib/tools/qlocale_p.h @@ -165,6 +165,17 @@ public: QLocale::Country country); static const QLocaleData *c(); + // Maximum number of significant digits needed to represent a double. + // We cannot use std::numeric_limits here without constexpr. + static const int DoubleMantissaBits = 53; + static const int Log10_2_100000 = 30103; // log10(2) * 100000 + // same as C++11 std::numeric_limits<T>::max_digits10 + static const int DoubleMaxSignificant = (DoubleMantissaBits * Log10_2_100000) / 100000 + 2; + + // Maximum number of digits before decimal point to represent a double + // Same as std::numeric_limits<double>::max_exponent10 + 1 + static const int DoubleMaxDigitsBeforeDecimal = 309; + enum DoubleForm { DFExponent = 0, DFDecimal, @@ -184,14 +195,10 @@ public: ShowBase = 0x80, UppercaseBase = 0x100, + ZeroPadExponent = 0x200, ForcePoint = Alternate }; - enum GroupSeparatorMode { - FailOnGroupSeparators, - ParseGroupSeparators - }; - enum NumberMode { IntegerMode, DoubleStandardMode, DoubleScientificMode }; typedef QVarLengthArray<char, 256> CharBuff; @@ -239,24 +246,26 @@ public: return float(d); } - double stringToDouble(const QChar *begin, int len, bool *ok, GroupSeparatorMode group_sep_mode) const; - qint64 stringToLongLong(const QChar *begin, int len, int base, bool *ok, GroupSeparatorMode group_sep_mode) const; - quint64 stringToUnsLongLong(const QChar *begin, int len, int base, bool *ok, GroupSeparatorMode group_sep_mode) const; + double stringToDouble(const QChar *begin, int len, bool *ok, + QLocale::NumberOptions number_options) const; + qint64 stringToLongLong(const QChar *begin, int len, int base, bool *ok, + QLocale::NumberOptions number_options) const; + quint64 stringToUnsLongLong(const QChar *begin, int len, int base, bool *ok, + QLocale::NumberOptions number_options) const; // these functions are used in QIntValidator (QtGui) Q_CORE_EXPORT static double bytearrayToDouble(const char *num, bool *ok, bool *overflow = 0); Q_CORE_EXPORT static qint64 bytearrayToLongLong(const char *num, int base, bool *ok, bool *overflow = 0); Q_CORE_EXPORT static quint64 bytearrayToUnsLongLong(const char *num, int base, bool *ok); - bool numberToCLocale(const QChar *str, int len, - GroupSeparatorMode group_sep_mode, - CharBuff *result) const; + bool numberToCLocale(const QChar *str, int len, QLocale::NumberOptions number_options, + CharBuff *result) const; inline char digitToCLocale(QChar c) const; // this function is used in QIntValidator (QtGui) - Q_CORE_EXPORT bool validateChars(const QString &str, NumberMode numMode, - QByteArray *buff, int decDigits = -1, - bool rejectGroupSeparators = false) const; + Q_CORE_EXPORT bool validateChars( + const QString &str, NumberMode numMode, QByteArray *buff, int decDigits = -1, + QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const; public: quint16 m_language_id, m_script_id, m_country_id; @@ -304,7 +313,9 @@ public: class Q_CORE_EXPORT QLocalePrivate { public: - static QLocalePrivate *create(const QLocaleData *data, int numberOptions = 0) + static QLocalePrivate *create( + const QLocaleData *data, + QLocale::NumberOptions numberOptions = QLocale::DefaultNumberOptions) { QLocalePrivate *retval = new QLocalePrivate; retval->m_data = data; @@ -351,7 +362,7 @@ public: const QLocaleData *m_data; QBasicAtomicInt ref; - quint16 m_numberOptions; + QLocale::NumberOptions m_numberOptions; }; template <> diff --git a/src/corelib/tools/qlocale_tools.cpp b/src/corelib/tools/qlocale_tools.cpp index 03b911c4b3..f766a301c5 100644 --- a/src/corelib/tools/qlocale_tools.cpp +++ b/src/corelib/tools/qlocale_tools.cpp @@ -33,9 +33,12 @@ ****************************************************************************/ #include "qlocale_tools_p.h" +#include "qdoublescanprint_p.h" #include "qlocale_p.h" #include "qstring.h" +#include <private/qnumeric_p.h> + #include <ctype.h> #include <errno.h> #include <float.h> @@ -44,10 +47,6 @@ #include <stdlib.h> #include <time.h> -#ifdef Q_OS_WINCE -# include "qfunctions_wince.h" // for _control87 -#endif - #if defined(Q_OS_LINUX) && !defined(__UCLIBC__) # include <fenv.h> #endif @@ -68,6 +67,307 @@ QT_BEGIN_NAMESPACE #include "../../3rdparty/freebsd/strtoull.c" #include "../../3rdparty/freebsd/strtoll.c" +QT_CLOCALE_HOLDER + +void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize, + bool &sign, int &length, int &decpt) +{ + if (bufSize == 0) { + decpt = 0; + sign = d < 0; + length = 0; + return; + } + + // Detect special numbers (nan, +/-inf) + // We cannot use the high-level API of libdouble-conversion as we need to apply locale-specific + // formatting, such as decimal points, thousands-separators, etc. Because of this, we have to + // check for infinity and NaN before calling DoubleToAscii. + if (qt_is_inf(d)) { + sign = d < 0; + if (bufSize >= 3) { + buf[0] = 'i'; + buf[1] = 'n'; + buf[2] = 'f'; + length = 3; + } else { + length = 0; + } + return; + } else if (qt_is_nan(d)) { + if (bufSize >= 3) { + buf[0] = 'n'; + buf[1] = 'a'; + buf[2] = 'n'; + length = 3; + } else { + length = 0; + } + return; + } + + if (form == QLocaleData::DFSignificantDigits && precision == 0) + precision = 1; // 0 significant digits is silently converted to 1 + +#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) + // one digit before the decimal dot, counts as significant digit for DoubleToStringConverter + if (form == QLocaleData::DFExponent && precision >= 0) + ++precision; + + double_conversion::DoubleToStringConverter::DtoaMode mode; + if (precision == QLocale::FloatingPointShortest) { + mode = double_conversion::DoubleToStringConverter::SHORTEST; + } else if (form == QLocaleData::DFSignificantDigits || form == QLocaleData::DFExponent) { + mode = double_conversion::DoubleToStringConverter::PRECISION; + } else { + mode = double_conversion::DoubleToStringConverter::FIXED; + } + double_conversion::DoubleToStringConverter::DoubleToAscii(d, mode, precision, buf, bufSize, + &sign, &length, &decpt); +#else // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED + + // Cut the precision at 999, to fit it into the format string. We can't get more than 17 + // significant digits, so anything after that is mostly noise. You do get closer to the "middle" + // of the range covered by the given double with more digits, so to a degree it does make sense + // to honor higher precisions. We define that at more than 999 digits that is not the case. + if (precision > 999) + precision = 999; + else if (precision == QLocale::FloatingPointShortest) + precision = QLocaleData::DoubleMaxSignificant; // "shortest" mode not supported by snprintf + + if (isZero(d)) { + // Negative zero is expected as simple "0", not "-0". We cannot do d < 0, though. + sign = false; + buf[0] = '0'; + length = 1; + decpt = 1; + return; + } else if (d < 0) { + sign = true; + d = -d; + } else { + sign = false; + } + + const int formatLength = 7; // '%', '.', 3 digits precision, 'f', '\0' + char format[formatLength]; + format[formatLength - 1] = '\0'; + format[0] = '%'; + format[1] = '.'; + format[2] = char((precision / 100) % 10) + '0'; + format[3] = char((precision / 10) % 10) + '0'; + format[4] = char(precision % 10) + '0'; + int extraChars; + switch (form) { + case QLocaleData::DFDecimal: + format[formatLength - 2] = 'f'; + // <anything> '.' <precision> '\0' - optimize for numbers smaller than 512k + extraChars = (d > (1 << 19) ? QLocaleData::DoubleMaxDigitsBeforeDecimal : 6) + 2; + break; + case QLocaleData::DFExponent: + format[formatLength - 2] = 'e'; + // '.', 'e', '-', <exponent> '\0' + extraChars = 7; + break; + case QLocaleData::DFSignificantDigits: + format[formatLength - 2] = 'g'; + + // either the same as in the 'e' case, or '.' and '\0' + // precision covers part before '.' + extraChars = 7; + break; + default: + Q_UNREACHABLE(); + } + + QVarLengthArray<char> target(precision + extraChars); + + length = qDoubleSnprintf(target.data(), target.size(), QT_CLOCALE, format, d); + int firstSignificant = 0; + int decptInTarget = length; + + // Find the first significant digit (not 0), and note any '.' we encounter. + // There is no '-' at the front of target because we made sure d > 0 above. + while (firstSignificant < length) { + if (target[firstSignificant] == '.') + decptInTarget = firstSignificant; + else if (target[firstSignificant] != '0') + break; + ++firstSignificant; + } + + // If no '.' found so far, search the rest of the target buffer for it. + if (decptInTarget == length) + decptInTarget = std::find(target.data() + firstSignificant, target.data() + length, '.') - + target.data(); + + int eSign = length; + if (form != QLocaleData::DFDecimal) { + // In 'e' or 'g' form, look for the 'e'. + eSign = std::find(target.data() + firstSignificant, target.data() + length, 'e') - + target.data(); + + if (eSign < length) { + // If 'e' is found, the final decimal point is determined by the number after 'e'. + // Mind that the final decimal point, decpt, is the offset of the decimal point from the + // start of the resulting string in buf. It may be negative or larger than bufSize, in + // 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 = qstrtoll(target.data() + eSign + 1, &endptr, 10, &ok) + 1; + Q_ASSERT(ok); + Q_ASSERT(endptr - target.data() <= length - eSign -1); + } 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 + // get the final decimal point from the position of the '.'. The '.' itself takes up one + // character. We adjust by 1 below if that gets in the way. + decpt = decptInTarget - firstSignificant; + } + } else { + // In 'f' form, there can not be an 'e', so it's enough to look for the '.' + // (and possibly adjust by 1 below) + decpt = decptInTarget - firstSignificant; + } + + // Move the actual digits from the snprintf target to the actual buffer. + if (decptInTarget > firstSignificant) { + // First move the digits before the '.', if any + int lengthBeforeDecpt = decptInTarget - firstSignificant; + memcpy(buf, target.data() + firstSignificant, qMin(lengthBeforeDecpt, bufSize)); + if (eSign > decptInTarget && lengthBeforeDecpt < bufSize) { + // Then move any remaining digits, until 'e' + memcpy(buf + lengthBeforeDecpt, target.data() + decptInTarget + 1, + qMin(eSign - decptInTarget - 1, bufSize - lengthBeforeDecpt)); + // The final length of the output is the distance between the first significant digit + // and 'e' minus 1, for the '.', except if the buffer is smaller. + length = qMin(eSign - firstSignificant - 1, bufSize); + } else { + // 'e' was before the decpt or things didn't fit. Don't subtract the '.' from the length. + length = qMin(eSign - firstSignificant, bufSize); + } + } else { + if (eSign > firstSignificant) { + // If there are any significant digits at all, they are all after the '.' now. + // Just copy them straight away. + memcpy(buf, target.data() + firstSignificant, qMin(eSign - firstSignificant, bufSize)); + + // The decimal point was before the first significant digit, so we were one off above. + // Consider 0.1 - buf will be just '1', and decpt should be 0. But + // "decptInTarget - firstSignificant" will yield -1. + ++decpt; + length = qMin(eSign - firstSignificant, bufSize); + } else { + // No significant digits means the number is just 0. + buf[0] = '0'; + length = 1; + decpt = 1; + } + } +#endif // QT_NO_DOUBLECONVERSION || QT_BOOTSTRAPPED + while (length > 1 && buf[length - 1] == '0') // drop trailing zeroes + --length; +} + +double asciiToDouble(const char *num, int numLen, bool &ok, int &processed) +{ + if (*num == '\0') { + ok = false; + processed = 0; + return 0.0; + } + + ok = true; + + // We have to catch NaN before because we need NaN as marker for "garbage" in the + // libdouble-conversion case and, in contrast to libdouble-conversion or sscanf, we don't allow + // "-nan" or "+nan" + if (qstrcmp(num, "nan") == 0) { + processed = 3; + return qt_snan(); + } else if ((num[0] == '-' || num[0] == '+') && qstrcmp(num + 1, "nan") == 0) { + processed = 0; + ok = false; + return 0.0; + } + + // Infinity values are implementation defined in the sscanf case. In the libdouble-conversion + // case we need infinity as overflow marker. + if (qstrcmp(num, "+inf") == 0) { + processed = 4; + return qt_inf(); + } else if (qstrcmp(num, "inf") == 0) { + processed = 3; + return qt_inf(); + } else if (qstrcmp(num, "-inf") == 0) { + processed = 4; + return -qt_inf(); + } + + double d = 0.0; +#if !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) + int conv_flags = double_conversion::StringToDoubleConverter::NO_FLAGS; + double_conversion::StringToDoubleConverter conv(conv_flags, 0.0, qt_snan(), 0, 0); + d = conv.StringToDouble(num, numLen, &processed); + + if (!qIsFinite(d)) { + ok = false; + if (qIsNaN(d)) { + // Garbage found. We don't accept it and return 0. + processed = 0; + return 0.0; + } else { + // Overflow. That's not OK, but we still return infinity. + return d; + } + } +#else + if (qDoubleSscanf(num, QT_CLOCALE, "%lf%n", &d, &processed) < 1) + processed = 0; + + if (processed != numLen || qIsNaN(d)) { + // Implementation defined nan symbol or garbage found. We don't accept it. + processed = 0; + ok = false; + return 0.0; + } + + if (!qIsFinite(d)) { + // Overflow. Check for implementation-defined infinity symbols and reject them. + // We assume that any infinity symbol has to contain a character that cannot be part of a + // "normal" number (that is 0-9, ., -, +, e). + ok = false; + for (int i = 0; i < numLen; ++i) { + char c = num[i]; + if ((c < '0' || c > '9') && c != '.' && c != '-' && c != '+' && c != 'e') { + // Garbage found + processed = 0; + return 0.0; + } + } + return d; + } +#endif // !defined(QT_NO_DOUBLECONVERSION) && !defined(QT_BOOTSTRAPPED) + + Q_ASSERT(processed == numLen); // Otherwise we would have gotten NaN or sorted it out above. + + // Check if underflow has occurred. + if (isZero(d)) { + for (int i = 0; i < numLen; ++i) { + if (num[i] >= '1' && num[i] <= '9') { + // if a digit before any 'e' is not 0, then a non-zero number was intended. + ok = false; + return 0.0; + } else if (num[i] == 'e') { + break; + } + } + } + return d; +} + unsigned long long qstrtoull(const char * nptr, const char **endptr, int base, bool *ok) { @@ -114,9 +414,6 @@ qstrtoll(const char * nptr, const char **endptr, int base, bool *ok) return result; } -static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, - int *sign, char **rve, char **digits_str); - QString qulltoa(qulonglong l, int base, const QChar _zero) { ushort buff[65]; // length of MAX_ULLONG in base 2 @@ -155,7 +452,7 @@ QString qlltoa(qlonglong l, int base, const QChar zero) } QString &decimalForm(QChar zero, QChar decimal, QChar group, - QString &digits, int decpt, uint precision, + QString &digits, int decpt, int precision, PrecisionMode pm, bool always_show_decpt, bool thousands_group) @@ -172,11 +469,11 @@ QString &decimalForm(QChar zero, QChar decimal, QChar group, if (pm == PMDecimalDigits) { uint decimal_digits = digits.length() - decpt; - for (uint i = decimal_digits; i < precision; ++i) + for (int i = decimal_digits; i < precision; ++i) digits.append(zero); } else if (pm == PMSignificantDigits) { - for (uint i = digits.length(); i < precision; ++i) + for (int i = digits.length(); i < precision; ++i) digits.append(zero); } else { // pm == PMChopTrailingZeros @@ -198,18 +495,19 @@ QString &decimalForm(QChar zero, QChar decimal, QChar group, QString &exponentForm(QChar zero, QChar decimal, QChar exponential, QChar group, QChar plus, QChar minus, - QString &digits, int decpt, uint precision, + QString &digits, int decpt, int precision, PrecisionMode pm, - bool always_show_decpt) + bool always_show_decpt, + bool leading_zero_in_exponent) { int exp = decpt - 1; if (pm == PMDecimalDigits) { - for (uint i = digits.length(); i < precision + 1; ++i) + for (int i = digits.length(); i < precision + 1; ++i) digits.append(zero); } else if (pm == PMSignificantDigits) { - for (uint i = digits.length(); i < precision; ++i) + for (int i = digits.length(); i < precision; ++i) digits.append(zero); } else { // pm == PMChopTrailingZeros @@ -220,2398 +518,42 @@ QString &exponentForm(QChar zero, QChar decimal, QChar exponential, digits.append(exponential); digits.append(QLocaleData::longLongToString(zero, group, plus, minus, - exp, 2, 10, -1, QLocaleData::AlwaysShowSign)); + exp, leading_zero_in_exponent ? 2 : 1, 10, -1, QLocaleData::AlwaysShowSign)); return digits; } -/* From: NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp */ -/* $FreeBSD: src/lib/libc/stdlib/netbsd_strtod.c,v 1.2.2.2 2001/03/02 17:14:15 tegge Exp $ */ - -/* Please send bug reports to - David M. Gay - AT&T Bell Laboratories, Room 2C-463 - 600 Mountain Avenue - Murray Hill, NJ 07974-2070 - U.S.A. - dmg@research.att.com or research!dmg - */ - -/* strtod for IEEE-, VAX-, and IBM-arithmetic machines. - * - * This strtod returns a nearest machine number to the input decimal - * string (or sets errno to ERANGE). With IEEE arithmetic, ties are - * broken by the IEEE round-even rule. Otherwise ties are broken by - * biased rounding (add half and chop). - * - * Inspired loosely by William D. Clinger's paper "How to Read Floating - * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * - * 1. We only require IEEE, IBM, or VAX double-precision - * arithmetic (not IEEE double-extended). - * 2. We get by with floating-point arithmetic in a case that - * Clinger missed -- when we're computing d * 10^n - * for a small integer d and the integer n is not too - * much larger than 22 (the maximum integer k for which - * we can represent 10^k exactly), we may be able to - * compute (d*10^k) * 10^(e-k) with just one roundoff. - * 3. Rather than a bit-at-a-time adjustment of the binary - * result in the hard case, we use floating-point - * arithmetic to determine the adjustment to within - * one bit; only in really hard cases do we need to - * compute a second residual. - * 4. Because of 3., we don't need a large table of powers of 10 - * for ten-to-e (just some small tables, e.g. of 10^k - * for 0 <= k <= 22). - */ - -/* - * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least - * significant byte has the lowest address. - * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most - * significant byte has the lowest address. - * #define Long int on machines with 32-bit ints and 64-bit longs. - * #define Sudden_Underflow for IEEE-format machines without gradual - * underflow (i.e., that flush to zero on underflow). - * #define IBM for IBM mainframe-style floating-point arithmetic. - * #define VAX for VAX-style floating-point arithmetic. - * #define Unsigned_Shifts if >> does treats its left operand as unsigned. - * #define No_leftright to omit left-right logic in fast floating-point - * computation of dtoa. - * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3. - * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines - * that use extended-precision instructions to compute rounded - * products and quotients) with IBM. - * #define ROUND_BIASED for IEEE-format with biased rounding. - * #define Inaccurate_Divide for IEEE-format with correctly rounded - * products but inaccurate quotients, e.g., for Intel i860. - * #define Just_16 to store 16 bits per 32-bit Long when doing high-precision - * integer arithmetic. Whether this speeds things up or slows things - * down depends on the machine and the number being converted. - * #define KR_headers for old-style C function headers. - * #define Bad_float_h if your system lacks a float.h or if it does not - * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP, - * FLT_RADIX, FLT_ROUNDS, and DBL_MAX. - * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n) - * if memory is available and otherwise does something you deem - * appropriate. If MALLOC is undefined, malloc will be invoked - * directly -- and assumed always to succeed. - */ - -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: strtod.c,v 1.26 1998/02/03 18:44:21 perry Exp $"); -#endif /* LIBC_SCCS and not lint */ - -/* -#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \ - defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \ - defined(__powerpc__) || defined(Q_OS_WIN) || defined(Q_OS_DARWIN) || defined(Q_OS_MAC) || \ - defined(mips) || defined(Q_OS_AIX) || defined(Q_OS_SOLARIS) -# define IEEE_BIG_OR_LITTLE_ENDIAN 1 -#endif -*/ - -// *All* of our architectures have IEEE arithmetic, don't they? -#define IEEE_BIG_OR_LITTLE_ENDIAN 1 - -#ifdef __arm32__ -/* - * Although the CPU is little endian the FP has different - * byte and word endianness. The byte order is still little endian - * but the word order is big endian. - */ -#define IEEE_BIG_OR_LITTLE_ENDIAN -#endif - -#ifdef vax -#define VAX -#endif - -#define Long qint32 -#define ULong quint32 - -#define MALLOC malloc - -#ifdef BSD_QDTOA_DEBUG -QT_BEGIN_INCLUDE_NAMESPACE -#include <stdio.h> -QT_END_INCLUDE_NAMESPACE - -#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);} -#endif - -#ifdef Unsigned_Shifts -#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000; -#else -#define Sign_Extend(a,b) /*no-op*/ -#endif - -#if (defined(IEEE_BIG_OR_LITTLE_ENDIAN) + defined(VAX) + defined(IBM)) != 1 -#error Exactly one of IEEE_BIG_OR_LITTLE_ENDIAN, VAX, or IBM should be defined. -#endif - -static inline ULong getWord0(const NEEDS_VOLATILE double x) -{ - const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; - } else { - return (ptr[7]<<24) + (ptr[6]<<16) + (ptr[5]<<8) + ptr[4]; - } -} - -static inline void setWord0(NEEDS_VOLATILE double *x, ULong l) -{ - NEEDS_VOLATILE uchar *ptr = reinterpret_cast<NEEDS_VOLATILE uchar *>(x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - ptr[0] = uchar(l>>24); - ptr[1] = uchar(l>>16); - ptr[2] = uchar(l>>8); - ptr[3] = uchar(l); - } else { - ptr[7] = uchar(l>>24); - ptr[6] = uchar(l>>16); - ptr[5] = uchar(l>>8); - ptr[4] = uchar(l); - } -} - -static inline ULong getWord1(const NEEDS_VOLATILE double x) -{ - const NEEDS_VOLATILE uchar *ptr = reinterpret_cast<const NEEDS_VOLATILE uchar *>(&x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - return (ptr[4]<<24) + (ptr[5]<<16) + (ptr[6]<<8) + ptr[7]; - } else { - return (ptr[3]<<24) + (ptr[2]<<16) + (ptr[1]<<8) + ptr[0]; - } -} -static inline void setWord1(NEEDS_VOLATILE double *x, ULong l) -{ - NEEDS_VOLATILE uchar *ptr = reinterpret_cast<uchar NEEDS_VOLATILE *>(x); - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - ptr[4] = uchar(l>>24); - ptr[5] = uchar(l>>16); - ptr[6] = uchar(l>>8); - ptr[7] = uchar(l); - } else { - ptr[3] = uchar(l>>24); - ptr[2] = uchar(l>>16); - ptr[1] = uchar(l>>8); - ptr[0] = uchar(l); - } -} - -static inline void Storeinc(ULong *&a, const ULong &b, const ULong &c) +double qstrtod(const char *s00, const char **se, bool *ok) { - - *a = (ushort(b) << 16) | ushort(c); - ++a; -} - -/* #define P DBL_MANT_DIG */ -/* Ten_pmax = floor(P*log(2)/log(5)) */ -/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */ -/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */ -/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */ - -#if defined(IEEE_BIG_OR_LITTLE_ENDIAN) -#define Exp_shift 20 -#define Exp_shift1 20 -#define Exp_msk1 0x100000 -#define Exp_msk11 0x100000 -#define Exp_mask 0x7ff00000 -#define P 53 -#define Bias 1023 -#define IEEE_Arith -#define Emin (-1022) -#define Exp_1 0x3ff00000 -#define Exp_11 0x3ff00000 -#define Ebits 11 -#define Frac_mask 0xfffff -#define Frac_mask1 0xfffff -#define Ten_pmax 22 -#define Bletch 0x10 -#define Bndry_mask 0xfffff -#define Bndry_mask1 0xfffff -#if defined(LSB) && defined(Q_OS_VXWORKS) -#undef LSB -#endif -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 1 -#define Tiny0 0 -#define Tiny1 1 -#define Quick_max 14 -#define Int_max 14 -#define Infinite(x) (getWord0(x) == 0x7ff00000) /* sufficient test for here */ -#else -#undef Sudden_Underflow -#define Sudden_Underflow -#ifdef IBM -#define Exp_shift 24 -#define Exp_shift1 24 -#define Exp_msk1 0x1000000 -#define Exp_msk11 0x1000000 -#define Exp_mask 0x7f000000 -#define P 14 -#define Bias 65 -#define Exp_1 0x41000000 -#define Exp_11 0x41000000 -#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */ -#define Frac_mask 0xffffff -#define Frac_mask1 0xffffff -#define Bletch 4 -#define Ten_pmax 22 -#define Bndry_mask 0xefffff -#define Bndry_mask1 0xffffff -#define LSB 1 -#define Sign_bit 0x80000000 -#define Log2P 4 -#define Tiny0 0x100000 -#define Tiny1 0 -#define Quick_max 14 -#define Int_max 15 -#else /* VAX */ -#define Exp_shift 23 -#define Exp_shift1 7 -#define Exp_msk1 0x80 -#define Exp_msk11 0x800000 -#define Exp_mask 0x7f80 -#define P 56 -#define Bias 129 -#define Exp_1 0x40800000 -#define Exp_11 0x4080 -#define Ebits 8 -#define Frac_mask 0x7fffff -#define Frac_mask1 0xffff007f -#define Ten_pmax 24 -#define Bletch 2 -#define Bndry_mask 0xffff007f -#define Bndry_mask1 0xffff007f -#define LSB 0x10000 -#define Sign_bit 0x8000 -#define Log2P 1 -#define Tiny0 0x80 -#define Tiny1 0 -#define Quick_max 15 -#define Int_max 15 -#endif -#endif - -#ifndef IEEE_Arith -#define ROUND_BIASED -#endif - -#ifdef RND_PRODQUOT -#define rounded_product(a,b) a = rnd_prod(a, b) -#define rounded_quotient(a,b) a = rnd_quot(a, b) -extern double rnd_prod(double, double), rnd_quot(double, double); -#else -#define rounded_product(a,b) a *= b -#define rounded_quotient(a,b) a /= b -#endif - -#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1)) -#define Big1 0xffffffff - -#ifndef Just_16 -/* When Pack_32 is not defined, we store 16 bits per 32-bit Long. - * This makes some inner loops simpler and sometimes saves work - * during multiplications, but it often seems to make things slightly - * slower. Hence the default is now to store 32 bits per Long. - */ -#ifndef Pack_32 -#define Pack_32 -#endif -#endif - -#define Kmax 15 - -struct -Bigint { - struct Bigint *next; - int k, maxwds, sign, wds; - ULong x[1]; -}; - - typedef struct Bigint Bigint; - -static Bigint *Balloc(int k) -{ - int x; - Bigint *rv; - - x = 1 << k; - rv = static_cast<Bigint *>(MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long))); - Q_CHECK_PTR(rv); - rv->k = k; - rv->maxwds = x; - rv->sign = rv->wds = 0; - return rv; -} - -static void Bfree(Bigint *v) -{ - free(v); -} - -#define Bcopy(x,y) memcpy(reinterpret_cast<char *>(&x->sign), reinterpret_cast<char *>(&y->sign), \ -y->wds*sizeof(Long) + 2*sizeof(int)) - -/* multiply by m and add a */ -static Bigint *multadd(Bigint *b, int m, int a) -{ - int i, wds; - ULong *x, y; -#ifdef Pack_32 - ULong xi, z; -#endif - Bigint *b1; - - wds = b->wds; - x = b->x; - i = 0; - do { -#ifdef Pack_32 - xi = *x; - y = (xi & 0xffff) * m + a; - z = (xi >> 16) * m + (y >> 16); - a = (z >> 16); - *x++ = (z << 16) + (y & 0xffff); -#else - y = *x * m + a; - a = (y >> 16); - *x++ = y & 0xffff; -#endif - } - while(++i < wds); - if (a) { - if (wds >= b->maxwds) { - b1 = Balloc(b->k+1); - Bcopy(b1, b); - Bfree(b); - b = b1; - } - b->x[wds++] = a; - b->wds = wds; - } - return b; -} - -static Bigint *s2b(const char *s, int nd0, int nd, ULong y9) -{ - Bigint *b; - int i, k; - Long x, y; - - x = (nd + 8) / 9; - for(k = 0, y = 1; x > y; y <<= 1, k++) ; -#ifdef Pack_32 - b = Balloc(k); - b->x[0] = y9; - b->wds = 1; -#else - b = Balloc(k+1); - b->x[0] = y9 & 0xffff; - b->wds = (b->x[1] = y9 >> 16) ? 2 : 1; -#endif - - i = 9; - if (9 < nd0) { - s += 9; - do b = multadd(b, 10, *s++ - '0'); - while(++i < nd0); - s++; - } - else - s += 10; - for(; i < nd; i++) - b = multadd(b, 10, *s++ - '0'); - return b; -} - -static int hi0bits(ULong x) -{ - int k = 0; - - if (!(x & 0xffff0000)) { - k = 16; - x <<= 16; - } - if (!(x & 0xff000000)) { - k += 8; - x <<= 8; - } - if (!(x & 0xf0000000)) { - k += 4; - x <<= 4; - } - if (!(x & 0xc0000000)) { - k += 2; - x <<= 2; - } - if (!(x & 0x80000000)) { - k++; - if (!(x & 0x40000000)) - return 32; - } - return k; -} - -static int lo0bits(ULong *y) -{ - int k; - ULong x = *y; - - if (x & 7) { - if (x & 1) - return 0; - if (x & 2) { - *y = x >> 1; - return 1; - } - *y = x >> 2; - return 2; - } - k = 0; - if (!(x & 0xffff)) { - k = 16; - x >>= 16; - } - if (!(x & 0xff)) { - k += 8; - x >>= 8; - } - if (!(x & 0xf)) { - k += 4; - x >>= 4; - } - if (!(x & 0x3)) { - k += 2; - x >>= 2; - } - if (!(x & 1)) { - k++; - x >>= 1; - if (!x & 1) - return 32; - } - *y = x; - return k; -} - -static Bigint *i2b(int i) -{ - Bigint *b; - - b = Balloc(1); - b->x[0] = i; - b->wds = 1; - return b; -} - -static Bigint *mult(Bigint *a, Bigint *b) -{ - Bigint *c; - int k, wa, wb, wc; - ULong carry, y, z; - ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0; -#ifdef Pack_32 - ULong z2; -#endif - - if (a->wds < b->wds) { - c = a; - a = b; - b = c; - } - k = a->k; - wa = a->wds; - wb = b->wds; - wc = wa + wb; - if (wc > a->maxwds) - k++; - c = Balloc(k); - for(x = c->x, xa = x + wc; x < xa; x++) - *x = 0; - xa = a->x; - xae = xa + wa; - xb = b->x; - xbe = xb + wb; - xc0 = c->x; -#ifdef Pack_32 - for(; xb < xbe; xb++, xc0++) { - if ((y = *xb & 0xffff) != 0) { - x = xa; - xc = xc0; - carry = 0; - do { - z = (*x & 0xffff) * y + (*xc & 0xffff) + carry; - carry = z >> 16; - z2 = (*x++ >> 16) * y + (*xc >> 16) + carry; - carry = z2 >> 16; - Storeinc(xc, z2, z); - } - while(x < xae); - *xc = carry; - } - if ((y = *xb >> 16) != 0) { - x = xa; - xc = xc0; - carry = 0; - z2 = *xc; - do { - z = (*x & 0xffff) * y + (*xc >> 16) + carry; - carry = z >> 16; - Storeinc(xc, z, z2); - z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry; - carry = z2 >> 16; - } - while(x < xae); - *xc = z2; - } - } -#else - for(; xb < xbe; xc0++) { - if (y = *xb++) { - x = xa; - xc = xc0; - carry = 0; - do { - z = *x++ * y + *xc + carry; - carry = z >> 16; - *xc++ = z & 0xffff; - } - while(x < xae); - *xc = carry; - } - } -#endif - for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ; - c->wds = wc; - return c; -} - -static Bigint *p5s; - -struct p5s_deleter -{ - ~p5s_deleter() - { - while (p5s) { - Bigint *next = p5s->next; - Bfree(p5s); - p5s = next; - } - } -}; - -static Bigint *pow5mult(Bigint *b, int k) -{ - Bigint *b1, *p5, *p51; - int i; - static const int p05[3] = { 5, 25, 125 }; - - if ((i = k & 3) != 0) - b = multadd(b, p05[i-1], 0); - - if (!(k >>= 2)) - return b; - if (!(p5 = p5s)) { - /* first time */ - static p5s_deleter deleter; - p5 = p5s = i2b(625); - p5->next = 0; - } - for(;;) { - if (k & 1) { - b1 = mult(b, p5); - Bfree(b); - b = b1; - } - if (!(k >>= 1)) - break; - if (!(p51 = p5->next)) { - p51 = p5->next = mult(p5,p5); - p51->next = 0; - } - p5 = p51; - } - return b; -} - -static Bigint *lshift(Bigint *b, int k) -{ - int i, k1, n, n1; - Bigint *b1; - ULong *x, *x1, *xe, z; - -#ifdef Pack_32 - n = k >> 5; -#else - n = k >> 4; -#endif - k1 = b->k; - n1 = n + b->wds + 1; - for(i = b->maxwds; n1 > i; i <<= 1) - k1++; - b1 = Balloc(k1); - x1 = b1->x; - for(i = 0; i < n; i++) - *x1++ = 0; - x = b->x; - xe = x + b->wds; -#ifdef Pack_32 - if (k &= 0x1f) { - k1 = 32 - k; - z = 0; - do { - *x1++ = *x << k | z; - z = *x++ >> k1; - } - while(x < xe); - if ((*x1 = z) != 0) - ++n1; - } -#else - if (k &= 0xf) { - k1 = 16 - k; - z = 0; - do { - *x1++ = *x << k & 0xffff | z; - z = *x++ >> k1; - } - while(x < xe); - if (*x1 = z) - ++n1; - } -#endif - else do - *x1++ = *x++; - while(x < xe); - b1->wds = n1 - 1; - Bfree(b); - return b1; -} - -static int cmp(Bigint *a, Bigint *b) -{ - ULong *xa, *xa0, *xb, *xb0; - int i, j; - - i = a->wds; - j = b->wds; -#ifdef BSD_QDTOA_DEBUG - if (i > 1 && !a->x[i-1]) - Bug("cmp called with a->x[a->wds-1] == 0"); - if (j > 1 && !b->x[j-1]) - Bug("cmp called with b->x[b->wds-1] == 0"); -#endif - if (i -= j) - return i; - xa0 = a->x; - xa = xa0 + j; - xb0 = b->x; - xb = xb0 + j; - for(;;) { - if (*--xa != *--xb) - return *xa < *xb ? -1 : 1; - if (xa <= xa0) - break; - } - return 0; -} - -static Bigint *diff(Bigint *a, Bigint *b) -{ - Bigint *c; - int i, wa, wb; - Long borrow, y; /* We need signed shifts here. */ - ULong *xa, *xae, *xb, *xbe, *xc; -#ifdef Pack_32 - Long z; -#endif - - i = cmp(a,b); - if (!i) { - c = Balloc(0); - c->wds = 1; - c->x[0] = 0; - return c; - } - if (i < 0) { - c = a; - a = b; - b = c; - i = 1; - } - else - i = 0; - c = Balloc(a->k); - c->sign = i; - wa = a->wds; - xa = a->x; - xae = xa + wa; - wb = b->wds; - xb = b->x; - xbe = xb + wb; - xc = c->x; - borrow = 0; -#ifdef Pack_32 - do { - y = (*xa & 0xffff) - (*xb & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) - (*xb++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(xc, z, y); - } - while(xb < xbe); - while(xa < xae) { - y = (*xa & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*xa++ >> 16) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(xc, z, y); - } -#else - do { - y = *xa++ - *xb++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *xc++ = y & 0xffff; - } - while(xb < xbe); - while(xa < xae) { - y = *xa++ + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *xc++ = y & 0xffff; - } -#endif - while(!*--xc) - wa--; - c->wds = wa; - return c; -} - -static double ulp(double x) -{ - Long L; - double a; - - L = (getWord0(x) & Exp_mask) - (P-1)*Exp_msk1; -#ifndef Sudden_Underflow - if (L > 0) { -#endif -#ifdef IBM - L |= Exp_msk1 >> 4; -#endif - setWord0(&a, L); - setWord1(&a, 0); -#ifndef Sudden_Underflow - } - else { - L = -L >> Exp_shift; - if (L < Exp_shift) { - setWord0(&a, 0x80000 >> L); - setWord1(&a, 0); - } - else { - setWord0(&a, 0); - L -= Exp_shift; - setWord1(&a, L >= 31 ? 1U : 1U << (31 - L)); - } - } -#endif - return a; -} - -static double b2d(Bigint *a, int *e) -{ - ULong *xa, *xa0, w, y, z; - int k; - double d; - - xa0 = a->x; - xa = xa0 + a->wds; - y = *--xa; -#ifdef BSD_QDTOA_DEBUG - if (!y) Bug("zero y in b2d"); -#endif - k = hi0bits(y); - *e = 32 - k; -#ifdef Pack_32 - if (k < Ebits) { - setWord0(&d, Exp_1 | y >> (Ebits - k)); - w = xa > xa0 ? *--xa : 0; - setWord1(&d, y << ((32-Ebits) + k) | w >> (Ebits - k)); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - if (k -= Ebits) { - setWord0(&d, Exp_1 | y << k | z >> (32 - k)); - y = xa > xa0 ? *--xa : 0; - setWord1(&d, z << k | y >> (32 - k)); - } - else { - setWord0(&d, Exp_1 | y); - setWord1(&d, z); - } -#else - if (k < Ebits + 16) { - z = xa > xa0 ? *--xa : 0; - setWord0(&d, Exp_1 | y << k - Ebits | z >> Ebits + 16 - k); - w = xa > xa0 ? *--xa : 0; - y = xa > xa0 ? *--xa : 0; - setWord1(&d, z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k); - goto ret_d; - } - z = xa > xa0 ? *--xa : 0; - w = xa > xa0 ? *--xa : 0; - k -= Ebits + 16; - setWord0(&d, Exp_1 | y << k + 16 | z << k | w >> 16 - k); - y = xa > xa0 ? *--xa : 0; - setWord1(&d, w << k + 16 | y << k); -#endif - ret_d: - return d; -} - -static Bigint *d2b(double d, int *e, int *bits) -{ - Bigint *b; - int de, i, k; - ULong *x, y, z; - -#ifdef Pack_32 - b = Balloc(1); -#else - b = Balloc(2); -#endif - x = b->x; - - z = getWord0(d) & Frac_mask; - setWord0(&d, getWord0(d) & 0x7fffffff); /* clear sign bit, which we ignore */ -#ifdef Sudden_Underflow - de = (int)(getWord0(d) >> Exp_shift); -#ifndef IBM - z |= Exp_msk11; -#endif -#else - if ((de = int(getWord0(d) >> Exp_shift)) != 0) - z |= Exp_msk1; -#endif -#ifdef Pack_32 - if ((y = getWord1(d)) != 0) { - if ((k = lo0bits(&y)) != 0) { - x[0] = y | z << (32 - k); - z >>= k; - } - else - x[0] = y; - i = b->wds = (x[1] = z) ? 2 : 1; - } - else { -#ifdef BSD_QDTOA_DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - x[0] = z; - i = b->wds = 1; - k += 32; - } -#else - if (y = getWord1(d)) { - if (k = lo0bits(&y)) - if (k >= 16) { - x[0] = y | z << 32 - k & 0xffff; - x[1] = z >> k - 16 & 0xffff; - x[2] = z >> k; - i = 2; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16 | z << 16 - k & 0xffff; - x[2] = z >> k & 0xffff; - x[3] = z >> k+16; - i = 3; - } - else { - x[0] = y & 0xffff; - x[1] = y >> 16; - x[2] = z & 0xffff; - x[3] = z >> 16; - i = 3; - } - } - else { -#ifdef BSD_QDTOA_DEBUG - if (!z) - Bug("Zero passed to d2b"); -#endif - k = lo0bits(&z); - if (k >= 16) { - x[0] = z; - i = 0; - } - else { - x[0] = z & 0xffff; - x[1] = z >> 16; - i = 1; - } - k += 32; - } - while(!x[i]) - --i; - b->wds = i + 1; -#endif -#ifndef Sudden_Underflow - if (de) { -#endif -#ifdef IBM - *e = (de - Bias - (P-1) << 2) + k; - *bits = 4*P + 8 - k - hi0bits(getWord0(d) & Frac_mask); -#else - *e = de - Bias - (P-1) + k; - *bits = P - k; -#endif -#ifndef Sudden_Underflow - } - else { - *e = de - Bias - (P-1) + 1 + k; -#ifdef Pack_32 - *bits = 32*i - hi0bits(x[i-1]); -#else - *bits = (i+2)*16 - hi0bits(x[i]); -#endif - } -#endif - return b; -} - -static double ratio(Bigint *a, Bigint *b) -{ - double da, db; - int k, ka, kb; - - da = b2d(a, &ka); - db = b2d(b, &kb); -#ifdef Pack_32 - k = ka - kb + 32*(a->wds - b->wds); -#else - k = ka - kb + 16*(a->wds - b->wds); -#endif -#ifdef IBM - if (k > 0) { - setWord0(&da, getWord0(da) + (k >> 2)*Exp_msk1); - if (k &= 3) - da *= 1 << k; - } - else { - k = -k; - setWord0(&db, getWord0(db) + (k >> 2)*Exp_msk1); - if (k &= 3) - db *= 1 << k; - } -#else - if (k > 0) - setWord0(&da, getWord0(da) + k*Exp_msk1); - else { - k = -k; - setWord0(&db, getWord0(db) + k*Exp_msk1); - } -#endif - return da / db; -} - -static const double tens[] = { - 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, - 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, - 1e20, 1e21, 1e22 -#ifdef VAX - , 1e23, 1e24 -#endif -}; - -#ifdef IEEE_Arith -static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 }; -static const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; -#define n_bigtens 5 -#else -#ifdef IBM -static const double bigtens[] = { 1e16, 1e32, 1e64 }; -static const double tinytens[] = { 1e-16, 1e-32, 1e-64 }; -#define n_bigtens 3 -#else -static const double bigtens[] = { 1e16, 1e32 }; -static const double tinytens[] = { 1e-16, 1e-32 }; -#define n_bigtens 2 -#endif -#endif - -/* - The pre-release gcc3.3 shipped with SuSE 8.2 has a bug which causes - the comparison 1e-100 == 0.0 to return true. As a workaround, we - compare it to a global variable containing 0.0, which produces - correct assembler output. - - ### consider detecting the broken compilers and using the static - ### double for these, and use a #define for all working compilers -*/ -static double g_double_zero = 0.0; - -Q_CORE_EXPORT double qstrtod(const char *s00, const char **se, bool *ok) -{ - int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign, - e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign; - const char *s, *s0, *s1; - double aadj, aadj1, adj, rv, rv0; - Long L; - ULong y, z; - Bigint *bb1, *bd0; - Bigint *bb = NULL, *bd = NULL, *bs = NULL, *delta = NULL;/* pacify gcc */ - - /* - #ifndef KR_headers - const char decimal_point = localeconv()->decimal_point[0]; - #else - const char decimal_point = '.'; - #endif */ - if (ok != 0) - *ok = true; - - const char decimal_point = '.'; - - sign = nz0 = nz = 0; - rv = 0.; - - - for(s = s00; ascii_isspace(uchar(*s)); s++) - ; - - if (*s == '-') { - sign = 1; - s++; - } else if (*s == '+') { - s++; - } - - if (*s == '\0') { - s = s00; - goto ret; - } - - if (*s == '0') { - nz0 = 1; - while(*++s == '0') ; - if (!*s) - goto ret; - } - s0 = s; - y = z = 0; - for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) - if (nd < 9) - y = 10*y + c - '0'; - else if (nd < 16) - z = 10*z + c - '0'; - nd0 = nd; - if (c == decimal_point) { - c = *++s; - if (!nd) { - for(; c == '0'; c = *++s) - nz++; - if (c > '0' && c <= '9') { - s0 = s; - nf += nz; - nz = 0; - goto have_dig; - } - goto dig_done; - } - for(; c >= '0' && c <= '9'; c = *++s) { - have_dig: - nz++; - if (c -= '0') { - nf += nz; - for(i = 1; i < nz; i++) - if (nd++ < 9) - y *= 10; - else if (nd <= DBL_DIG + 1) - z *= 10; - if (nd++ < 9) - y = 10*y + c; - else if (nd <= DBL_DIG + 1) - z = 10*z + c; - nz = 0; - } - } - } - dig_done: - e = 0; - if (c == 'e' || c == 'E') { - if (!nd && !nz && !nz0) { - s = s00; - goto ret; - } - s00 = s; - esign = 0; - switch(c = *++s) { - case '-': - esign = 1; - case '+': - c = *++s; - } - if (c >= '0' && c <= '9') { - while(c == '0') - c = *++s; - if (c > '0' && c <= '9') { - L = c - '0'; - s1 = s; - while((c = *++s) >= '0' && c <= '9') - L = 10*L + c - '0'; - if (s - s1 > 8 || L > 19999) - /* Avoid confusion from exponents - * so large that e might overflow. - */ - e = 19999; /* safe for 16 bit ints */ - else - e = int(L); - if (esign) - e = -e; - } - else - e = 0; - } - else - s = s00; - } - if (!nd) { - if (!nz && !nz0) - s = s00; - goto ret; - } - e1 = e -= nf; - - /* Now we have nd0 digits, starting at s0, followed by a - * decimal point, followed by nd-nd0 digits. The number we're - * after is the integer represented by those digits times - * 10**e */ - - if (!nd0) - nd0 = nd; - k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; - rv = y; - if (k > 9) - rv = tens[k - 9] * rv + z; - - bd0 = 0; - if (nd <= DBL_DIG -#ifndef RND_PRODQUOT - && FLT_ROUNDS == 1 -#endif - ) { - if (!e) - goto ret; - if (e > 0) { - if (e <= Ten_pmax) { -#ifdef VAX - goto vax_ovfl_check; -#else - /* rv = */ rounded_product(rv, tens[e]); - goto ret; -#endif - } - i = DBL_DIG - nd; - if (e <= Ten_pmax + i) { - /* A fancier test would sometimes let us do - * this for larger i values. - */ - e -= i; - rv *= tens[i]; -#ifdef VAX - /* VAX exponent range is so narrow we must - * worry about overflow here... - */ - vax_ovfl_check: - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - /* rv = */ rounded_product(rv, tens[e]); - if ((getWord0(rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) - goto ovfl; - setWord0(&rv, getWord0(rv) + P*Exp_msk1); -#else - /* rv = */ rounded_product(rv, tens[e]); -#endif - goto ret; - } - } -#ifndef Inaccurate_Divide - else if (e >= -Ten_pmax) { - /* rv = */ rounded_quotient(rv, tens[-e]); - goto ret; - } -#endif - } - e1 += nd - k; - - /* Get starting approximation = rv * 10**e1 */ - - if (e1 > 0) { - if ((i = e1 & 15) != 0) - rv *= tens[i]; - if (e1 &= ~15) { - if (e1 > DBL_MAX_10_EXP) { - ovfl: - // errno = ERANGE; - if (ok != 0) - *ok = false; -#ifdef __STDC__ - rv = HUGE_VAL; -#else - /* Can't trust HUGE_VAL */ -#ifdef IEEE_Arith - setWord0(&rv, Exp_mask); - setWord1(&rv, 0); -#else - setWord0(&rv, Big0); - setWord1(&rv, Big1); -#endif -#endif - if (bd0) - goto retfree; - goto ret; - } - if (e1 >>= 4) { - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= bigtens[j]; - /* The last multiplication could overflow. */ - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - rv *= bigtens[j]; - if ((z = getWord0(rv) & Exp_mask) - > Exp_msk1*(DBL_MAX_EXP+Bias-P)) - goto ovfl; - if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) { - /* set to largest number */ - /* (Can't trust DBL_MAX) */ - setWord0(&rv, Big0); - setWord1(&rv, Big1); - } - else - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - } - - } - } - else if (e1 < 0) { - e1 = -e1; - if ((i = e1 & 15) != 0) - rv /= tens[i]; - if (e1 &= ~15) { - e1 >>= 4; - if (e1 >= 1 << n_bigtens) - goto undfl; - for(j = 0; e1 > 1; j++, e1 >>= 1) - if (e1 & 1) - rv *= tinytens[j]; - /* The last multiplication could underflow. */ - rv0 = rv; - rv *= tinytens[j]; - if (rv == g_double_zero) - { - rv = 2.*rv0; - rv *= tinytens[j]; - if (rv == g_double_zero) - { - undfl: - rv = 0.; - // errno = ERANGE; - if (ok != 0) - *ok = false; - if (bd0) - goto retfree; - goto ret; - } - setWord0(&rv, Tiny0); - setWord1(&rv, Tiny1); - /* The refinement below will clean - * this approximation up. - */ - } - } - } - - /* Now the hard part -- adjusting rv to the correct value.*/ - - /* Put digits into bd: true value = bd * 10^e */ - - bd0 = s2b(s0, nd0, nd, y); - - for(;;) { - bd = Balloc(bd0->k); - Bcopy(bd, bd0); - bb = d2b(rv, &bbe, &bbbits); /* rv = bb * 2^bbe */ - bs = i2b(1); - - if (e >= 0) { - bb2 = bb5 = 0; - bd2 = bd5 = e; - } - else { - bb2 = bb5 = -e; - bd2 = bd5 = 0; - } - if (bbe >= 0) - bb2 += bbe; - else - bd2 -= bbe; - bs2 = bb2; -#ifdef Sudden_Underflow -#ifdef IBM - j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3); -#else - j = P + 1 - bbbits; -#endif -#else - i = bbe + bbbits - 1; /* logb(rv) */ - if (i < Emin) /* denormal */ - j = bbe + (P-Emin); - else - j = P + 1 - bbbits; -#endif - bb2 += j; - bd2 += j; - i = bb2 < bd2 ? bb2 : bd2; - if (i > bs2) - i = bs2; - if (i > 0) { - bb2 -= i; - bd2 -= i; - bs2 -= i; - } - if (bb5 > 0) { - bs = pow5mult(bs, bb5); - bb1 = mult(bs, bb); - Bfree(bb); - bb = bb1; - } - if (bb2 > 0) - bb = lshift(bb, bb2); - if (bd5 > 0) - bd = pow5mult(bd, bd5); - if (bd2 > 0) - bd = lshift(bd, bd2); - if (bs2 > 0) - bs = lshift(bs, bs2); - delta = diff(bb, bd); - dsign = delta->sign; - delta->sign = 0; - i = cmp(delta, bs); - if (i < 0) { - /* Error is less than half an ulp -- check for - * special case of mantissa a power of two. - */ - if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) - break; - delta = lshift(delta,Log2P); - if (cmp(delta, bs) > 0) - goto drop_down; - break; - } - if (i == 0) { - /* exactly half-way between */ - if (dsign) { - if ((getWord0(rv) & Bndry_mask1) == Bndry_mask1 - && getWord1(rv) == 0xffffffff) { - /*boundary case -- increment exponent*/ - setWord0(&rv, (getWord0(rv) & Exp_mask) - + Exp_msk1 -#ifdef IBM - | Exp_msk1 >> 4 -#endif - ); - setWord1(&rv, 0); - break; - } - } - else if (!(getWord0(rv) & Bndry_mask) && !getWord1(rv)) { - drop_down: - /* boundary case -- decrement exponent */ -#ifdef Sudden_Underflow - L = getWord0(rv) & Exp_mask; -#ifdef IBM - if (L < Exp_msk1) -#else - if (L <= Exp_msk1) -#endif - goto undfl; - L -= Exp_msk1; -#else - L = (getWord0(rv) & Exp_mask) - Exp_msk1; -#endif - setWord0(&rv, L | Bndry_mask1); - setWord1(&rv, 0xffffffff); -#ifdef IBM - goto cont; -#else - break; -#endif - } -#ifndef ROUND_BIASED - if (!(getWord1(rv) & LSB)) - break; -#endif - if (dsign) - rv += ulp(rv); -#ifndef ROUND_BIASED - else { - rv -= ulp(rv); -#ifndef Sudden_Underflow - if (rv == g_double_zero) - goto undfl; -#endif - } -#endif - break; - } - if ((aadj = ratio(delta, bs)) <= 2.) { - if (dsign) - aadj = aadj1 = 1.; - else if (getWord1(rv) || getWord0(rv) & Bndry_mask) { -#ifndef Sudden_Underflow - if (getWord1(rv) == Tiny1 && !getWord0(rv)) - goto undfl; -#endif - aadj = 1.; - aadj1 = -1.; - } - else { - /* special case -- power of FLT_RADIX to be */ - /* rounded down... */ - - if (aadj < 2./FLT_RADIX) - aadj = 1./FLT_RADIX; - else - aadj *= 0.5; - aadj1 = -aadj; - } - } - else { - aadj *= 0.5; - aadj1 = dsign ? aadj : -aadj; -#ifdef Check_FLT_ROUNDS - switch(FLT_ROUNDS) { - case 2: /* towards +infinity */ - aadj1 -= 0.5; - break; - case 0: /* towards 0 */ - case 3: /* towards -infinity */ - aadj1 += 0.5; - } -#else - if (FLT_ROUNDS == 0) - aadj1 += 0.5; -#endif - } - y = getWord0(rv) & Exp_mask; - - /* Check for overflow */ - - if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) { - rv0 = rv; - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - adj = aadj1 * ulp(rv); - rv += adj; - if ((getWord0(rv) & Exp_mask) >= - Exp_msk1*(DBL_MAX_EXP+Bias-P)) { - if (getWord0(rv0) == Big0 && getWord1(rv0) == Big1) - goto ovfl; - setWord0(&rv, Big0); - setWord1(&rv, Big1); - goto cont; - } - else - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - } - else { -#ifdef Sudden_Underflow - if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) { - rv0 = rv; - setWord0(&rv, getWord0(rv) + P*Exp_msk1); - adj = aadj1 * ulp(rv); - rv += adj; -#ifdef IBM - if ((getWord0(rv) & Exp_mask) < P*Exp_msk1) -#else - if ((getWord0(rv) & Exp_mask) <= P*Exp_msk1) -#endif - { - if (getWord0(rv0) == Tiny0 - && getWord1(rv0) == Tiny1) - goto undfl; - setWord0(&rv, Tiny0); - setWord1(&rv, Tiny1); - goto cont; - } - else - setWord0(&rv, getWord0(rv) - P*Exp_msk1); - } - else { - adj = aadj1 * ulp(rv); - rv += adj; - } -#else - /* Compute adj so that the IEEE rounding rules will - * correctly round rv + adj in some half-way cases. - * If rv * ulp(rv) is denormalized (i.e., - * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid - * trouble from bits lost to denormalization; - * example: 1.2e-307 . - */ - if (y <= (P-1)*Exp_msk1 && aadj >= 1.) { - aadj1 = int(aadj + 0.5); - if (!dsign) - aadj1 = -aadj1; - } - adj = aadj1 * ulp(rv); - rv += adj; -#endif - } - z = getWord0(rv) & Exp_mask; - if (y == z) { - /* Can we stop now? */ - L = Long(aadj); - aadj -= L; - /* The tolerances below are conservative. */ - if (dsign || getWord1(rv) || getWord0(rv) & Bndry_mask) { - if (aadj < .4999999 || aadj > .5000001) - break; - } - else if (aadj < .4999999/FLT_RADIX) - break; - } - cont: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(delta); - } - retfree: - Bfree(bb); - Bfree(bd); - Bfree(bs); - Bfree(bd0); - Bfree(delta); - ret: + int processed = 0; + bool nonNullOk = false; + int len = static_cast<int>(strlen(s00)); + Q_ASSERT(len >= 0); + double d = asciiToDouble(s00, len, nonNullOk, processed); if (se) - *se = s; - return sign ? -rv : rv; -} - -static int quorem(Bigint *b, Bigint *S) -{ - int n; - Long borrow, y; - ULong carry, q, ys; - ULong *bx, *bxe, *sx, *sxe; -#ifdef Pack_32 - Long z; - ULong si, zs; -#endif - - n = S->wds; -#ifdef BSD_QDTOA_DEBUG - /*debug*/ if (b->wds > n) - /*debug*/ Bug("oversize b in quorem"); -#endif - if (b->wds < n) - return 0; - sx = S->x; - sxe = sx + --n; - bx = b->x; - bxe = bx + n; - q = *bxe / (*sxe + 1); /* ensure q <= true quotient */ -#ifdef BSD_QDTOA_DEBUG - /*debug*/ if (q > 9) - /*debug*/ Bug("oversized quotient in quorem"); -#endif - if (q) { - borrow = 0; - carry = 0; - do { -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) * q + carry; - zs = (si >> 16) * q + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(bx, z, y); -#else - ys = *sx++ * q + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *bx++ = y & 0xffff; -#endif - } - while(sx <= sxe); - if (!*bxe) { - bx = b->x; - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - if (cmp(b, S) >= 0) { - q++; - borrow = 0; - carry = 0; - bx = b->x; - sx = S->x; - do { -#ifdef Pack_32 - si = *sx++; - ys = (si & 0xffff) + carry; - zs = (si >> 16) + (ys >> 16); - carry = zs >> 16; - y = (*bx & 0xffff) - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - z = (*bx >> 16) - (zs & 0xffff) + borrow; - borrow = z >> 16; - Sign_Extend(borrow, z); - Storeinc(bx, z, y); -#else - ys = *sx++ + carry; - carry = ys >> 16; - y = *bx - (ys & 0xffff) + borrow; - borrow = y >> 16; - Sign_Extend(borrow, y); - *bx++ = y & 0xffff; -#endif - } - while(sx <= sxe); - bx = b->x; - bxe = bx + n; - if (!*bxe) { - while(--bxe > bx && !*bxe) - --n; - b->wds = n; - } - } - return q; -} - -/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string. - * - * Inspired by "How to Print Floating-Point Numbers Accurately" by - * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101]. - * - * Modifications: - * 1. Rather than iterating, we use a simple numeric overestimate - * to determine k = floor(log10(d)). We scale relevant - * quantities using O(log2(k)) rather than O(k) multiplications. - * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't - * try to generate digits strictly left to right. Instead, we - * compute with fewer bits and propagate the carry if necessary - * when rounding the final digit up. This is often faster. - * 3. Under the assumption that input will be rounded nearest, - * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22. - * That is, we allow equality in stopping tests when the - * round-nearest rule will give the same floating-point value - * as would satisfaction of the stopping test with strict - * inequality. - * 4. We remove common factors of powers of 2 from relevant - * quantities. - * 5. When converting floating-point integers less than 1e16, - * we use floating-point arithmetic rather than resorting - * to multiple-precision integers. - * 6. When asked to produce fewer than 15 digits, we first try - * to get by with floating-point arithmetic; we resort to - * multiple-precision integer arithmetic only if we cannot - * guarantee that the floating-point calculation has given - * the correctly rounded result. For k requested digits and - * "uniformly" distributed input, the probability is - * something like 10^(k-15) that we must resort to the Long - * calculation. - */ - -#if defined(Q_OS_WIN) && defined (Q_CC_GNU) && !defined(_clear87) // See QTBUG-7576 -extern "C" { -__attribute__ ((dllimport)) unsigned int __cdecl __MINGW_NOTHROW _control87 (unsigned int unNew, unsigned int unMask); -__attribute__ ((dllimport)) unsigned int __cdecl __MINGW_NOTHROW _clearfp (void); /* Clear the FPU status word */ + *se = s00 + processed; + if (ok) + *ok = nonNullOk; + return d; } -# define _clear87 _clearfp -#endif - -/* This actually sometimes returns a pointer to a string literal - cast to a char*. Do NOT try to modify the return value. */ -Q_CORE_EXPORT char *qdtoa ( double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) +QString qdtoa(qreal d, int *decpt, int *sign) { - // Some values of the floating-point control word can cause _qdtoa to crash with an underflow. - // We set a safe value here. -#ifdef Q_OS_WIN - _clear87(); - unsigned int oldbits = _control87(0, 0); -#ifndef MCW_EM -# ifdef _MCW_EM -# define MCW_EM _MCW_EM -# else -# define MCW_EM 0x0008001F -# endif -#endif - _control87(MCW_EM, MCW_EM); -#endif - -#if defined(Q_OS_LINUX) && !defined(__UCLIBC__) - fenv_t envp; - feholdexcept(&envp); -#endif - - char *s = _qdtoa(d, mode, ndigits, decpt, sign, rve, resultp); - -#ifdef Q_OS_WIN - _clear87(); -#ifndef _M_X64 - _control87(oldbits, 0xFFFFF); -#else -# ifndef _MCW_EM // Potentially missing on MinGW -# define _MCW_EM 0x0008001f -# endif -# ifndef _MCW_RC -# define _MCW_RC 0x00000300 -# endif -# ifndef _MCW_DN -# define _MCW_DN 0x03000000 -# endif - _control87(oldbits, _MCW_EM|_MCW_DN|_MCW_RC); -#endif //_M_X64 -#endif //Q_OS_WIN + bool nonNullSign = false; + int nonNullDecpt = 0; + int length = 0; -#if defined(Q_OS_LINUX) && !defined(__UCLIBC__) - fesetenv(&envp); -#endif - - return s; -} + // Some versions of libdouble-conversion like an extra digit, probably for '\0' + char result[QLocaleData::DoubleMaxSignificant + 1]; + doubleToAscii(d, QLocaleData::DFSignificantDigits, QLocale::FloatingPointShortest, result, + QLocaleData::DoubleMaxSignificant + 1, nonNullSign, length, nonNullDecpt); -static char *_qdtoa( NEEDS_VOLATILE double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **resultp) -{ - /* - Arguments ndigits, decpt, sign are similar to those - of ecvt and fcvt; trailing zeros are suppressed from - the returned string. If not null, *rve is set to point - to the end of the return value. If d is +-Infinity or NaN, - then *decpt is set to 9999. - - mode: - 0 ==> shortest string that yields d when read in - and rounded to nearest. - 1 ==> like 0, but with Steele & White stopping rule; - e.g. with IEEE P754 arithmetic , mode 0 gives - 1e23 whereas mode 1 gives 9.999999999999999e22. - 2 ==> max(1,ndigits) significant digits. This gives a - return value similar to that of ecvt, except - that trailing zeros are suppressed. - 3 ==> through ndigits past the decimal point. This - gives a return value similar to that from fcvt, - except that trailing zeros are suppressed, and - ndigits can be negative. - 4-9 should give the same return values as 2-3, i.e., - 4 <= mode <= 9 ==> same return as mode - 2 + (mode & 1). These modes are mainly for - debugging; often they run slower but sometimes - faster than modes 2-3. - 4,5,8,9 ==> left-to-right digit generation. - 6-9 ==> don't try fast floating-point estimate - (if applicable). - - Values of mode other than 0-9 are treated as mode 0. - - Sufficient space is allocated to the return value - to hold the suppressed trailing zeros. - */ - - int bbits, b2, b5, be, dig, i, ieps, ilim0, - j, j1, k, k0, k_check, leftright, m2, m5, s2, s5, - try_quick; - int ilim = 0, ilim1 = 0, spec_case = 0; /* pacify gcc */ - Long L; -#ifndef Sudden_Underflow - int denorm; - ULong x; -#endif - Bigint *b, *b1, *delta, *mhi, *S; - Bigint *mlo = NULL; /* pacify gcc */ - double d2; - double ds, eps; - char *s, *s0; - - if (getWord0(d) & Sign_bit) { - /* set sign for everything, including 0's and NaNs */ - *sign = 1; - setWord0(&d, getWord0(d) & ~Sign_bit); /* clear sign bit */ - } - else - *sign = 0; + if (sign) + *sign = nonNullSign ? 1 : 0; + if (decpt) + *decpt = nonNullDecpt; -#if defined(IEEE_Arith) + defined(VAX) -#ifdef IEEE_Arith - if ((getWord0(d) & Exp_mask) == Exp_mask) -#else - if (getWord0(d) == 0x8000) -#endif - { - /* Infinity or NaN */ - *decpt = 9999; - s = -#ifdef IEEE_Arith - !getWord1(d) && !(getWord0(d) & 0xfffff) ? const_cast<char*>("Infinity") : -#endif - const_cast<char*>("NaN"); - if (rve) - *rve = -#ifdef IEEE_Arith - s[3] ? s + 8 : -#endif - s + 3; - return s; - } -#endif -#ifdef IBM - d += 0; /* normalize */ -#endif - if (d == g_double_zero) - { - *decpt = 1; - s = const_cast<char*>("0"); - if (rve) - *rve = s + 1; - return s; - } - - b = d2b(d, &be, &bbits); - i = (int)(getWord0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)); -#ifndef Sudden_Underflow - if (i != 0) { -#endif - d2 = d; - setWord0(&d2, getWord0(d2) & Frac_mask1); - setWord0(&d2, getWord0(d2) | Exp_11); -#ifdef IBM - if (j = 11 - hi0bits(getWord0(d2) & Frac_mask)) - d2 /= 1 << j; -#endif - - /* log(x) ~=~ log(1.5) + (x-1.5)/1.5 - * log10(x) = log(x) / log(10) - * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10)) - * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2) - * - * This suggests computing an approximation k to log10(d) by - * - * k = (i - Bias)*0.301029995663981 - * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 ); - * - * We want k to be too large rather than too small. - * The error in the first-order Taylor series approximation - * is in our favor, so we just round up the constant enough - * to compensate for any error in the multiplication of - * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077, - * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14, - * adding 1e-13 to the constant term more than suffices. - * Hence we adjust the constant term to 0.1760912590558. - * (We could get a more accurate k by invoking log10, - * but this is probably not worthwhile.) - */ - - i -= Bias; -#ifdef IBM - i <<= 2; - i += j; -#endif -#ifndef Sudden_Underflow - denorm = 0; - } - else { - /* d is denormalized */ - - i = bbits + be + (Bias + (P-1) - 1); - x = i > 32 ? getWord0(d) << (64 - i) | getWord1(d) >> (i - 32) - : getWord1(d) << (32 - i); - d2 = x; - setWord0(&d2, getWord0(d2) - 31*Exp_msk1); /* adjust exponent */ - i -= (Bias + (P-1) - 1) + 1; - denorm = 1; - } -#endif - ds = (d2-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981; - k = int(ds); - if (ds < 0. && ds != k) - k--; /* want k = floor(ds) */ - k_check = 1; - if (k >= 0 && k <= Ten_pmax) { - if (d < tens[k]) - k--; - k_check = 0; - } - j = bbits - i - 1; - if (j >= 0) { - b2 = 0; - s2 = j; - } - else { - b2 = -j; - s2 = 0; - } - if (k >= 0) { - b5 = 0; - s5 = k; - s2 += k; - } - else { - b2 -= k; - b5 = -k; - s5 = 0; - } - if (mode < 0 || mode > 9) - mode = 0; - try_quick = 1; - if (mode > 5) { - mode -= 4; - try_quick = 0; - } - leftright = 1; - switch(mode) { - case 0: - case 1: - ilim = ilim1 = -1; - i = 18; - ndigits = 0; - break; - case 2: - leftright = 0; - /* no break */ - case 4: - if (ndigits <= 0) - ndigits = 1; - ilim = ilim1 = i = ndigits; - break; - case 3: - leftright = 0; - /* no break */ - case 5: - i = ndigits + k + 1; - ilim = i; - ilim1 = i - 1; - if (i <= 0) - i = 1; - } - QT_TRY { - *resultp = static_cast<char *>(malloc(i + 1)); - Q_CHECK_PTR(*resultp); - } QT_CATCH(...) { - Bfree(b); - QT_RETHROW; - } - s = s0 = *resultp; - - if (ilim >= 0 && ilim <= Quick_max && try_quick) { - - /* Try to get by with floating-point arithmetic. */ - - i = 0; - d2 = d; - k0 = k; - ilim0 = ilim; - ieps = 2; /* conservative */ - if (k > 0) { - ds = tens[k&0xf]; - j = k >> 4; - if (j & Bletch) { - /* prevent overflows */ - j &= Bletch - 1; - d /= bigtens[n_bigtens-1]; - ieps++; - } - for(; j; j >>= 1, i++) - if (j & 1) { - ieps++; - ds *= bigtens[i]; - } - d /= ds; - } - else if ((j1 = -k) != 0) { - d *= tens[j1 & 0xf]; - for(j = j1 >> 4; j; j >>= 1, i++) - if (j & 1) { - ieps++; - d *= bigtens[i]; - } - } - if (k_check && d < 1. && ilim > 0) { - if (ilim1 <= 0) - goto fast_failed; - ilim = ilim1; - k--; - d *= 10.; - ieps++; - } - eps = ieps*d + 7.; - setWord0(&eps, getWord0(eps) - (P-1)*Exp_msk1); - if (ilim == 0) { - S = mhi = 0; - d -= 5.; - if (d > eps) - goto one_digit; - if (d < -eps) - goto no_digits; - goto fast_failed; - } -#ifndef No_leftright - if (leftright) { - /* Use Steele & White method of only - * generating digits needed. - */ - eps = 0.5/tens[ilim-1] - eps; - for(i = 0;;) { - L = Long(d); - d -= L; - *s++ = '0' + int(L); - if (d < eps) - goto ret1; - if (1. - d < eps) - goto bump_up; - if (++i >= ilim) - break; - eps *= 10.; - d *= 10.; - } - } - else { -#endif - /* Generate ilim digits, then fix them up. */ - eps *= tens[ilim-1]; - for(i = 1;; i++, d *= 10.) { - L = Long(d); - d -= L; - *s++ = '0' + int(L); - if (i == ilim) { - if (d > 0.5 + eps) - goto bump_up; - else if (d < 0.5 - eps) { - while(*--s == '0') {} - s++; - goto ret1; - } - break; - } - } -#ifndef No_leftright - } -#endif - fast_failed: - s = s0; - d = d2; - k = k0; - ilim = ilim0; - } - - /* Do we have a "small" integer? */ - - if (be >= 0 && k <= Int_max) { - /* Yes. */ - ds = tens[k]; - if (ndigits < 0 && ilim <= 0) { - S = mhi = 0; - if (ilim < 0 || d <= 5*ds) - goto no_digits; - goto one_digit; - } - for(i = 1;; i++) { - L = Long(d / ds); - d -= L*ds; -#ifdef Check_FLT_ROUNDS - /* If FLT_ROUNDS == 2, L will usually be high by 1 */ - if (d < 0) { - L--; - d += ds; - } -#endif - *s++ = '0' + int(L); - if (i == ilim) { - d += d; - if (d > ds || (d == ds && L & 1)) { - bump_up: - while(*--s == '9') - if (s == s0) { - k++; - *s = '0'; - break; - } - ++*s++; - } - break; - } - if ((d *= 10.) == g_double_zero) - break; - } - goto ret1; - } - - m2 = b2; - m5 = b5; - mhi = mlo = 0; - if (leftright) { - if (mode < 2) { - i = -#ifndef Sudden_Underflow - denorm ? be + (Bias + (P-1) - 1 + 1) : -#endif -#ifdef IBM - 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3); -#else - 1 + P - bbits; -#endif - } - else { - j = ilim - 1; - if (m5 >= j) - m5 -= j; - else { - s5 += j -= m5; - b5 += j; - m5 = 0; - } - if ((i = ilim) < 0) { - m2 -= i; - i = 0; - } - } - b2 += i; - s2 += i; - mhi = i2b(1); - } - if (m2 > 0 && s2 > 0) { - i = m2 < s2 ? m2 : s2; - b2 -= i; - m2 -= i; - s2 -= i; - } - if (b5 > 0) { - if (leftright) { - if (m5 > 0) { - mhi = pow5mult(mhi, m5); - b1 = mult(mhi, b); - Bfree(b); - b = b1; - } - if ((j = b5 - m5) != 0) - b = pow5mult(b, j); - } - else - b = pow5mult(b, b5); - } - S = i2b(1); - if (s5 > 0) - S = pow5mult(S, s5); - - /* Check for special case that d is a normalized power of 2. */ - - if (mode < 2) { - if (!getWord1(d) && !(getWord0(d) & Bndry_mask) -#ifndef Sudden_Underflow - && getWord0(d) & Exp_mask -#endif - ) { - /* The special case */ - b2 += Log2P; - s2 += Log2P; - spec_case = 1; - } - else - spec_case = 0; - } - - /* Arrange for convenient computation of quotients: - * shift left if necessary so divisor has 4 leading 0 bits. - * - * Perhaps we should just compute leading 28 bits of S once - * and for all and pass them and a shift to quorem, so it - * can do shifts and ors to compute the numerator for q. - */ -#ifdef Pack_32 - if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0) - i = 32 - i; -#else - if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf) - i = 16 - i; -#endif - if (i > 4) { - i -= 4; - b2 += i; - m2 += i; - s2 += i; - } - else if (i < 4) { - i += 28; - b2 += i; - m2 += i; - s2 += i; - } - if (b2 > 0) - b = lshift(b, b2); - if (s2 > 0) - S = lshift(S, s2); - if (k_check) { - if (cmp(b,S) < 0) { - k--; - b = multadd(b, 10, 0); /* we botched the k estimate */ - if (leftright) - mhi = multadd(mhi, 10, 0); - ilim = ilim1; - } - } - if (ilim <= 0 && mode > 2) { - if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) { - /* no digits, fcvt style */ - no_digits: - k = -1 - ndigits; - goto ret; - } - one_digit: - *s++ = '1'; - k++; - goto ret; - } - if (leftright) { - if (m2 > 0) - mhi = lshift(mhi, m2); - - /* Compute mlo -- check for special case - * that d is a normalized power of 2. - */ - - mlo = mhi; - if (spec_case) { - mhi = Balloc(mhi->k); - Bcopy(mhi, mlo); - mhi = lshift(mhi, Log2P); - } - - for(i = 1;;i++) { - dig = quorem(b,S) + '0'; - /* Do we yet have the shortest decimal string - * that will round to d? - */ - j = cmp(b, mlo); - delta = diff(S, mhi); - j1 = delta->sign ? 1 : cmp(b, delta); - Bfree(delta); -#ifndef ROUND_BIASED - if (j1 == 0 && !mode && !(getWord1(d) & 1)) { - if (dig == '9') - goto round_9_up; - if (j > 0) - dig++; - *s++ = dig; - goto ret; - } -#endif - if (j < 0 || (j == 0 && !mode -#ifndef ROUND_BIASED - && !(getWord1(d) & 1) -#endif - )) { - if (j1 > 0) { - b = lshift(b, 1); - j1 = cmp(b, S); - if ((j1 > 0 || (j1 == 0 && dig & 1)) - && dig++ == '9') - goto round_9_up; - } - *s++ = dig; - goto ret; - } - if (j1 > 0) { - if (dig == '9') { /* possible if i == 1 */ - round_9_up: - *s++ = '9'; - goto roundoff; - } - *s++ = dig + 1; - goto ret; - } - *s++ = dig; - if (i == ilim) - break; - b = multadd(b, 10, 0); - if (mlo == mhi) - mlo = mhi = multadd(mhi, 10, 0); - else { - mlo = multadd(mlo, 10, 0); - mhi = multadd(mhi, 10, 0); - } - } - } - else - for(i = 1;; i++) { - *s++ = dig = quorem(b,S) + '0'; - if (i >= ilim) - break; - b = multadd(b, 10, 0); - } - - /* Round off last digit */ - - b = lshift(b, 1); - j = cmp(b, S); - if (j > 0 || (j == 0 && dig & 1)) { - roundoff: - while(*--s == '9') - if (s == s0) { - k++; - *s++ = '1'; - goto ret; - } - ++*s++; - } - else { - while(*--s == '0') {} - s++; - } - ret: - Bfree(S); - if (mhi) { - if (mlo && mlo != mhi) - Bfree(mlo); - Bfree(mhi); - } - ret1: - Bfree(b); - if (s == s0) { /* don't return empty string */ - *s++ = '0'; - k = 0; - } - *s = 0; - *decpt = k + 1; - if (rve) - *rve = s; - return s0; + return QLatin1String(result, length); } QT_END_NAMESPACE diff --git a/src/corelib/tools/qlocale_tools_p.h b/src/corelib/tools/qlocale_tools_p.h index 03f35209b4..3a8036c642 100644 --- a/src/corelib/tools/qlocale_tools_p.h +++ b/src/corelib/tools/qlocale_tools_p.h @@ -66,8 +66,13 @@ QT_BEGIN_NAMESPACE +double asciiToDouble(const char *num, int numLen, bool &ok, int &processed); +void doubleToAscii(double d, QLocaleData::DoubleForm form, int precision, char *buf, int bufSize, + bool &sign, int &length, int &decpt); + QString qulltoa(qulonglong l, int base, const QChar _zero); QString qlltoa(qlonglong l, int base, const QChar zero); +Q_CORE_EXPORT QString qdtoa(qreal d, int *decpt, int *sign); enum PrecisionMode { PMDecimalDigits = 0x01, @@ -76,15 +81,16 @@ enum PrecisionMode { }; QString &decimalForm(QChar zero, QChar decimal, QChar group, - QString &digits, int decpt, uint precision, + QString &digits, int decpt, int precision, PrecisionMode pm, bool always_show_decpt, bool thousands_group); QString &exponentForm(QChar zero, QChar decimal, QChar exponential, QChar group, QChar plus, QChar minus, - QString &digits, int decpt, uint precision, + QString &digits, int decpt, int precision, PrecisionMode pm, - bool always_show_decpt); + bool always_show_decpt, + bool leading_zero_in_exponent); inline bool isZero(double d) { @@ -96,8 +102,6 @@ inline bool isZero(double d) } } -Q_CORE_EXPORT char *qdtoa(double d, int mode, int ndigits, int *decpt, - int *sign, char **rve, char **digits_str); Q_CORE_EXPORT double qstrtod(const char *s00, char const **se, bool *ok); qlonglong qstrtoll(const char *nptr, const char **endptr, int base, bool *ok); qulonglong qstrtoull(const char *nptr, const char **endptr, int base, bool *ok); diff --git a/src/corelib/tools/qpair.h b/src/corelib/tools/qpair.h index d637067fa8..b21750f76c 100644 --- a/src/corelib/tools/qpair.h +++ b/src/corelib/tools/qpair.h @@ -46,30 +46,36 @@ struct QPair typedef T2 second_type; Q_DECL_CONSTEXPR QPair() - Q_DECL_NOEXCEPT_EXPR(noexcept(T1()) && noexcept(T2())) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_default_constructible<T1>::value && + std::is_nothrow_default_constructible<T2>::value)) : first(), second() {} Q_DECL_CONSTEXPR QPair(const T1 &t1, const T2 &t2) - Q_DECL_NOEXCEPT_EXPR(noexcept(T1(t1)) && noexcept(T2(t2))) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_copy_constructible<T1>::value && + std::is_nothrow_copy_constructible<T2>::value)) : first(t1), second(t2) {} // compiler-generated copy/move ctor/assignment operators are fine! template <typename TT1, typename TT2> Q_DECL_CONSTEXPR QPair(const QPair<TT1, TT2> &p) - Q_DECL_NOEXCEPT_EXPR(noexcept(T1(p.first)) && noexcept(T2(p.second))) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_constructible<T1, TT1&>::value && + std::is_nothrow_constructible<T2, TT2&>::value)) : first(p.first), second(p.second) {} template <typename TT1, typename TT2> Q_DECL_RELAXED_CONSTEXPR QPair &operator=(const QPair<TT1, TT2> &p) - Q_DECL_NOEXCEPT_EXPR(noexcept(std::declval<T1&>() = p.first) && noexcept(std::declval<T2&>() = p.second)) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_assignable<T1, TT1&>::value && + std::is_nothrow_assignable<T2, TT2&>::value)) { first = p.first; second = p.second; return *this; } #ifdef Q_COMPILER_RVALUE_REFS template <typename TT1, typename TT2> Q_DECL_CONSTEXPR QPair(QPair<TT1, TT2> &&p) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_constructible<T1, TT1>::value && + std::is_nothrow_constructible<T2, TT2>::value)) // can't use std::move here as it's not constexpr in C++11: - Q_DECL_NOEXCEPT_EXPR(noexcept(T1(static_cast<TT1 &&>(p.first))) && noexcept(T2(static_cast<TT2 &&>(p.second)))) : first(static_cast<TT1 &&>(p.first)), second(static_cast<TT2 &&>(p.second)) {} template <typename TT1, typename TT2> Q_DECL_RELAXED_CONSTEXPR QPair &operator=(QPair<TT1, TT2> &&p) - Q_DECL_NOEXCEPT_EXPR(noexcept(std::declval<T1&>() = std::move(p.first)) && noexcept(std::declval<T2&>() = std::move(p.second))) + Q_DECL_NOEXCEPT_EXPR((std::is_nothrow_assignable<T1, TT1>::value && + std::is_nothrow_assignable<T2, TT2>::value)) { first = std::move(p.first); second = std::move(p.second); return *this; } #endif diff --git a/src/corelib/tools/qregexp.h b/src/corelib/tools/qregexp.h index f384e6c51f..9c68c194e0 100644 --- a/src/corelib/tools/qregexp.h +++ b/src/corelib/tools/qregexp.h @@ -68,10 +68,9 @@ public: ~QRegExp(); QRegExp &operator=(const QRegExp &rx); #ifdef Q_COMPILER_RVALUE_REFS - inline QRegExp &operator=(QRegExp &&other) - { qSwap(priv,other.priv); return *this; } + QRegExp &operator=(QRegExp &&other) Q_DECL_NOTHROW { swap(other); return *this; } #endif - inline void swap(QRegExp &other) { qSwap(priv, other.priv); } + void swap(QRegExp &other) Q_DECL_NOTHROW { qSwap(priv, other.priv); } bool operator==(const QRegExp &rx) const; inline bool operator!=(const QRegExp &rx) const { return !operator==(rx); } diff --git a/src/corelib/tools/qringbuffer.cpp b/src/corelib/tools/qringbuffer.cpp index 85cfdaf129..e9b655c01e 100644 --- a/src/corelib/tools/qringbuffer.cpp +++ b/src/corelib/tools/qringbuffer.cpp @@ -65,6 +65,8 @@ const char *QRingBuffer::readPointerAtPosition(qint64 pos, qint64 &length) const void QRingBuffer::free(qint64 bytes) { + Q_ASSERT(bytes <= bufferSize); + while (bytes > 0) { const qint64 blockSize = buffers.first().size() - head; @@ -100,20 +102,25 @@ char *QRingBuffer::reserve(qint64 bytes) if (bytes <= 0 || bytes >= MaxByteArraySize) return 0; - const qint64 newSize = bytes + tail; - // if need buffer reallocation - if (newSize > buffers.last().size()) { - if (newSize > buffers.last().capacity() && (tail >= basicBlockSize - || newSize >= MaxByteArraySize)) { - // shrink this buffer to its current size - buffers.last().resize(tail); - - // create a new QByteArray - buffers.append(QByteArray()); - ++tailBuffer; - tail = 0; + if (buffers.isEmpty()) { + buffers.append(QByteArray()); + buffers.first().resize(qMax(basicBlockSize, int(bytes))); + } else { + const qint64 newSize = bytes + tail; + // if need buffer reallocation + if (newSize > buffers.last().size()) { + if (newSize > buffers.last().capacity() && (tail >= basicBlockSize + || newSize >= MaxByteArraySize)) { + // shrink this buffer to its current size + buffers.last().resize(tail); + + // create a new QByteArray + buffers.append(QByteArray()); + ++tailBuffer; + tail = 0; + } + buffers.last().resize(qMax(basicBlockSize, tail + int(bytes))); } - buffers.last().resize(qMax(basicBlockSize, tail + int(bytes))); } char *writePtr = buffers.last().data() + tail; @@ -134,9 +141,13 @@ char *QRingBuffer::reserveFront(qint64 bytes) return 0; if (head < bytes) { - buffers.first().remove(0, head); - if (tailBuffer == 0) - tail -= head; + if (buffers.isEmpty()) { + buffers.append(QByteArray()); + } else { + buffers.first().remove(0, head); + if (tailBuffer == 0) + tail -= head; + } head = qMax(basicBlockSize, int(bytes)); if (bufferSize == 0) { @@ -155,6 +166,8 @@ char *QRingBuffer::reserveFront(qint64 bytes) void QRingBuffer::chop(qint64 bytes) { + Q_ASSERT(bytes <= bufferSize); + while (bytes > 0) { if (tailBuffer == 0 || tail > bytes) { // keep a single block around if it does not exceed @@ -185,6 +198,9 @@ void QRingBuffer::chop(qint64 bytes) void QRingBuffer::clear() { + if (buffers.isEmpty()) + return; + buffers.erase(buffers.begin() + 1, buffers.end()); buffers.first().clear(); @@ -193,20 +209,32 @@ void QRingBuffer::clear() bufferSize = 0; } -qint64 QRingBuffer::indexOf(char c, qint64 maxLength) const +qint64 QRingBuffer::indexOf(char c, qint64 maxLength, qint64 pos) const { - qint64 index = 0; - qint64 j = head; - for (int i = 0; index < maxLength && i < buffers.size(); ++i) { - const char *ptr = buffers[i].constData() + j; - j = qMin(index + (i == tailBuffer ? tail : buffers[i].size()) - j, maxLength); - - while (index < j) { - if (*ptr++ == c) - return index; - ++index; + if (maxLength <= 0 || pos < 0) + return -1; + + qint64 index = -(pos + head); + for (int i = 0; i < buffers.size(); ++i) { + const qint64 nextBlockIndex = qMin(index + (i == tailBuffer ? tail : buffers[i].size()), + maxLength); + + if (nextBlockIndex > 0) { + const char *ptr = buffers[i].constData(); + if (index < 0) { + ptr -= index; + index = 0; + } + + const char *findPtr = reinterpret_cast<const char *>(memchr(ptr, c, + nextBlockIndex - index)); + if (findPtr) + return qint64(findPtr - ptr) + index + pos; + + if (nextBlockIndex == maxLength) + return -1; } - j = 0; + index = nextBlockIndex; } return -1; } @@ -288,7 +316,10 @@ qint64 QRingBuffer::peek(char *data, qint64 maxLength, qint64 pos) const void QRingBuffer::append(const QByteArray &qba) { if (tail == 0) { - buffers.last() = qba; + if (buffers.isEmpty()) + buffers.append(qba); + else + buffers.last() = qba; } else { buffers.last().resize(tail); buffers.append(qba); diff --git a/src/corelib/tools/qringbuffer_p.h b/src/corelib/tools/qringbuffer_p.h index 68509a6a80..96c4f9acb6 100644 --- a/src/corelib/tools/qringbuffer_p.h +++ b/src/corelib/tools/qringbuffer_p.h @@ -54,9 +54,7 @@ class QRingBuffer { public: explicit inline QRingBuffer(int growth = 4096) : - head(0), tail(0), tailBuffer(0), basicBlockSize(growth), bufferSize(0) { - buffers.append(QByteArray()); - } + head(0), tail(0), tailBuffer(0), basicBlockSize(growth), bufferSize(0) { } inline qint64 nextDataBlockSize() const { return (tailBuffer == 0 ? tail : buffers.first().size()) - head; @@ -114,14 +112,17 @@ public: Q_CORE_EXPORT void clear(); inline qint64 indexOf(char c) const { return indexOf(c, size()); } - Q_CORE_EXPORT qint64 indexOf(char c, qint64 maxLength) const; + Q_CORE_EXPORT qint64 indexOf(char c, qint64 maxLength, qint64 pos = 0) const; Q_CORE_EXPORT qint64 read(char *data, qint64 maxLength); Q_CORE_EXPORT QByteArray read(); Q_CORE_EXPORT qint64 peek(char *data, qint64 maxLength, qint64 pos = 0) const; Q_CORE_EXPORT void append(const QByteArray &qba); inline qint64 skip(qint64 length) { - return read(0, length); + qint64 bytesToSkip = qMin(length, bufferSize); + + free(bytesToSkip); + return bytesToSkip; } Q_CORE_EXPORT qint64 readLine(char *data, qint64 maxLength); diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp index 86f4c6a268..b5e27cc720 100644 --- a/src/corelib/tools/qsharedpointer.cpp +++ b/src/corelib/tools/qsharedpointer.cpp @@ -1292,6 +1292,17 @@ compile. Use qSharedPointerConstCast to cast away the constness. */ +/*! + \fn QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr) + \relates QSharedPointer + \since 5.7 + + Writes the pointer tracked by \a ptr into the debug object \a debug for + debugging purposes. + + \sa {Debugging Techniques} +*/ + #include <qset.h> #include <qmutex.h> @@ -1497,7 +1508,7 @@ void QtSharedPointer::internalSafetyCheckAdd(const void *d_ptr, const volatile v //qDebug("Adding d=%p value=%p", d_ptr, ptr); const void *other_d_ptr = kp->dataPointers.value(ptr, 0); - if (other_d_ptr) { + if (Q_UNLIKELY(other_d_ptr)) { # ifdef BACKTRACE_SUPPORTED printBacktrace(knownPointers()->dPointers.value(other_d_ptr).backtrace); # endif @@ -1528,7 +1539,7 @@ void QtSharedPointer::internalSafetyCheckRemove(const void *d_ptr) QMutexLocker lock(&kp->mutex); QHash<const void *, Data>::iterator it = kp->dPointers.find(d_ptr); - if (it == kp->dPointers.end()) { + if (Q_UNLIKELY(it == kp->dPointers.end())) { qFatal("QSharedPointer: internal self-check inconsistency: pointer %p was not tracked. " "To use QT_SHAREDPOINTER_TRACK_POINTERS, you have to enable it throughout " "in your code.", d_ptr); @@ -1555,10 +1566,10 @@ void QtSharedPointer::internalSafetyCheckCleanCheck() KnownPointers *const kp = knownPointers(); Q_ASSERT_X(kp, "internalSafetyCheckSelfCheck()", "Called after global statics deletion!"); - if (kp->dPointers.size() != kp->dataPointers.size()) + if (Q_UNLIKELY(kp->dPointers.size() != kp->dataPointers.size())) qFatal("Internal consistency error: the number of pointers is not equal!"); - if (!kp->dPointers.isEmpty()) + if (Q_UNLIKELY(!kp->dPointers.isEmpty())) qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size()); # endif } diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h index 279ec36a28..56e13d500f 100644 --- a/src/corelib/tools/qsharedpointer.h +++ b/src/corelib/tools/qsharedpointer.h @@ -153,6 +153,8 @@ template <class X, class T> QSharedPointer<X> qSharedPointerObjectCast(const QWe template <class X, class T> QWeakPointer<X> qWeakPointerCast(const QWeakPointer<T> &src); +template <class T> QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr); + QT_END_NAMESPACE #endif // Q_QDOC diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h index 1323dd6b1c..ace6c5d093 100644 --- a/src/corelib/tools/qsharedpointer_impl.h +++ b/src/corelib/tools/qsharedpointer_impl.h @@ -55,6 +55,7 @@ QT_END_NAMESPACE #include <new> #include <QtCore/qatomic.h> #include <QtCore/qobject.h> // for qobject_cast +#include <QtCore/qdebug.h> #if QT_DEPRECATED_SINCE(5, 5) #include <QtCore/qhash.h> #endif @@ -305,7 +306,7 @@ public: inline T &operator*() const { return *data(); } inline T *operator->() const { return data(); } - QSharedPointer() : value(Q_NULLPTR), d(Q_NULLPTR) { } + QSharedPointer() Q_DECL_NOTHROW : value(Q_NULLPTR), d(Q_NULLPTR) {} ~QSharedPointer() { deref(); } inline explicit QSharedPointer(T *ptr) : value(ptr) // noexcept @@ -315,22 +316,22 @@ public: inline QSharedPointer(T *ptr, Deleter deleter) : value(ptr) // throws { internalConstruct(ptr, deleter); } - inline QSharedPointer(const QSharedPointer &other) : value(other.value), d(other.d) + QSharedPointer(const QSharedPointer &other) Q_DECL_NOTHROW : value(other.value), d(other.d) { if (d) ref(); } - inline QSharedPointer &operator=(const QSharedPointer &other) + QSharedPointer &operator=(const QSharedPointer &other) Q_DECL_NOTHROW { QSharedPointer copy(other); swap(copy); return *this; } #ifdef Q_COMPILER_RVALUE_REFS - inline QSharedPointer(QSharedPointer &&other) + QSharedPointer(QSharedPointer &&other) Q_DECL_NOTHROW : value(other.value), d(other.d) { other.d = Q_NULLPTR; other.value = Q_NULLPTR; } - inline QSharedPointer &operator=(QSharedPointer &&other) + QSharedPointer &operator=(QSharedPointer &&other) Q_DECL_NOTHROW { QSharedPointer moved(std::move(other)); swap(moved); @@ -596,7 +597,7 @@ public: inline bool operator !() const { return isNull(); } inline T *data() const { return d == Q_NULLPTR || d->strongref.load() == 0 ? Q_NULLPTR : value; } - inline QWeakPointer() : d(Q_NULLPTR), value(Q_NULLPTR) { } + inline QWeakPointer() Q_DECL_NOTHROW : d(Q_NULLPTR), value(Q_NULLPTR) { } inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; } #ifndef QT_NO_QOBJECT @@ -614,15 +615,26 @@ public: { return *this = QWeakPointer(ptr); } #endif - inline QWeakPointer(const QWeakPointer &o) : d(o.d), value(o.value) + QWeakPointer(const QWeakPointer &other) Q_DECL_NOTHROW : d(other.d), value(other.value) { if (d) d->weakref.ref(); } - inline QWeakPointer &operator=(const QWeakPointer &o) +#ifdef Q_COMPILER_RVALUE_REFS + QWeakPointer(QWeakPointer &&other) Q_DECL_NOTHROW + : d(other.d), value(other.value) { - internalSet(o.d, o.value); + other.d = Q_NULLPTR; + other.value = Q_NULLPTR; + } + QWeakPointer &operator=(QWeakPointer &&other) Q_DECL_NOTHROW + { QWeakPointer moved(std::move(other)); swap(moved); return *this; } +#endif + QWeakPointer &operator=(const QWeakPointer &other) Q_DECL_NOTHROW + { + QWeakPointer copy(other); + swap(copy); return *this; } - inline void swap(QWeakPointer &other) + void swap(QWeakPointer &other) Q_DECL_NOTHROW { qSwap(this->d, other.d); qSwap(this->value, other.value); @@ -858,6 +870,16 @@ inline void qSwap(QSharedPointer<T> &p1, QSharedPointer<T> &p2) p1.swap(p2); } +#ifndef QT_NO_DEBUG_STREAM +template <class T> +Q_INLINE_TEMPLATE QDebug operator<<(QDebug debug, const QSharedPointer<T> &ptr) +{ + QDebugStateSaver saver(debug); + debug.nospace() << "QSharedPointer(" << ptr.data() << ")"; + return debug; +} +#endif + QT_END_NAMESPACE namespace std { template <class T> diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp index 3e4fdfaaf1..171e87df05 100644 --- a/src/corelib/tools/qsimd.cpp +++ b/src/corelib/tools/qsimd.cpp @@ -68,6 +68,8 @@ // copied from <linux/auxvec.h> #define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ +#elif defined(Q_CC_GHS) +#include <INTEGRITY_types.h> #endif QT_BEGIN_NAMESPACE @@ -179,6 +181,10 @@ static int maxBasicCpuidSupported() int info[4]; __cpuid(info, 0); return info[0]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUID(0, info); + return info[0]; #else return 0; #endif @@ -198,6 +204,11 @@ static void cpuidFeatures01(uint &ecx, uint &edx) __cpuid(info, 1); ecx = info[2]; edx = info[3]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUID(1, info); + ecx = info[2]; + edx = info[3]; #endif } @@ -223,6 +234,11 @@ static void cpuidFeatures07_00(uint &ebx, uint &ecx) __cpuidex(info, 7, 0); ebx = info[1]; ecx = info[2]; +#elif defined(Q_CC_GHS) + unsigned int info[4]; + __CPUIDEX(7, 0, info); + ebx = info[1]; + ecx = info[2]; #endif } @@ -232,7 +248,7 @@ inline quint64 _xgetbv(__int64) { return 0; } #endif static void xgetbv(uint in, uint &eax, uint &edx) { -#if defined(Q_CC_GNU) +#if defined(Q_CC_GNU) || defined(Q_CC_GHS) asm (".byte 0x0F, 0x01, 0xD0" // xgetbv instruction : "=a" (eax), "=d" (edx) : "c" (in)); @@ -638,6 +654,15 @@ int ffsll(quint64 i) #endif #elif defined(Q_OS_ANDROID) || defined(Q_OS_QNX) || defined(Q_OS_OSX) # define ffsll __builtin_ffsll +#elif defined(Q_OS_INTEGRITY) +int ffsll(quint64 i) +{ + unsigned long result; + result = __CLZ32(i); + if (!result) + result = 32 + __CLZ32(i >> 32); + return result; +} #endif #ifdef Q_ATOMIC_INT64_IS_SUPPORTED @@ -685,7 +710,7 @@ void qDetectCpuFeatures() #else bool runningOnValgrind = false; #endif - if (!runningOnValgrind && (minFeature != 0 && (f & minFeature) != minFeature)) { + if (Q_UNLIKELY(!runningOnValgrind && minFeature != 0 && (f & minFeature) != minFeature)) { quint64 missing = minFeature & ~f; fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n "); for (int i = 0; i < features_count; ++i) { diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h index 12a329f36c..dedee06e38 100644 --- a/src/corelib/tools/qsimd_p.h +++ b/src/corelib/tools/qsimd_p.h @@ -73,6 +73,7 @@ * SSE4_2 | x86 | I & C | I & C | I only | * AVX | x86 | I & C | I & C | I & C | * AVX2 | x86 | I & C | I & C | I only | + * AVX512xx | x86 | I & C | I & C | I only | * I = intrinsics; C = code generation * * Code can use the following constructs to determine compiler support & status: @@ -430,7 +431,23 @@ static inline quint64 qCpuFeatures() #define qCpuHasFeature(feature) ((qCompilerCpuFeatures & (Q_UINT64_C(1) << CpuFeature ## feature)) \ || (qCpuFeatures() & (Q_UINT64_C(1) << CpuFeature ## feature))) -#ifdef Q_PROCESSOR_X86 +#if QT_HAS_BUILTIN(__builtin_clz) && QT_HAS_BUILTIN(__builtin_ctz) && defined(Q_CC_CLANG) && !defined(Q_CC_INTEL) +static Q_ALWAYS_INLINE unsigned _bit_scan_reverse(unsigned val) +{ + Q_ASSERT(val != 0); // if val==0, the result is undefined. + unsigned result = static_cast<unsigned>(__builtin_clz(val)); // Count Leading Zeros + // Now Invert the result: clz will count *down* from the msb to the lsb, so the msb index is 31 + // and the lsb inde is 0. The result for _bit_scan_reverse is expected to be the index when + // counting up: msb index is 0 (because it starts there), and the lsb index is 31. + result ^= sizeof(unsigned) * 8 - 1; + return result; +} +static Q_ALWAYS_INLINE unsigned _bit_scan_forward(unsigned val) +{ + Q_ASSERT(val != 0); // if val==0, the result is undefined. + return static_cast<unsigned>(__builtin_ctz(val)); // Count Trailing Zeros +} +#elif defined(Q_PROCESSOR_X86) // Bit scan functions for x86 # if defined(Q_CC_MSVC) && !defined(Q_OS_WINCE) // MSVC calls it _BitScanReverse and returns the carry flag, which we don't need diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index d1b5327f5c..1cb5e4ff06 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -40,6 +40,7 @@ #include <qtextcodec.h> #endif #include <private/qutfcodec_p.h> +#include <private/qlocale_tools_p.h> #include "qsimd_p.h" #include <qnumeric.h> #include <qdatastream.h> @@ -5866,6 +5867,46 @@ QString &QString::vsprintf(const char *cformat, va_list ap) return *this = vasprintf(cformat, ap); } +static void append_utf8(QString &qs, const char *cs, int len) +{ + const int oldSize = qs.size(); + qs.resize(oldSize + len); + const QChar *newEnd = QUtf8::convertToUnicode(qs.data() + oldSize, cs, len); + qs.resize(newEnd - qs.constData()); +} + +static uint parse_flag_characters(const char * &c) Q_DECL_NOTHROW +{ + uint flags = QLocaleData::ZeroPadExponent; + while (true) { + switch (*c) { + case '#': flags |= QLocaleData::Alternate; break; + case '0': flags |= QLocaleData::ZeroPadded; break; + case '-': flags |= QLocaleData::LeftAdjusted; break; + case ' ': flags |= QLocaleData::BlankBeforePositive; break; + case '+': flags |= QLocaleData::AlwaysShowSign; break; + case '\'': flags |= QLocaleData::ThousandsGroup; break; + default: return flags; + } + ++c; + } +} + +static int parse_field_width(const char * &c) +{ + Q_ASSERT(qIsDigit(*c)); + + // can't be negative - started with a digit + // contains at least one digit + const char *endp; + bool ok; + const qulonglong result = qstrtoull(c, &endp, 10, &ok); + c = endp; + while (qIsDigit(*c)) // preserve Qt 5.5 behavior of consuming all digits, no matter how many + ++c; + return ok && result < qulonglong(std::numeric_limits<int>::max()) ? int(result) : 0; +} + /*! \fn QString::vasprintf(const char *cformat, va_list ap) \since 5.5 @@ -5896,7 +5937,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) const char *cb = c; while (*c != '\0' && *c != '%') c++; - result.append(QString::fromUtf8(cb, (int)(c - cb))); + append_utf8(result, cb, int(c - cb)); if (*c == '\0') break; @@ -5915,23 +5956,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) continue; } - // Parse flag characters - uint flags = 0; - bool no_more_flags = false; - do { - switch (*c) { - case '#': flags |= QLocaleData::Alternate; break; - case '0': flags |= QLocaleData::ZeroPadded; break; - case '-': flags |= QLocaleData::LeftAdjusted; break; - case ' ': flags |= QLocaleData::BlankBeforePositive; break; - case '+': flags |= QLocaleData::AlwaysShowSign; break; - case '\'': flags |= QLocaleData::ThousandsGroup; break; - default: no_more_flags = true; break; - } - - if (!no_more_flags) - ++c; - } while (!no_more_flags); + uint flags = parse_flag_characters(c); if (*c == '\0') { result.append(QLatin1String(escape_start)); // incomplete escape, treat as non-escape text @@ -5941,15 +5966,8 @@ QString QString::vasprintf(const char *cformat, va_list ap) // Parse field width int width = -1; // -1 means unspecified if (qIsDigit(*c)) { - QString width_str; - while (*c != '\0' && qIsDigit(*c)) - width_str.append(QLatin1Char(*c++)); - - // can't be negative - started with a digit - // contains at least one digit - width = width_str.toInt(); - } - else if (*c == '*') { + width = parse_field_width(c); + } else if (*c == '*') { // can't parse this in another function, not portably, at least width = va_arg(ap, int); if (width < 0) width = -1; // treat all negative numbers as unspecified @@ -5966,15 +5984,8 @@ QString QString::vasprintf(const char *cformat, va_list ap) if (*c == '.') { ++c; if (qIsDigit(*c)) { - QString precision_str; - while (*c != '\0' && qIsDigit(*c)) - precision_str.append(QLatin1Char(*c++)); - - // can't be negative - started with a digit - // contains at least one digit - precision = precision_str.toInt(); - } - else if (*c == '*') { + precision = parse_field_width(c); + } else if (*c == '*') { // can't parse this in another function, not portably, at least precision = va_arg(ap, int); if (precision < 0) precision = -1; // treat all negative numbers as unspecified @@ -6175,8 +6186,7 @@ QString QString::vasprintf(const char *cformat, va_list ap) } case lm_ll: { qint64 *n = va_arg(ap, qint64*); - volatile uint tmp = result.length(); // egcs-2.91.66 gets internal - *n = tmp; // compiler error without volatile + *n = result.length(); break; } default: { @@ -6239,7 +6249,7 @@ qlonglong QString::toIntegral_helper(const QChar *data, int len, bool *ok, int b } #endif - return QLocaleData::c()->stringToLongLong(data, len, base, ok, QLocaleData::FailOnGroupSeparators); + return QLocaleData::c()->stringToLongLong(data, len, base, ok, QLocale::RejectGroupSeparator); } @@ -6279,7 +6289,8 @@ qulonglong QString::toIntegral_helper(const QChar *data, uint len, bool *ok, int } #endif - return QLocaleData::c()->stringToUnsLongLong(data, len, base, ok, QLocaleData::FailOnGroupSeparators); + return QLocaleData::c()->stringToUnsLongLong(data, len, base, ok, + QLocale::RejectGroupSeparator); } /*! @@ -6480,7 +6491,7 @@ ushort QString::toUShort(bool *ok, int base) const double QString::toDouble(bool *ok) const { - return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocaleData::FailOnGroupSeparators); + return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocale::RejectGroupSeparator); } /*! @@ -7728,6 +7739,8 @@ QString QString::arg(double a, int fieldWidth, char fmt, int prec, QChar fillCha if (!(locale.numberOptions() & QLocale::OmitGroupSeparator)) flags |= QLocaleData::ThousandsGroup; + if (!(locale.numberOptions() & QLocale::OmitLeadingZeroInExponent)) + flags |= QLocaleData::ZeroPadExponent; locale_arg = locale.d->m_data->doubleToString(a, prec, form, fieldWidth, flags); } @@ -10448,7 +10461,7 @@ ushort QStringRef::toUShort(bool *ok, int base) const double QStringRef::toDouble(bool *ok) const { - return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocaleData::FailOnGroupSeparators); + return QLocaleData::c()->stringToDouble(constData(), size(), ok, QLocale::RejectGroupSeparator); } /*! diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index d21708efb9..5894b869da 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -387,25 +387,25 @@ public: # define Q_REQUIRED_RESULT # define Q_REQUIRED_RESULT_pushed # endif - QString toLower() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toLower() const & Q_REQUIRED_RESULT { return toLower_helper(*this); } - QString toLower() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toLower() && Q_REQUIRED_RESULT { return toLower_helper(*this); } - QString toUpper() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toUpper() const & Q_REQUIRED_RESULT { return toUpper_helper(*this); } - QString toUpper() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toUpper() && Q_REQUIRED_RESULT { return toUpper_helper(*this); } - QString toCaseFolded() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toCaseFolded() const & Q_REQUIRED_RESULT { return toCaseFolded_helper(*this); } - QString toCaseFolded() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString toCaseFolded() && Q_REQUIRED_RESULT { return toCaseFolded_helper(*this); } - QString trimmed() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString trimmed() const & Q_REQUIRED_RESULT { return trimmed_helper(*this); } - QString trimmed() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString trimmed() && Q_REQUIRED_RESULT { return trimmed_helper(*this); } - QString simplified() const & Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString simplified() const & Q_REQUIRED_RESULT { return simplified_helper(*this); } - QString simplified() && Q_REQUIRED_RESULT + Q_ALWAYS_INLINE QString simplified() && Q_REQUIRED_RESULT { return simplified_helper(*this); } # ifdef Q_REQUIRED_RESULT_pushed # pragma pop_macro("Q_REQUIRED_RESULT") @@ -958,8 +958,9 @@ inline int QString::toWCharArray(wchar_t *array) const if (sizeof(wchar_t) == sizeof(QChar)) { memcpy(array, d->data(), sizeof(QChar) * size()); return size(); + } else { + return toUcs4_helper(d->data(), size(), reinterpret_cast<uint *>(array)); } - return toUcs4_helper(d->data(), size(), reinterpret_cast<uint *>(array)); } QT_WARNING_POP diff --git a/src/corelib/tools/qversionnumber.h b/src/corelib/tools/qversionnumber.h index ebf1844f38..6a2718ca28 100644 --- a/src/corelib/tools/qversionnumber.h +++ b/src/corelib/tools/qversionnumber.h @@ -273,7 +273,7 @@ public: Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber commonPrefix(const QVersionNumber &v1, const QVersionNumber &v2) Q_REQUIRED_RESULT; Q_CORE_EXPORT QString toString() const Q_REQUIRED_RESULT; - Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = 0) Q_REQUIRED_RESULT; + Q_CORE_EXPORT static Q_DECL_PURE_FUNCTION QVersionNumber fromString(const QString &string, int *suffixIndex = Q_NULLPTR) Q_REQUIRED_RESULT; private: #ifndef QT_NO_DATASTREAM diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index ed07f70e87..5cfeff5a4f 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -24,6 +24,7 @@ HEADERS += \ tools/qdatetime.h \ tools/qdatetime_p.h \ tools/qdatetimeparser_p.h \ + tools/qdoublescanprint_p.h \ tools/qeasingcurve.h \ tools/qfreelist_p.h \ tools/qhash.h \ @@ -136,10 +137,6 @@ false: SOURCES += $$NO_PCH_SOURCES # Hack for QtCreator tools/qbytearray_mac.mm \ tools/qdatetime_mac.mm } -else:blackberry { - SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_blackberry.cpp tools/qtimezoneprivate_tz.cpp - HEADERS += tools/qlocale_blackberry.h -} else:android { SOURCES += tools/qelapsedtimer_unix.cpp tools/qlocale_unix.cpp tools/qtimezoneprivate_android.cpp } @@ -198,6 +195,14 @@ INCLUDEPATH += ../3rdparty/md5 \ ../3rdparty/md4 \ ../3rdparty/sha3 +contains(QT_CONFIG, doubleconversion) { + include($$PWD/../../3rdparty/double-conversion/double-conversion.pri) +} else:contains(QT_CONFIG, system-doubleconversion) { + LIBS_PRIVATE += -ldouble-conversion +} else { + DEFINES += QT_NO_DOUBLECONVERSION +} + # Note: libm should be present by default becaue this is C++ !macx-icc:!vxworks:!haiku:unix:LIBS_PRIVATE += -lm |