diff options
-rw-r--r-- | src/corelib/text/qlocale.cpp | 28 | ||||
-rw-r--r-- | src/corelib/text/qlocale_p.h | 18 | ||||
-rw-r--r-- | src/gui/util/qvalidator.cpp | 48 |
3 files changed, 57 insertions, 37 deletions
diff --git a/src/corelib/text/qlocale.cpp b/src/corelib/text/qlocale.cpp index b5edfdefe8..87a6585421 100644 --- a/src/corelib/text/qlocale.cpp +++ b/src/corelib/text/qlocale.cpp @@ -4205,11 +4205,12 @@ bool QLocaleData::numberToCLocale(QStringView s, QLocale::NumberOptions number_o return true; } -bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray *buff, - int decDigits, QLocale::NumberOptions number_options) const +ParsingResult +QLocaleData::validateChars(QStringView str, NumberMode numMode, int decDigits, + QLocale::NumberOptions number_options) const { - buff->clear(); - buff->reserve(str.size()); + ParsingResult result; + result.buff.reserve(str.size()); enum { Whole, Fractional, Exponent } state = Whole; const bool scientific = numMode == DoubleScientificMode; @@ -4227,14 +4228,14 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray case Fractional: // If a double has too many digits in its fractional part it is Invalid. if (decDigits-- == 0) - return false; + return {}; break; case Exponent: if (!isAsciiDigit(last)) { // This is the first digit in the exponent (there may have beena '+' // or '-' in before). If it's a zero, the exponent is zero-padded. if (c == '0' && (number_options & QLocale::RejectLeadingZeroInExponent)) - return false; + return {}; } break; } @@ -4245,7 +4246,7 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray // If an integer has a decimal point, it is Invalid. // A double can only have one, at the end of its whole-number part. if (numMode == IntegerMode || state != Whole) - return false; + return {}; // Even when decDigits is 0, we do allow the decimal point to be // present - just as long as no digits follow it. @@ -4256,14 +4257,14 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray case '-': // A sign can only appear at the start or after the e of scientific: if (last != '\0' && !(scientific && last == 'e')) - return false; + return {}; break; case ',': // Grouping is only allowed after a digit in the whole-number portion: if ((number_options & QLocale::RejectGroupSeparator) || state != Whole || !isAsciiDigit(last)) { - return false; + return {}; } // We could check grouping sizes are correct, but fixup()s are // probably better off correcting any misplacement instead. @@ -4272,7 +4273,7 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray case 'e': // Only one e is allowed and only in scientific: if (!scientific || state == Exponent) - return false; + return {}; state = Exponent; break; @@ -4282,16 +4283,17 @@ bool QLocaleData::validateChars(QStringView str, NumberMode numMode, QByteArray // validators don't accept those values. // For anything else, tokens.nextToken() must have returned 0. Q_ASSERT(!c || c == 'a' || c == 'f' || c == 'i' || c == 'n'); - return false; + return {}; } } last = c; if (c != ',') // Skip grouping - buff->append(c); + result.buff.append(c); } - return true; + result.state = ParsingResult::Acceptable; + return result; } double QLocaleData::stringToDouble(QStringView str, bool *ok, diff --git a/src/corelib/text/qlocale_p.h b/src/corelib/text/qlocale_p.h index 649f75fbeb..2c36f9bdaf 100644 --- a/src/corelib/text/qlocale_p.h +++ b/src/corelib/text/qlocale_p.h @@ -214,6 +214,18 @@ Q_DECLARE_TYPEINFO(QLocaleId, Q_PRIMITIVE_TYPE); using CharBuff = QVarLengthArray<char, 256>; +struct ParsingResult +{ + enum State { // A duplicate of QValidator::State + Invalid, + Intermediate, + Acceptable + }; + + State state = Invalid; + CharBuff buff; +}; + struct QLocaleData { public: @@ -361,9 +373,9 @@ public: [[nodiscard]] inline NumericData numericData(NumberMode mode) const; // this function is used in QIntValidator (QtGui) - [[nodiscard]] Q_CORE_EXPORT bool validateChars( - QStringView str, NumberMode numMode, QByteArray *buff, int decDigits = -1, - QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const; + [[nodiscard]] Q_CORE_EXPORT ParsingResult + validateChars(QStringView str, NumberMode numMode, int decDigits = -1, + QLocale::NumberOptions number_options = QLocale::DefaultNumberOptions) const; // Access to assorted data members: [[nodiscard]] QLocaleId id() const diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index ce6c7a98a3..4f788c5190 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -363,8 +363,12 @@ static qlonglong pow10(int exp) } template <typename T> static inline -std::optional<QValidator::State> initialResultCheck(T min, T max, const QByteArray &buff) +std::optional<QValidator::State> initialResultCheck(T min, T max, const ParsingResult &result) { + if (result.state == ParsingResult::Invalid) + return QValidator::Invalid; + + const CharBuff &buff = result.buff; if (buff.isEmpty()) return QValidator::Intermediate; @@ -376,21 +380,23 @@ std::optional<QValidator::State> initialResultCheck(T min, T max, const QByteArr if (buff.size() == 1 && (ch == '-' || ch == '+')) return QValidator::Intermediate; + if (result.state == ParsingResult::Intermediate) + return QValidator::Intermediate; + return std::nullopt; } QValidator::State QIntValidator::validate(QString & input, int&) const { - QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, -1, - locale().numberOptions())) { - return Invalid; - } + ParsingResult result = + locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, -1, + locale().numberOptions()); - std::optional<QValidator::State> opt = initialResultCheck(b, t, buff); + std::optional<State> opt = initialResultCheck(b, t, result); if (opt) return *opt; + const CharBuff &buff = result.buff; bool ok; qlonglong entered = QLocaleData::bytearrayToLongLong(buff, 10, &ok); if (!ok) @@ -421,11 +427,12 @@ QValidator::State QIntValidator::validate(QString & input, int&) const /*! \reimp */ void QIntValidator::fixup(QString &input) const { - QByteArray buff; - if (!locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, &buff, -1, - locale().numberOptions())) { + auto [parseState, buff] = + locale().d->m_data->validateChars(input, QLocaleData::IntegerMode, -1, + locale().numberOptions()); + if (parseState == ParsingResult::Invalid) return; - } + bool ok; qlonglong entered = QLocaleData::bytearrayToLongLong(buff, 10, &ok); if (ok) @@ -653,12 +660,10 @@ QValidator::State QDoubleValidator::validate(QString & input, int &) const QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QLocaleData::NumberMode numMode, const QLocale &locale) const { Q_Q(const QDoubleValidator); - QByteArray buff; - if (!locale.d->m_data->validateChars(input, numMode, &buff, q->dec, locale.numberOptions())) { - return QValidator::Invalid; - } + ParsingResult result = + locale.d->m_data->validateChars(input, numMode, q->dec, locale.numberOptions()); - std::optional<QValidator::State> opt = initialResultCheck(q->b, q->t, buff); + std::optional<QValidator::State> opt = initialResultCheck(q->b, q->t, result); if (opt) return *opt; @@ -739,15 +744,16 @@ void QDoubleValidatorPrivate::fixupWithLocale(QString &input, QLocaleData::Numbe const QLocale &locale) const { Q_Q(const QDoubleValidator); - QByteArray buff; // Passing -1 as the number of decimals, because fixup() exists to improve // an Intermediate value, if it can. - if (!locale.d->m_data->validateChars(input, numMode, &buff, -1, locale.numberOptions())) + auto [parseState, buff] = + locale.d->m_data->validateChars(input, numMode, -1, locale.numberOptions()); + if (parseState == ParsingResult::Invalid) return; - // buff now contains data in C locale. + // buff contains data in C locale. bool ok = false; - const double entered = buff.toDouble(&ok); + const double entered = QByteArrayView(buff).toDouble(&ok); if (ok) { // Here we need to adjust the output format accordingly char mode; @@ -771,7 +777,7 @@ void QDoubleValidatorPrivate::fixupWithLocale(QString &input, QLocaleData::Numbe if (eIndex < 0) eIndex = buff.size(); precision = eIndex - (buff.contains('.') ? 1 : 0) - - (buff.startsWith('-') || buff.startsWith('+') ? 1 : 0); + - (buff[0] == '-' || buff[0] == '+' ? 1 : 0); } // Use q->dec to limit the number of decimals, because we want the // fixup() result to pass validate(). |