From 67129ef9cd946837cec6118c9e6e5a03b7eae342 Mon Sep 17 00:00:00 2001 From: Ahmad Samir Date: Sat, 18 Mar 2023 14:41:52 +0200 Subject: QLocaleData: change validateChars() to return validation State Instead of returning just bool, return a result struct {State, CharBuff}, a State is useful as it can have an Intermediate state where the input isn't Acceptable yet, but not Invalid as such. The example from the linked bug is in tst_QIntValidator::validateFrench(), a string "1 ", which can be interpretted as a number with a group separator, but the input shouldn't end with a group separator (changing the unittest will be done as part of a separate commit). CharBuff (QVarLengthArray) replaces the QByteArray input parameter; a QVarLengthArray means no heap allocation in typical use-cases with input text < 256 characters to validate. This required minimum changes (QVLA doesn't have startsWith, replaced by comparing with buff[0]; and for converting to double, wrapped it in a QBAV). Task-number: QTBUG-111371 Change-Id: I4e0eb612d470ef03faf52031ddfe9c4bdb31e1e1 Reviewed-by: Edward Welbourne --- src/gui/util/qvalidator.cpp | 48 +++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'src/gui/util/qvalidator.cpp') 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 static inline -std::optional initialResultCheck(T min, T max, const QByteArray &buff) +std::optional 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 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 opt = initialResultCheck(b, t, buff); + std::optional 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 opt = initialResultCheck(q->b, q->t, buff); + std::optional 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(). -- cgit v1.2.3